Redis-使用备忘

Redis-使用备忘

基本介绍

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API

安装和官网

https://redis.io/
Docker安装Redis:https://blog.csdn.net/weixin_45821811/article/details/116211724

命令查询

http://www.redis.cn/
http://redisdoc.com/

常用指令

所有操作具有原子性,就是成功一起成功,失败一起失败,特别针对多值操作的命令

  • keys * 查询所有键(keys *1,查询以1为结尾的所有键值)
  • del 删除key为键值的数据

字符串类型与操作

  • set 添加键值
  • get 查询对应键值
  • append 将value追加到原值末尾
  • strlen 获得值长度
  • setnx 只有在key不存在时,设置key的值
  • incr 将key中存储数字值+1,只能对数字操作(非数字返回错误),如果为空,新增值为1
  • decr 与incr相反,减1,如果为空,新增值为-1
  • incrby <步长> 将key原来数字值增加 自定义步长大小
  • decrby <步长> 与incrby相反,减 自定义步长
  • mset .... 同时设置一个或者多个值
  • mget .... 同时获取一个或多个值
  • msetnv .... 同时设置一个或者多个值,当且仅所有key都不存在才成功,有一个失败全部失败
  • getrange <起始位置> <结束位置> 获得取值范围内的字符串,类似java substring
  • setrange <起始位置> 覆写所存储字符串,从 起始位置 开始(索引从0开始)
  • setex <过期时间> 设置键值的同时,设置过期时间,单位秒
  • getset 以新换旧,设置新值同时获得旧值

list类型与操作

底层结构:双向链表

  • lpush/rpush ..... 从左边/右边插入一个或多个值(key不存在,或建立个空列表,并执行后面操作;当key存在,且不是列表类型,返回一个错误)
  • lpop/rpop 从左边/右边弹出一个值
  • lrange <起始位置> <结束位置> 返回列表指定区间元素,下标都以0为开始,-1可以表示最后一个元素(负数表示倒数顺序)
  • rpoplpush 把key1的尾部元素放到key2的头部
  • lindex 把下标为index的值取回,与pop不一样,它不破坏原来结构
  • llen 得到列表元素总个数
  • linsert before/after 在value的前面/后面插入newvalue
  • lrem 从左边删除n个value(从左到右)
  • lset 将列表key下标为index的值替换为value

set类型与操作

底层结构:dict字典,哈希表原理实现;无序且排重

  • sadd .... 将一个或多个member加入到集合,已存在的member元素会忽略
  • smembers 查看集合全部元素
  • sismember 判断member是否存在于集合key中,有1,没有0
  • scard 得到集合总元素个数
  • srem .... 将一个或多个member元素删除
  • spop 随机从该集合吐出一个值
  • srandmember 随机从该集合取出n个member,不会从集合删除
  • smove 把member从key1移动到key2
  • sinter 返回两个集合的交集元素
  • sunion 返回两个集合的并集元素
  • sdiff 返回两个集合的差集元素(key1中,不包含key2中的,所以这个的key顺序会影响结果)

hash类型与操作

键值对集合,适合用于存储对象,类似java Map<String,Object>

  • hset .... 将哈希表key中的字段field1设置为value1,如果表不存在,则创建后执行赋值(返回1或几个值就是几),如果表存在且字段也存在,那么替换key中的field1为新的value1(返回0)
  • hmset .... 同hset,6版本以上hset已经支持多个值
  • hget 从key哈希表取出field的value(key或者field不存在,返回nil)
  • hmget .... 批量取回hash表的field对应value值
  • hexists 判断key中field是否存在(存在1,不存在0)
  • hkeys 列出key中所有的field
  • hvals 列出key中所有的value
  • hincrby 为key哈希表field字段的值加上增量(正数和负数都可以,如果field不存在,初始化为0进行增量相加,如果field为字符串,则报错)
  • hsetnx 将哈希表key中的域field设置为value,当且仅当域field不存在

zset类型与操作

