- 日志
 - 31
 
- 好友
 - 17
 
- 阅读权限
 - 150
 
- 收听
 - 1
 
- 在线时间
 - 1969 小时
 
- 最后登录
 - 2025-11-4
 
 
 
 
 
  
超级版主 
教育辅助界扛把子 
 
- 精华
 - 1
 
- 热心
 - 10 
 
- 听众
 - 1
 
- 威望
 - 2 
 
- 贡献
 - 17894 
 
- 违规
 - 0 
 
- 书币
 - 56007 
 
- 注册时间
 - 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~ 写的比较乱。。 凑合看吧。有问题可以在讨论哈 。 
 |   
 
 
 
 |