- 日志
- 23
- 好友
- 17
- 阅读权限
- 150
- 收听
- 1
- 在线时间
- 1558 小时
- 最后登录
- 2024-11-21
超级版主
教育辅助界扛把子
- 精华
- 1
- 热心
- 7
- 听众
- 1
- 威望
- 48
- 贡献
- 14307
- 违规
- 0
- 书币
- 49981
- 注册时间
- 2020-4-8
|
emm 上次帮水友排查了一个redis 的问题。有水友留言想了解一下redis。我对redis的了解也不是很多一点点浅见分享给水友。希望水友能有收获。
Redis 是什么?
官方解释(https://redis.io/docs/about/): Redis是一个开源(BSD许可)的内存数据结构存储,用作数据库、缓存、消息代{过}{滤}理和流引擎。Redis提供了数据结构,如字符串、哈希、列表、集合、排序集合、范围查询、位图、超日志、地理空间索引和流。Redis具有内置复制、Lua脚本、LRU驱逐、事务和不同级别的磁盘持久性,并通过Redis Sentinel和Redis Cluster提供高可用性和自动分区。
通俗解释(个人认为),Redis 是一款基于C语言开发的开源的内存数据库。它提供了丰富的数据(结构)类型 包括字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)和有序集合(sorted sets)、位图(bitmap)、地理空间索引(GEO)、流(stream) 等, 可以基于这些属于上述的数据(结构)类型,高效的满足我们的业务需求。
Redis 官网: https://redis.io/ (注意这里是.io域名)
版本差异
Redis 社区比较活跃,版本更新迭代非常快。截止到目前发文之前的版本是 Stable (7.2) 这里我们只拿出 5、6、7 三个版本简略说下差异,这里只说最核心的部分。详细对比差异请参考官网或网络。
redis 5 新的stream数据类型
redis 6 增加了多线程Thread I/O(工作线程还是单线程) 和 ACL细粒度的权限控制
redis 7 Redis Functions
Redis怎么使用? 可以用来做什么?
Redis 通常需要搭配一种开发语言来配合业务使用。如常见的开发语言都会有SDK 客户端。https://redis.io/docs/connect/clients/(官方clients) 也可以使用常见的桌面端开源图形客户端。
Redis 根据不同的业务需求,所能做的东西也不同 App后台服务端端业务、场景不同需求不同。下面我会举一些常见的业务需求场景 和 经典实现。
为什么要使用redis ?
Redis 基于内存操作数据,且是单线程原子操作(单个命令),因为单线程读写,避免了多线程并发冲突。早起redis 官方号称 单机redis qps为10w/s(和机器配置相关)
Redis桌面客户端
这种开源的桌面客户端连接工具非常的多,大家可以根据自己的喜好选择。我这里只介绍两款 两款都支持 支持Mac、Windows和Linux。
Tiny RDM
官网: https://redis.tinycraft.cc/zh/ (https://github.com/wailsapp/wails "https://redis.tinycraft.cc/zh/")
github: https://github.com/tiny-craft/tiny-rdm/releases (https://github.com/wailsapp/wails "https://github.com/tiny-craft/tiny-rdm/releases")
AnotherRedisDesktopManager
github:https://github.com/qishibo/AnotherRedisDesktopManager/releases
redis 安装
这里提供两种安装方式。
基于 Rethat Linux 发行版本的操作系统安装(yum)
yum install -y gcc tcl gcc-c++ make
yum install -y epel-release
yum install redis -y
上述命令执行完就已经安装好了。
打开配置文件:vim /etc/redis.conf
修改默认密码:查找 requirepass,默认密码为 foobared。需要修改
找到 bind 127.0.0.1 将其注释,否则redis只允许本机连接
找到 protected-mode yes 将其改为:protected-mode no
找到 port 6379 建议修改默认端口号
添加iptables 规则:
iptables -I INPUT -p tcp --dport 6379 -j ACCEPT
Centos7 防火墙规则 :
firewall-cmd --zone=public --add-port=6379/tcp --permanent
firewall-cmd --reload
启动 : systemctl start redis
基于docker的方式安装,全平台通用前提是要装个docker。
1、docker pull redis:6.2.7
2、创建需要挂载的配置目录和文件
mkdir -p /data/redis6/conf
touch /data/redis6/redis.conf(这一步也可以先启动容器 从容器中copy出来一个。或者去dockerHub wget下来一个)
3、启动 docker run -p 6379:6379 --privileged=true --name redis6 -v /data/redis6/data:/data -v /data/redis6/conf/redis.conf:/etc/redis/redis.conf -d redis:6.2.7 redis-server /etc/redis/redis.conf
Redis 命令:
https://redis.io/commands/(官网)
每个命令都有示例 。可以根据数据类型筛选,过滤 首字母索引等。
以前有个中文版的现在找不到了
redis 常见的数据类型 和 经典实现
String:
描述: 最基本的数据类型,二进制安全。不仅限于 存储 String。最大存储512M.
ops: set [key,val] 会覆盖数据 get[key] incre[key]自增 setnx [key,val] 如果存在则返回,不存在则返回0。
经典实现: 自增数实现分布式全局ID 各种访问数量,如 用户访问量,点赞。字符串用来存储 token , 短信验证码之类。
Hash(字典):
描述: 存储类型类似于对象。hmset创建对象。 通过hget hset 获取对象。
ops: hmset key [filed,val],[filed,val],[filed,val]. hget obj.filed. hset obj.filed
经典实现: json序列化的对象存储,购物车实现。
List(列表):
desc: 按照插入的String元素排序,后进先出 (stack)的数据结构。可以存储40亿成员。O(1) 复杂度
ops: lpush [key,val]。 lrange [0 n] 取数据
经典实现: 最新消息排行榜。
Set(集合):
desc: 集合,类似于java List 无序,通过hash表实现。不允许重复。
ops: sadd [key,val] 添加集合元素, smembers [key] 获取集合。
SRANDMEMBER KEY :随机弹出集合中的一个元素
SPOP KEY :随机删除弹出集合中的一个元素
SCARD KEY : 集合中的元素个数
经典实现:
把关注人存在set中.可以 求交集、并集、差集。操作 计算共同关注。
SPOP 、SRANDMEMBER 随机弹出元素可用于立即参与(微信)抽奖。(把用户id放入)
SCARD 可用于显示多少人进行参加抽奖活动
SCARD 点赞数量
StoreSet(Zset有序集合):
desc: 会记录一个double类型的 score ,按照从小到达排序。score可以重复,Value不允许重复 分数小靠前。
升序排列,分值越大越靠后,分值相同,则按照value的字典顺序排序
ops:
zadd key [NX|XX] [CH] [INCR] score member [score member ...]
nx: member 必须不存在,才可以设置成功,用于添加
xx: member 必须存在,才可以设置成功,用于更新
ch: 返回此次操作后,有序集合元素和分数发生变化的个数
incr: 对 score 做增加,相当于后面介绍的 zincrby
zadd key score value [添加key]
ZCARD key [获取一个排序的集合中的成员数量]
zrange key 0,n(-1) [遍历集合 从小到大]
zrevrange key 0,n(-1)[遍历集合 从大到小]
zrangebyscore key 0,n(-1) limit x x[根据分数值查询,可选分页参数]
zremrangebyscore key x x 删除有序set。
经典实现:热搜排行榜(根据浏览点赞)、存储班级学生成绩排序。程序根据重要的任务排序,score 高的任务优先执行。
pub/sub(发布订阅)
底层实现:
Redis有两种发布/订阅模式:
基于频道(Channel)的发布/订阅
基于模式(pattern)的发布/订阅
命令:
#订阅 处于监听消息的状态
SUBSCRIBE channels
subscreibe user-topic
#发布消息
PUBLISH channels message
publish user-topic hello
# 查看当前订阅列表
pubsub channels
BitMap
ops : setbit key 1 1 ,getbit key 1, bitcount key
经典实现: 统计打卡 、在线人数 、10亿手机号中判断重复
redis 具体使用场景(Redis 通常需要配合开发语言来完成业务。)
String 类型
存储 AccessToken 和 RefreshToken。
现在主流的web 或者app 与后端交互 登陆鉴权 的方式基本是 accessToken的形式。
用户登陆 服务端会 生成两个随机字符串 "access_token:a6f1efca84705b7041193f96f265ac768d35" 作为Key,
把用户的id 作为value 。设置过期时间为30min 后过期。
生成"refresh_token:e4e44f08754dadbfeec2927ee706cb01fa6b" 作为key ,把用户id 设置成value
设置过期时间为 1个月。
这样每次客户端发起请求携带access_token,后端从redis拿到并且校验,如果过期。则前端重新使用refresh_token换取 access_token。
set access_token:a6f1efca84705b7041193f96f265ac768d35 1 ex 1800
set refresh_token:e4e44f08754dadbfeec2927ee706cb01fa6b 1 ex 2626560
设置商品详情页,从程序中写入redis 中。
分布式自增ID (在分布式环境下保证id不重复)
set increment_id 1
INCR increment_id
Set 数据类型
公司年会简单的抽奖 把 公司所有人的姓名添加到 set 集合中。总共 有 3 等奖。 从
set 集合中随机弹出 3 个 做为 1 2 3 等奖。
sadd prize_user tom
sadd prize_user eric
sadd prize_user jack
sadd prize_user bob
SPOP prize_user
SPOP prize_user
SPOP prize_user
bitMap
有序大数据 去重 统计
假如 需要对一个亿的手机号判断是否有重复。在通常情况下我们会通过hash 来判断。这样不仅占用内存而且效率也不是特别高。我们可以把号码放到redis bitmap中。号码通常是11位第一位都是1 可以去调。这样还剩下 8位数字。bitmap 是一个数组具体存储的是bit位 0 和 1 。那么我们的号码就可以作为数组下标[index]最大为 99999999 的下标。下面我们就以131 开头的号码演示
setbit mobile_coll 3162587639 1
setbit mobile_coll 3162587611 1
setbit mobile_coll 3162587612 1
setbit mobile_coll 3162587613 1
setbit mobile_coll 3162587614 1
setbit mobile_coll 3162587615 1
setbit mobile_coll 3162587615 1
当我们第一次 放进去 13162587615 号码的时候返回0。我们再次放进去的时候就返回 1 说明该号码已经存在。时间复杂度为O(1) 且不占用内存。
bitMap 在线用户统计 把一些用户添加到 user_onlins 中 1表示在线 0表示下线 (online 单词好像拼错了undefined)setbit user_onlins 132637 1
setbit user_onlins 132638 1
setbit user_onlins 132639 0
setbit user_onlins 132640 1
setbit user_onlins 132641 1
setbit user_onlins 132642 1
BITCOUNT user_onlins 统计 user_onlins 下的在线人数
分布式锁
如果我们的系统是分布式服务架构,调用操作系统内核加锁。已经不能保证并发安全。
举例子 52论坛中的签到功能,在0点的时候一个用户模拟发送了10个签到请求,如果该系统是分布式的情况下 10个请求 会被nginx 分发3台服务器。单个服务器中跑的代码加锁已经不能保证数据一致性。这个时候可以借助一个中间件来完成分布式锁的功能。保证在分布式集群环境下并发安全。
分布式锁的实现方式很多。借助的中间件也不限于Redis 主要是一种思想。在java生产环境中一般会使用 redisson 提供的分布式锁。或者zookeeper 来实现。
redis 内存8种淘汰策略(内存超过 maxmemory):
maxmemory-policy 可以指定配置使用下面哪一种淘汰策略。
默认是no-eviction。内存满了写入OOM。
1. volatile-lru:从已设置过期时间的数据集中挑选最近最少使⽤的数据淘汰。
2. volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
3. allkeys-lru:当内存不⾜以容纳新写⼊数据时,在键空间中,移除最近最少使⽤的 key(常用)
4. allkeys-random:从数据集(server.db.dict)中任意选择数据淘汰。
5. volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
6. no-eviction:禁⽌驱逐数据,也就是说当内存不⾜以容纳新写⼊数据时,新写⼊操作会报错OOM。
7. volatile-lfu:从已设置过期时间的数据集中挑选最不经常使⽤的数据淘汰。
8. allkeys-lfu:当内存不⾜以容纳新写⼊数据时,在键空间中,移除最不经常使⽤的 key。
redis 删除策略(key过期删):
1、定时删除(时间换空间)
节约内存,无占用,不分时段占用CPU资源,频度高
2、惰性删除(空间换时间)
内存占用严重 延时执行,CPU利用率高
3、定期删除(折中)两种方式混合 Redis默认采用的就是该模式
内存定期随机清理 每秒花费固定的CPU资源维护内存 随机抽查,重点抽查
ok~ 写的比较乱。。 凑合看吧。有问题可以在讨论哈 。
|
|