有序集合

  • zadd ... 将一个或者多个member及其score值加入到有序集合中,如果member已经是有序集合成员,那么更新这个member的score值,并通过重新插入这个member元素,来保证member在正确的位置
  • zrange [withscores] 返回有序集 key 中,下标在start-stop之间的元素,带上withscores,可以让分数一起和值返回到结果集
  • zrevrange [withscores] 返回逆序集,与zrange相反
  • zscore 返回对应集合中member的排序码
  • zrangebyscore [withscores] [limit offset count] 返回有序集key中,所有score值介于min和max之间的成员(包括min与max),按score值递增次序排序(从小到大)
    可选的 LIMIT 参数指定返回结果的数量及区间(就像SQL中的 SELECT LIMIT offset, count )
  • zrevrangebyscore [withscores] [limit offset count] 与zrangebyscore 类似,返回值按score递减次序排序(从大到小)
  • zincrby 为元素的score加上增量
  • zrem 删除集合下指定value元素
  • zcount 统计该集合下,分数区间内的元素个数
  • zrank 返回该值在集合中的排名,从0开始

配置文件

https://www.cnblogs.com/nhdlb/p/14048083.html

单位

1k => 1000 bytes
1kb => 1024 bytes
1m => 1000000 bytes
1mb => 1024*1024 bytes
1g => 1000000000 bytes
1gb => 1024*1024*1024 bytes
支持字节,不支持位,不区分大小写

include

多实例的情况可以把公用配置文件提取出来,然后使用include(复用配置)

network

  • bind
    • 默认情况下bind=127.0.0.1只接受本机访问请求
    • 如果服务器是需要远程访问,需要将其注释掉
  • protected-mode
    • 默认是开启状态
    • 如果服务器需要远程访问,需要将yes改为no
  • port
    • 默认6379,可以修改
  • timeout
    • 一个空闲客户端维持多少秒会关闭,默认0,表示永不超时
  • tcp-keepalive
    • 对访问客户端的一种心跳检测,每隔n秒检测一次,单位为秒
    • 如果设置为0,则不会进行keepalive检测,建议设置为60
    • 这个检测的目的是为了保证链接是有效的,快速清理无效链接,回收资源

general-通用

  • daemonize
    • 是否为后台进程,设置为yes表示守护进程,后台启动
  • pidfile
    • 存放pid文件的位置,每个实例会产生不同的pid文件,记录redis的进程号
  • loglevel
    • 日志级别,默认生产模式notice,开发测试使用debug(日志内容多,不建议生产使用)
    • debug:会打印很多信息,适用于开发和测试阶段
    • verbose:包含很多信息(冗长,不太有用信息),但比debug要清爽
    • notice:适用于生产(适当的信息)
    • warning:警告信息(只有非常重要的信息)
  • logfile
    • 默认“”,为控制台打印,没有日志文件生成,可以配置相对于的日志文件存放路径,注意需要提前创建一个文件即可
  • databases
    • 默认16,设定库的数量,登入时默认进入0号库,可以通过select命令切换库

security-安全

  • requirepass
    • 设定使用使用密码,默认密码“foobared”
    • 设定密码后,操作数据时需要输入授权密码
    • redis.conf中设置密码表示永久生效(每次启动服务)
      运行中设置密码表示单次服务中生效-重启服务失效
      • config set requirepass 设置验证密码(本次链接中还是有效,此刻后其他连入都要验证)
      • config get requirepass 查看设置明文
    • auth 进行验证,默认用户名default(可以不用输入)
    • acl list 查看所有用户列表
    • acl whoami 查看自己当前验证的用户名

limits-限制

  • maxclients
    • 设置同时可以和多少客户端链接,默认1w个客户端
    • 如果达到限制,会向这些链接请求发出“max number of clients reached”
  • maxmemory
    • 设置实例内存占用大小
    • 默认情况,对32位实例限制在3GB,64位无此限制,最小不能小于1MB
    • 设置建议:
      • 只能根据具体生产环境来调试,不要预设值,从小到大测试,不影响正常程序运行即可;
      • 如果使用redis做纯缓存,64-128MB对一般小型网站够用;
      • 如果做数据库,设置到物理内存1/2到3/4都可;
      • 这里还要注意,如果使用了快照功能,最好用到50%以下的物理内存,因为快照复制需要双倍空间,没用用到快照可以用到80%物理内存,只要保证java、nginx等其它程序正常运行即可
  • maxmemory-policy
    • 设置内存到达最大的处理策略(尽量避免触发此策略)
    • policy
      • volatile-lru 使用LRU算法移除key,只对设置了过期时间的键(最近最少使用)
      • allkeys-lru 使用LRU算法移除key,对所有键
      • volatile-random 随机移除ket,只对设置了过期时间的键
      • allkeys-random 随机移除ket,对所有键
      • volatile-ttl 移除那些TTL值最小的key,既那些最近要过期的key
      • noeviction 不进行移除,针对写操作,只是返回错误信息
  • maxmemory-samples
    • 设置样本数量,LRU算法和最小TTl算法都并非是精确算法,都是估算值,所以你可以设置样本大小,redis默认会检查这么多个key并选择其中lru的那个
    • 一般设置3到7的数字,数值越小样本越不精确,但性能消耗最小

发布订阅(pub/sub)

一种消息模式,发送者pub发送消息,订阅者sub接收消息
redis客户端可以订阅任意数量的频道

模式分类

  • 一个发布者,多个订阅者:主要应用-通知、公告,可以作为消息队列或者消息管道
  • 多个发布者,一个订阅者:主要应用-排行榜、投票、计数
  • 多个发布者,多个订阅者:主要应用-群聊、聊天

常用指令

  • publish channel msg 将信息msg发送到指定频道channel
  • subscribe channel [channel...] 订阅频道,可以同时订阅多个频道
  • unsubscribe [channel...] 取消订阅指定的频道,如果不指定频道,则会取消订阅所有频道
  • psubscribe pattern [pattern...] 订阅一个或多个符合给定模式的频道,每个模式以作为匹配符,比如it匹配所有以it开头的频道(it.news、it.blog、it.tweets 等等)
  • punsubscribe [pattern...] 取消订阅规则(同上),如果没有指定则取消所有规则

jedis(java操作redis)

项目中引入

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
<!--如果需要远程链接要注意
1.如果设置了密码,则需要身份验证
2.防火墙需要放开端口
3.redis配置信息中要注销bind配置-->

主从服务

命令

1.info replication 查询当前主从服务状态
2.slaveof ip port 将本服务设置为目标ip:port服务的从服务

原理

1.slave启动成功链接到master后会发送一个sync命令
2.master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步
3.slave服务在接收到数据文件后,将其存盘并加载到内存中,即 完全复制
4.master数据变化,会将新的收集到的修改命令依次传给slave,完成同步,即 增量复制
5.但是只要是重新链接master,一次完全复制(全量复制)将被自动执行

细节

1.从服务shutdown后,重新启动需要重新指向主服务,否则默认启动后角色为master
2.主服务shutdown后,从服务并不会升级为主服务,只是在查看角色时,会看到主服务为down状态,等待主服务启动后改为up状态

一主二仆

1.一个主服务带两个从服务模式

薪火相传

1.从服务可以设定master为另一个从服务,这种模式优点是减轻master写压力,去中心化减低风险
2.风险是一旦某个从服务宕机,后面的从服务都无法同步
3.主服务宕机,从服务还是从服务,无法写数据

反客为主

1.使用命令slave no one 将从服务转为从服务,一般用在薪火相传模式下,后续从服务无需改变
2.从服务变为主服务后,最大的变化是可以进行修改数据操作

哨兵模式(sentinel)

1.访客为主的自动版,能够后台监控主机是否故障,如果故障根据投票数自动将从服务转为主服务
2.需要在一主二仆模式下
3.创建sentinel.conf,名字不能乱写,按指定的来
4.配置内容:sentinel monitor redis_master 127.0.0.1 6379 1

  • sentinel 关键字
  • monitor redis_master 为监控对象命名的服务器名称
  • 127.0.0.1 6379 监听哪一个主服务
  • 1 表示至少1个哨兵同意迁移就可以切换
    5.启动哨兵:redis-sentinel sentinel.conf
    6.哨兵默认端口:26379
    7.当原来主服务宕机,哨兵从原来从机选举中产生新的主机
    8.如果原来主服务启动,哨兵会操作它成为从机

注意事项与细节

1.在哨兵模式下,主机down后执行的流程分析

  • 新主登基
    • 从下线的主服务所管理的从服务挑选一个从服务,将其转为主服务
    • 选择条件:
      1. 选择优先级靠前(可以再redis.conf中配置 replica-priority 100,值越小优先级越高)
      2. 选择偏移量最大的(指获得原主机数据的量,数据量最全的优先级高)
      3. 选择runid最小的(redis实例启动后都会生成一个40位的runid,值越小优先级越高)
  • 群仆俯首
    • 挑选出新的主服务之后,sentinel同原主服务的从服务发送slaveof新主服务 的命令,复制新master
  • 旧主俯首
    • 当已下线的服务上线,sentinel会向其发送slaveof新主服务 的命令,让其成为新主的从服务

集群

传统方式:使用代理主机方式,成本高,维护难
去中心化方式:任何一台服务器都可以作为请求入口,各个服务联通

介绍

Redis集群实现了对自己的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数数的1/N
Redis集群通过分区(partition)来提供一定程度的可用性(availability):即使有部分节点失效或者无法通讯,集群也可以继续处理命令请求

部署

1.保证redis目录下,rdb和aof文件删除,保证数据环境干净
2.新建配置文件,内容如下,同一台机器多个服务测试的话,需要复制配置文件,同时修改端口6379为不同端口号(vi 替换指令 :%s/6379/6380)

  include /xxx/redis.conf //载入统一配置
  pidfile "/var/run/redis_6379.pid" //实例pid路径
  port 6379 //redis运行端口
  dbfilename "dump6379.rdb" // 数据保存路径
  cluster-enable yes //打开集群模式
  cluster-config-file nodes-6379.conf //设定节点配置文件名
  cluster-node-timeout 15000 //设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换

3.启动全部的redis服务,检查服务启动成功(ps -ef|grep redis,服务最后有cluster标记),同时检查对应目录设定节点配置文件正常生成
4.使用节点合成一个集群指令:redis-cli --cluster create --cluster-replicas 1 192.168.x.x:6379 192.168.x.x:6379 192.168.x.x:6379 192.168.x.x:6379 192.168.x.x:6379 192.168.x.x:6379

  • 可以进入redis安装目录,使用src源文件目录中运行此命令(需要一个ruby环境,redis6在源文件自带)
  • 组合之前,确保所有实例启动后,nodes-xxx.conf文件都正常生成
  • 此处不要用127.0.0.1,请用真实IP,生产环境中,所有IP都是独立的
  • replicas 1 采用最简单的方式配置集群,一台主机,一台从机,正好三组, -replicas 0 表示创建集群的方式,以0个从机的方式创建集群(此处即为创建仅有三个主机的集群)
  • -a参数填写redis服务器的密码(没有设置密码可以不写-a)
  • 搭建集群如果没有成功,把sentinel进程kill掉,再试一下
    5.集群方式登入:redis-cli -c -p 6379,登入后可以使用功能cluster nodes查看集群信息(从机S信息后会带上M主机的识别码),这里注意-c一定要带(-c代表录入值后,自动转移并录入)
    6.可参考网址:https://blog.csdn.net/qq_46370017/article/details/126347976

使用

1.插槽机制

  • 一个 Redis 集群包含 16384 个插槽(hash slot), 数据库中的每个键都属于这 16384 个插槽的其中一个
  • 插槽用来把值平均分配到不同主机中去,达到分担压力的效果。(比如set k1 v1操作的时候,会计算k1所在插槽值,根据各节点管辖的插槽范围,放入相应的节点中去)
  • 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽
    2.录入值
  • redis每次录入、查询键值,redis都会计算出该key应该送往的插槽,如果不是该客户端对应服务器的插槽,redis会告知应前往的redis实例地址和端口
  • redis-cli客户端提供了-c参数实现自动重定向
  • 如redis-cli -c -p 6379 登入后,再录入、查询键值可以自动重定向
  • 不在一个slot下的键值,是不能使用mget,mset等多键操作
  • 可以通过{}来定义组概念,从而使得key中{}内相同内容的键值对放到一个slot中去(key值后面添加{ 组名 },就可以根据组名计算插槽,而不用再根据key值计算)
    3.集群常用命令
  • cluster keyslot 得到key键的插槽值
  • cluster countkeysinslot 返回slot有多少key(这里要注意,它查询的是本机,如果你的slot落在其他机器上,你查询的值会是0,必须找到对应的机器查询,才会准确)
  • cluster getkeysinslot 返回count个slot槽中的键(如果count大于slot数量,也只会返回全部的键,并不会报错)

故障恢复

  • 如果主节点下线,从节点会自动升为主节点(配置文件里面设置cluster-node-timeout 15000,所以会在15秒后判断为失联)
  • 主节点恢复后,它成为从机
  • 如果所有某一段插槽主从都宕机,redis服务是否还能继续,要根据不同的配置而言
    • redis.conf 中参数 cluster-require-full-coverage,如果为yes:整个集群都挂掉,如果为no:只是该插槽数据不能使用,也无法存储

Jedis开发

  • 即使链接的不是主机,集群会自动切换主机存储,主机写,从机读
  • 无中心化主从集群,无论从哪台主机写的数据,其他主机上都能读到数据
  • 记得打开Redis相关的端口,否则会报错
    • 1.firewall-cmd --add-port=<redis服务端口号>/tcp --permanent
    • 2.firewall-cmd --reload
    • 3.firewall-cmd --list-all

优缺点

  • 优点
    • 扩容方便(集群增加节点)
    • 分摊压力(读写分离、key分段)
    • 无中心配置简单(任意一台接入)
  • 缺点
    • 多键操作不被允许
    • 多键Redis事务是不被支持的,lua脚背不被支持
    • 由于此方案出现较晚,大部分公司采用其他集群方案,而需要切换为此方案,需要整体迁移过渡而不是逐步过渡,难度和复杂度高

应用

缓存穿透

  • 原理:当用户访问一个不存在数据,每次都通过缓存去施压数据源,导致数据源崩溃,而原来缓存的价值和作用消失了
  • 现象:应用服务器会线程堆积、redis命中率降低、一直查数据库
  • 解决思路:
    • 对空值进行缓存:如果一个查询返回的数据为空,我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间短一些,最长不超过5分钟
    • 设置可访问的名单(白名单):定义一个可访问名单,每次访问和白名单id进行比较,如果访问id不在白名单,进行拦截,不允许访问,比如使用bitmaps实现
    • 采用布隆过滤器:布隆过滤可以用于检索一个元素是否在一个集合中,优点是空间效率和查询时间都远远超过一般算法,缺点是有一定误判率和删除困难
    • 进行实时监控:当发现Redis命中率开始急剧下降,需要排查访问对象和访问的数据,需要和运维人员配合,可以设置黑名单限制服务

缓存击穿

  • 原理:当某个key过期的一瞬间,正好遇到大并发瞬间访问数据源,导致数据源崩溃,而原来缓存的价值和作用消失了
  • 现象:数据库访问压力瞬间增加、redis里面没有出现大量key过期、redis正常运行,但是数据库可能瘫痪了
  • 解决思路:
    • 预先设置热门数据:在redis高峰访问前,把一些热门数据提前存入redis里面,加大这些热门数据的key时长
    • 实时调整:现场监控哪些数据热门,实时调整key的过期时间
    • 使用锁:设置排他锁,仅允许一个线程进入数据库查询并重新放入缓存,其他并发线程休眠等待,此方案效率会有所影响

缓存雪崩

  • 原理:当大量key过期的一瞬间,正好遇到大并发瞬间访问数据源,导致数据源崩溃,而原来缓存的价值和作用消失了
  • 现象:数据库访问压力变大,服务器崩溃、Redis极短时间有大量key访问,而这些key集中过期
  • 解决思路:
    • 构建多级缓存架构:nginx缓存 + redis缓存 + 其他缓存(ehcache等),这种方式开发/维护成本高
    • 使用锁或者队列:用加锁和队列保证不会有大量线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上,不适用高并发情况
    • 设置过期标志更新缓存:记录缓存数据是否过期,如果过期会触发通知另外线程在后台去主动更新实际key的缓存,而不是等到一起过期的时候一起去更新
    • 将缓存失效时间分散开:可以在原有的失效时间基础上增加一个随机值,如1-5分钟随机,这样每个缓存的过期时间的重复率就会降低,就很难引发集体失效事件

分布式锁

我们在开发应用的时候,如果需要对某一个共享变量进行多线程同步访问的时候,可以使用我们学到的锁进行处理,但是,普通的锁只能在单机的情况下使用。随着业务的发展,用户数越来越多,访问量大幅增加,就需要我们做集群,一个应用需要部署到几台机器,然后做负载均衡,为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用并发处理相关的功能进行互斥控制。但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的应用并不能提供分布式锁的能力。为了解决这个问题就需要一种跨机器的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题
https://blog.csdn.net/qq_41378597/article/details/123384266

主流实现方案

  • 基于数据库实现分布式锁
  • 基于缓存(Redis等):性能最好
  • 基于Zookeeper:可靠性最好

redis实现分布式锁

基本指令(以锁的角度理解指令)
  • setnx key value 进行上锁/加锁,利用在这个key没有删除前,不能执行相同key的上锁指令
  • del key 释放锁,删除值
  • expire key seconds 给锁设置过期时间,防止死锁
  • ttl key 查看锁的过期剩余时间,过期显示-2
  • set key value nx ex seconds 为了保证原子性,可以在设置锁同时设置过期时间,以免另一条指令失败
代码实现
    //编写方法:完成分布式锁对num+1操作
    @GetMapping("/lock")
    public void lock(){

        //设置锁/获取锁 key -》 lock:setnx
        //Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "ok");
        //设置锁/获取锁 key -》 lock:set lock ok -nx -er 3000,防止死锁,随之产生一个问题,自动释放时业务未执行完成,
        // 后面的线程开始抢资源,且最重要的是会删其他线程的锁
        //Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "ok",3, TimeUnit.SECONDS);
        //增加UUID保护
        String uuid = UUID.randomUUID().toString();
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS);


        if(lock){
            //设置锁成功
            Object value = redisTemplate.opsForValue().get("num");
            //判断value是否有值,需要事先初始化
            if(value==null|| !StringUtils.hasText(value.toString())){
                //未初始化,或者无法初始化
                return;
            }
            //转为整数
            int num = Integer.parseInt(value.toString());
            //设置回去
            redisTemplate.opsForValue().set("num", ++num);
            //释放锁-lock
            //redisTemplate.delete("lock");

            //防止误删其他线程的锁,uuid比对
            //Object uuidR = redisTemplate.opsForValue().get("lock");
            //if (uuid.equals((String) uuidR)){
            //    // 这里到下面删除比较中间会有时间差,极端情况会出现瞬间其他用户进来(因为这里瞬间锁到期了),删除了其他线程锁
            //    redisTemplate.delete("lock");
            //}

            //这里需要保证删除的原子性,使用lua脚本
            //原子脚本定义
            String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
            //建立脚本执行器
            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
            //设置内容
            redisScript.setScriptText(script);
            //设置返回值
            redisScript.setResultType(Long.class);
            //执行脚本
            redisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);

        } else{
            // 获取锁失败,休眠100毫秒,再重新获取lock
            try {
                Thread.sleep(100);
                //重新执行
                lock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
注意事项和细节
  • 定义锁的key,key可以根据业务,分别设置,比如操作某商品,key应该是为每个sku定义的,也就是每个sku有一把锁
  • 为了确保分布式锁可用,要确保锁的实现同时满足以下四个条件:
    • 互斥性,在任意时刻,只有一个客服端能持有锁
    • 不会发生死锁,即使有个客户端在持有锁期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁
    • 加锁和解锁必须是同一客户端,A客户端不能把B客户端加的锁给解了
    • 加锁和解锁必须具有原子性

Redis ACL

Access Control List(访问控制列表)的缩写,该功能限制可以执行的命令和可以访问的键;redis 5版本前只有密码控制和rename来调整高危命令(如 flushdb、KEYS*、shutdown等);而Redis ACL则提供对用户进行更细粒度的权限控制

  • 接入权限:用户名和密码
  • 可以执行的命令
  • 可以操作的KEY

常用指令

1.acl list 命令展示用户权限列表
2.acl cat 命令

Redis新功能

IO多线程

IO多线程是指和客户端交互时,网络IO交互处理模块多线程,而非执行命令多线程(Redis6执行命令依然是单线程);总的来说Redis和客户端的交互是多线程,在执行指令的时候,仍然是单线程+IO多路复用
IO多线程只用来处理网络数据的读写和协议解析,之所以这么设计是不想因为多线程而变得复杂(去改造控制key、lua、事务、lpush等并发问题)
默认不开启,需要配置文件设置

io-threads-do-reads yes
io-threads 4

工具支持Cluster

老版Redis想要搭建集群需要单独安装ruby环境;Redis 5 将redis-trib.rb 的功能集成到redis-cli;官方的redis-benchmark工具(性能测试工具,它可以模拟N个客户端同时向redis发送M条查询命令的应用场景)开始支持cluster模式,通过多线程的方式对多个分片进行压测

其他新功能

1.RESP3新的Redis通信协议:优化服务端与客户端之间通信
2.Client side caching 客户端缓存:基于RESP3协议实现的客户端缓存功能。为了进一步提升缓存的性能,将客户端经常访问的数据cache到客户端,减少TCP网络交互
3.Proxy集群代理模式:Proxy功能,让Cluster拥有像单实例一样的接入方式,降低大家使用cluster的门槛
4.Modules API
Redis 6中模块API开发进展非常大,因为Redis Labs为了开发复杂的功能,从一开始就用上Redis模块。
Redis可以变成一个框架,利用Modules来构建不同系统,而不需要从头开始写然后还要BSD许可。
Redis一开始就是一个向编写各种系统开放的平台。

posted @   邵泽龙  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示