redis
2020-01-15 13:55:16 0 举报
AI智能生成
登录查看完整内容
redis
作者其他创作
大纲/内容
redis配置
Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf
CONFIG GET * 获取所有配置项
CONFIG GET CONFIG_SETTING_NAME 获取某项具体的配置
CONFIG SET CONFIG_SETTING_NAME NEW_CONFIG_VALUE
redis.conf详解
持久化
RDB
RDB 快照,对redis中的数据执行周期性的全量持久化到磁盘,恢复快
RDB生成快照可自动触发,也可以使用命令手动触发,以下是redis触发执行快照条件
客户端执行命令save和bgsave会生成快照
save操作阻塞主进程,会导致服务一段时间不可用
bgsave 是fork子进程来执行save操作,仅在fork子进程的时候发生阻塞
根据配置文件save m n规则进行自动快照
主从复制时,从库全量复制同步主库数据,此时主库会执行bgsave命令进行快照
客户端执行数据库清空命令FLUSHALL时候,触发快照
客户端执行shutdown关闭redis时,触发快照
RDB持久化机制的工作流程
2、子进程尝试将数据dump到临时的rdb快照文件中
3、完成rdb快照文件的生成之后,就替换之前的旧的快照文件
优点
灵活设置备份频率和周期
非常适合冷备份,对于灾难恢复来说,RDB 是非常不错的选择。我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上
性能最大化。对于 Redis 的服务进程而言,在开始持久化时,它唯一需要做的只是 fork 出子进程,极大避免了服务进程进行IO操作
相比于 AOF 机制,RDB 的恢复速度更更快
缺点
如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔一段时间生成一次
RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒
AOF
AOF 追加 更新指令 到本地文件,达到一定的量后会对文件进行瘦身
AOF持久化配置
always: 每次写入一条数据,同步追加到aof文件,性能非常非常差,吞吐量很低; 确保说redis里的数据一条都不丢失
everysec: 每秒将os cache中的数据追加到aof文件。默认的配置
no: 仅仅redis负责将数据写入os cache就撒手不管了,然后后面os自己会时不时有自己的策略将数据刷入磁盘,不可控制(即redis不负责更新aof文件,何时更新由宿主机自己决定,Linux64位大概是30秒一次)
AOF 重写
aof文件是追加的形式增量递增的 ,因为内存的容量是有限的,且redis的有些数据会有过期的概念,和淘汰机制的存在,会导致一开始存储的指令没有实际对应的数据。
重写工作流程
redis fork一个子进程
子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写入日志
redis主进程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件
子进程写完新的日志文件之后,redis主进程将内存中的新日志再次追加到新的AOF文件中,最后替换旧的文件
该机制可以带来更高的数据安全性,即数据持久性。Redis 中提供了 3 种同步策略,即每秒同步、每修改(执行一个命令)同步和不同步
日志文件的写入操作采用的是 append 模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容
AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据
对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
根据同步策略的不同,AOF 在运行效率上往往会慢于 RDB
持久化的意义:故障恢复
AOF:存放的指令日志,做数据恢复的时候,其实是要回放和执行所有的指令日志,来恢复出来内存中的所有数据的
RDB,就是一份数据文件,恢复的时候,直接加载到内存中即可
持久化方案
持久化方案:主从的时候 主节点只做aof (避免aof重写?) 从节点使用aof+rdb混合持久化
开启混合持久化
# aof-use-rdb-preamble yes
key过期策略
主动过期:redis会将所有设置过期时间的key放在一个独立的字典里面,以后会定时遍历这个字典来删除到期的 key
1、默认会每秒进行十次过期扫描
2、从过期字典中随机 20 个 key,删除这 20 个 key 中已经过期的 key
3、如果过期的 key 比率超过 1/4,那就重复步骤 1
4、同时,为了保证过期扫描不会出现循环过度,导致线程卡死现象,算法还增加了扫描时间的上限,默认不会超过 25ms
惰性删除:就是指在客户端访问这个 key 的时候,redis 对 key 的过期时间进行检查,如果过期了就立即删除。
缓存
缓存雪崩
同一时间大面积的缓存失效,或者redis宕机,瞬间所有查询打到DB上,导致DB奔溃。
解决方案
分散key的过期时间
通过搭建缓存的高可用,避免缓存挂掉导致无法提供服务的情况
使用本地缓存时,即使分布式缓存挂了,也可以将 DB 查询到的结果缓存到本地,避免后续请求全部到达 DB 中
缓存穿透
被动写:当从缓存中查不到数据时,然后从数据库查询到该数据,写入该数据到缓存中
解决方法
1、网关层(比如说nginx)做限制,对每秒请求超出一定阈值的ip做拉黑处理
2、缓存空对象。当从 DB 查询数据为空,我们仍然将这个空结果进行缓存,并设置过期时间
3、使用布隆过滤器。在缓存服务的基础上,构建 BloomFilter 数据结构,在 BloomFilter 中存储对应的 KEY 是否存在,如果存在,说明该 KEY 对应的值不为空。需要提前将已存在的数据放在布隆过滤器里面
1、根据 KEY 查询【BloomFilter 缓存】。如果不存在对应的值,直接返回;如果存在,继续向下执行。
2、根据 KEY 查询在【数据缓存】的值。如果存在值,直接返回;如果不存在值,继续向下执行。
3、查询 DB 对应的值,如果存在,则更新到缓存,并返回该值。
缓存击穿
某个极度“热点”数据在某个时间点过期时,恰好在这个时间点对这个 KEY 有大量的并发请求过来,导致DB奔溃
1、使用互斥锁。请求发现缓存不存在后,去查询 DB 前,使用分布式锁,保证有且只有一个线程去查询 DB ,并更新到缓存。
1、获取分布式锁,直到成功或超时。如果超时,则抛出异常,返回。如果成功,继续向下执行。
2、获取缓存。如果存在值,则直接返回;如果不存在,则继续往下执行。因为,获得到锁,可能已经被“那个”线程去查询过 DB ,并更新到缓存中了
3、查询 DB ,并更新到缓存中,返回值。
2、手动过期。缓存上从不设置过期时间,功能上将过期时间存在 KEY 对应的 VALUE 里
1、获取缓存。通过 VALUE 的过期时间,判断是否过期。如果未过期,则直接返回;如果已过期,继续往下执行。
2、通过一个后台的异步线程进行缓存的构建,也就是“手动”过期。通过后台的异步线程,保证有且只有一个线程去查询 DB。
3、同时,虽然 VALUE 已经过期,还是直接返回。通过这样的方式,保证服务的可用性,虽然损失了一定的时效性。
数据双写不一致???
并发的场景下,导致读取老的 DB 数据,更新到缓存中
缓存和 DB 的操作,不在一个事务中,可能只有一个 DB 操作成功,而另一个 Cache 操作失败,导致不一致。
2、先淘汰缓存,再写数据库因为先淘汰缓存,所以数据的最终一致性是可以得到有效的保证的。为什么呢?先淘汰缓存,即使写数据库发生异常,也就是下次缓存读取时,多读取一次数据库。https://www.w3cschool.cn/architectroad/architectroad-consistency-of-cache-with-database.html
1、将缓存可能存在的并行写,实现串行写。
在写请求时,先淘汰缓存之前,先获取该分布式锁。
在读请求时,发现缓存不存在时,先获取分布式锁。
拓展
edis存储键值对实际使用的是hashtable的数据结构
Redis线程模型
Redis 内部使用文件事件处理器 file event handler,这个文件事件处理器是单线程的,所以 Redis 才叫做单线程的模型。
它采用 IO 多路复用机制同时监听多个 Socket,根据 Socket 上的事件来选择对应的事件处理器进行处理
多个 Socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程序会监听多个 socket
会将 socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,把该事件交给对应的事件处理器进行处理
单线程避免了多线程的切换性能损耗问题
keys 和 scan
redis是单线程的,在数据量大的时候,keys * 操作获取全部的key就会导致 Redis 服务卡顿,其余的指令延后或超时报错
sacn 是通过游标分步进行的,不会阻塞线程
提供 limit 参数,可以控制每次返回结果的最大条数
返回的结果可能会有重复,需要客户端去重复
遍历的过程中如果有数据修改,改动后的数据能不能遍历到是不确定的
info:查看redis服务运行信息
Server
Clients
connected_clients:当期连接的客户端数量client_recent_max_input_buffer:当前连接的客户端当中,最大输入缓存client_recent_max_output_buffer:当前连接的客户端当中,最长的输出列表blocked_clients:阻塞的客户端数量BLPOP、BRPOP、BRPOPLPUSH
Memory
used_memory:使用内存,以字节(byte)为单位used_memory_human:以人类可读的格式返回 Redis 使用内存used_memory_rss:系统给redis分配的内存即常驻内存,和top 、 ps 等命令的输出一致used_memory_rss_human:used_memory_peak:内存使用的峰值大小used_memory_peak_human:used_memory_peak_perc:used_memory_overhead:used_memory_startup:used_memory_dataset:used_memory_dataset_perc:allocator_allocated:allocator_active:allocator_resident:total_system_memory:total_system_memory_human:used_memory_lua:lua引擎使用的内存used_memory_lua_human:used_memory_scripts:used_memory_scripts_human:number_of_cached_scripts:maxmemory:maxmemory_human:maxmemory_policy:allocator_frag_ratio:allocator_frag_bytes:allocator_rss_ratio:allocator_rss_bytes:rss_overhead_ratio:rss_overhead_bytes:mem_fragmentation_ratio:redis 内存碎片率mem_fragmentation_bytes:mem_not_counted_for_evict:mem_replication_backlog:mem_clients_slaves:mem_clients_normal:mem_aof_buffer:mem_allocator: 内存分配器active_defrag_running:lazyfree_pending_objects:
Persistence
loading:0rdb_changes_since_last_save:1866 #自上次dump后rdb的改动rdb_bgsave_in_progress:0 #标识rdb save是否进行中rdb_last_save_time:1452048771 #上次save的时间戳rdb_last_bgsave_status:ok #上次的save操作状态rdb_last_bgsave_time_sec:0 #上次rdb save操作使用的时间(单位s)rdb_current_bgsave_time_sec:-1 #如果rdb save操作正在进行,则是所使用的时间aof_enabled:1 #是否开启aof,默认没开启(已开启)aof_rewrite_in_progress:0 #标识aof的rewrite操作是否在进行中aof_rewrite_scheduled:0 #标识是否将要在rdb save操作结束后执行aof_last_rewrite_time_sec:0 #上次rewrite操作使用的时间(单位s)aof_current_rewrite_time_sec:-1 #如果rewrite操作正在进行,则记录所使用的时间aof_last_bgrewrite_status:ok #上次rewrite操作的状态aof_last_write_status:ok #上次write操作的状态aof_current_size:42820373 #aof当前大小,以字节(byte)为单位aof_base_size:16223723 #aof上次启动或rewrite的大小aof_pending_rewrite:0 #同上面的aof_rewrite_scheduledaof_buffer_length:0 #aof buffer的大小aof_rewrite_buffer_length:0 #aof rewrite buffer的大小aof_pending_bio_fsync:0 #后台IO队列中等待fsync任务的个数aof_delayed_fsync:41394 #延迟的fsync计数器aof_last_cow_size:
Stats
total_connections_received:61264941 #自启动起连接过的总数total_commands_processed:951647408 #自启动起运行命令的总数instantaneous_ops_per_sec:13 #每秒执行的命令个数total_net_input_bytes:10353total_net_output_bytes:18286instantaneous_input_kbps:0.00instantaneous_output_kbps:0.00rejected_connections:0 #因为最大客户端连接书限制,而导致被拒绝连接的个数sync_full:23 sync_partial_ok:0 sync_partial_err:0expired_keys:40225836 #自启动起过期的key的总数expired_stale_perc:0.00expired_time_cap_reached_count:0evicted_keys:0 #因为内存大小限制,而被驱逐出去的键的个数keyspace_hits:54841673 #自启动起命中key的个数keyspace_misses:344507 #自启动起未命中key的个数pubsub_channels:0pubsub_patterns:0latest_fork_usec:8775 #上次的fork操作使用的时间(单位ms)migrate_cached_sockets:0 slave_expires_tracked_keys:0active_defrag_hits:0active_defrag_misses:0active_defrag_key_hits:0active_defrag_key_misses:0
Replication
CPU
used_cpu_sys:23111.87 #cpu在内核态所消耗的cpu的时间used_cpu_user:17763.81 #cpu在用户态所消耗的cpu的时间used_cpu_sys_children:7909.22used_cpu_user_children:62767.11
Cluster
cluster_enabled:0#是否允许集群
Keyspace
淘汰机制
当 Redis 内存超出物理内存限制时,内存的数据会开始和磁盘产生频繁的交换 (swap)
交换会让 Redis 的性能急剧下降,对于访问量比较频繁的 Redis 来说,这样龟速的存取效率基本上等于不可用
为了限制最大使用内存,Redis 提供了配置参数 maxmemory 来限制内存超出期望大小 ,超出后执行淘汰策略
淘汰策略
noeviction:不淘汰key(默认),只能读,不能写
volatile-lru : 淘汰过期集合的key中最少使用
volatile-ttl : 淘汰过期集合的key中,剩余寿命最短
volatile-random : 随机淘汰过期集合的key
allkeys-lru : 淘汰全部key中最少使用
allkeys-random 随机淘汰全部key
redis
数据类型
基本数据类型
String字符串
当字符串长度小于1M前,成倍扩容,大于1M后每次只扩容1M最大为512M
每次修改后会使设置的过期时间失效
指令
set key value
设置指定的key值
get key
获取key的值
getrange key start end
获取字符串值的字符串 getrange wang 1 2 如果值是huan 就是ua
getset key value
将给定 key 的值设为 value ,并返回 key 的旧值(old value)
getbit key offset
对key所存储的字符串值,获取指定偏移量上的位
mget key1 key2
获取多个key对应的值
setbit key offset
对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)
setex key seconds value
将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)
setnx key value
只有当key不存在时,新增key
setrange key offset value
用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始,返回修改后value的长度
strlen key
返回 key 所储存的字符串值的长度
mset key value key value
同时设置一个或多个key value对
msetnx key value key value
当且仅当所有给定 key 都不存在,设置多个键值对,如果已经有一个key已经存在,则整条语句失败
psetex key milliseconds value
它以毫秒为单位设置 key 的生存时间
incr key
将key中存储的数字值增一
incrby key increment
将 key 所储存的值加上给定的增量值(increment)
decr key
将 key 中储存的数字值减一
incrbyfloat key increment
将 key 所储存的值加上给定的浮点增量值(increment)
\tdecrby key decrement
key 所储存的值减去给定的减量值(decrement)
append key value
如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾如果key不存在 就相当于set key value
Hash
Hash类型是String类型的field和value的映射表
Hash 可以对用户结构中的每个字段单独存储。这样当我们需要获取用户信息时可以进行部分获取
而以整个字符串的形式去保存用户信息的话就只能一次性全部读取,这样就会比较浪费网络流量。
但是hash 结构的存储消耗要高于单个字符串
每个 hash 可以存储 2的32次方 - 1 键值对(40多亿)
hdel key filed1 field2
删除一个或多个hash字段
hexists key filed
获取hash表中,指定的字段是否存在
hget key filed
获取hash表中指定字段的值
hgetall key
获取hash表中指定key的所有字段
hincrby key field increment
为哈希表 key 中的指定字段的整数值加上增量 increment
hincrbyfloat key field increment
为hash表 key 中的指定字段的浮点数值加上增量 increment
hkeys key
获取hash表中所有的字段
hlen key
获取hash表中字段的数量
hmget key field1 field2
获取hash表中给定字段的值
hmset key field1 value1 field2 value2
同时将多个 field-value (域-值)对设置到hash表 key 中
hset key field value
将hash表 key 中的字段 field 的值设为 value
hsetnx key field value
只有在字段 field 不存在时,设置哈希表字段的值
hvals key
获取hash表中所有的值
scan cursor match pattern count num
渐进式遍历键,从cursor开始取num个键,获取满足条件的key,除了返回满足条件的键,还会返回下个满足条件的游标
List
List类型是一个链表结构的集合,并且是有序的集合,其值是可以重复的
List类型有点类似数组的概念,所以具有下标,可以针对指定下标进行操作
既可以做【栈-先进后出】使用,也可以做【队列-先进先出】使用,所以常用来做异步队列使用
列表最多可以包含 2的32次方 - 1 个元素,约40亿
blpop key timeout
移出并获取列表的第一个元素(最后加入的数), 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
brpop key timeout
移出并获取列表的最后一个元素(最先加入的数), 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
brpoplpush source destination timeout
从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
lindex key index
通过索引获取列表中的元素
linsert key before|after pivot value
在列表的元素前或者后插入元素
llen key
获取列表的长度
lpop key
移除并获取列表中的第一个元素
lpush key value1 value2
将一个或多个值插入到列表头部
lpushx key value
将一个值插入到已存在的列表头部
lrange key start stop
获取列表指定范围的元素
lrem key count value
移除列表元素
lset key index value
通过索引设置列表元素的值,如果索引不存在报错
ltrim key start stop
对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
rpop
移除列表的最后一个元素,返回值为移除的元素
rpoppush source destination
移除列表的最后一个元素,并将该元素添加到另一个列表并返回
rpush key value1 value2
在列表中添加一个或多个值
rpushx key value
为已存在的列表添加值
r开头的是栈,l开头的是队列,队列先进先出
相当于 Java 语言里面的 LinkedList
list 的插入和删除操作非常快,但是索引定位很慢
Redis 的列表结构常用来做异步队列使用。将需要延后处理的任务结构体序列化成字符串塞进 Redis 的列表,另一个线程从这个列表中轮询数据进行处理
set
相当于 Java 语言里面的 HashSet,它内部的键值对是无序的唯一的,即可以用来做去重的处理
以对Set实施交集(Inter--InterStore)、并集(Union--UnionStore)和差集(Diff--DiffStore)的操作
sadd key member1 member2
向集合添加一个或多个成员
scard key
获取集合的成员数
sdiff key1 key2
获取key1和key2的差集,需要把元素多的key放在前面
sdiffstore destination key1 key2
获取key1和key2的差集,并把差集保存在destination 需要把元素多的key放在前面
sinter key1 key2
获取key1和key2的交集
sinterstore destination key1 key2
获取key1和key2的交集,并把交集保存在destination
sismember key member
判断member元素是否在集合key的成员,如果是返回1,如果不是返回0
smembers key
返回集合中的所有成员
smove source destination member
将 member 元素从 source 集合移动到 destination 集合,移动后source没有该元素
spop key
移除集合中一个随机的元素并返回
srandmember key count
返回集合中一个或多个随机数
srem key member1 member2
移除集合中的一个或多个成员
sunion key1 key2
返回所有给定集合的并集
sunionstore destination key1 key2
所有给定集合的并集存储在 destination 集合中
zset(sorted set)
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序
zadd key score1 member1 [score2 member2]
向有序集合添加一个或多个成员,或者更新已存在成员的分数
zcard key
获取有序集合的成员数
zcount key min max
计算在有序集合中指定区间分数的成员数
zincrby key increment member
有序集合中对指定成员的分数加上增量 increment,只是给分数增加增量改变排序,不会改变值得大学
zinterscore destination numkeys key [key ...]
计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中
zlexcount key min max
在有序集合中计算指定字典区间内成员数量
zrange key start stop [withscores]
通过索引区间返回有序集合指定区间内的成员,withscores表示显示每个元素的分数
zrangebylex key min max [limit offset count]
通过字典区间返回有序集合的成员
zrangebyscore key min max [withscores] [limit]
通过分数返回有序集合指定区间内的成员
zrank key member
返回有序集合中指定成员的索引,从0开始,如果不存在 返回nil
zrem key member [member ...]
移除有序集合中的一个或多个成员
zremrangebylex key min max
移除有序集合中给定的字典区间的所有成员
zremrangebyrank key start stop
移除有序集合中给定的排名区间的所有成员
zremrangebyscore key min max
移除有序集合中给定的分数区间的所有成员
zrevrange key start stop [withscores]
返回有序集中指定区间内的成员,通过索引,分数从高到低
自增是有范围的,它的范围是 signed long 9223372036854775807的最大最小值,超过了这个值,Redis 会报错
zrevrangebyscore key max min [withscores]
返回有序集中指定分数区间内的成员,分数从高到低排序
zrevrank key member
返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
zscore key member
返回有序集中,成员的分数值
zunionstore destination numkeys key [key ...]
计算给定的一个或多个有序集的并集,并存储在新的 key 中
zset 可以用来存粉丝列表,value 值是粉丝的用户 ID,score 是关注时间。我们可以对粉丝列表按关注时间进行排序。 zset 还可以用来存储学生的成绩,value 值是学生的 ID,score 是他的考试成绩。我们可以对成绩按分数进行排序就可以得到他的名次。
容器型数据结构的通用规则
list/set/hash/zset 这四种数据结构是容器型数据结构
如果容器不存在,那就创建一个,再进行操作
如果容器里元素没有了,那么立即删除元素,释放内存
HyperLogLog
HyperLogLog 提供不精确的去重计数方案(统计UV),标准误差为81%
pfmerge指令:用于将多个 pf 计数值累加在一起形成一个新的 pf 值(合并多个页面的UV值)
无法知道某一个值是不是已经在 HyperLogLog 结构里面(仅提供添加,统计,合并三个操作)
pfadd key element [element ...]
添加指定元素到 HyperLogLog 中
pfcount key [key ...]
返回给定 HyperLogLog 的基数估算值
pfmerge destkey sourcekey [sourcekey ...]
将多个 HyperLogLog 合并为一个 HyperLogLog
应用
统计注册 IP 数统计每日访问 IP 数统计页面实时 UV 数统计在线用户数统计用户每天搜索不同词条的个数
HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身
GeoHash
实现附近的人的功能 参考地址:https://juejin.im/post/5da40462f265da5baf410a11
Stream
redis 5.0后版本出现的数据结构 可以支持广播模式的可持久化的消息队列
布隆过滤器
可以理解为一个不怎么精确的 set 结构,通过在add前用bf.reserve指令显式创建,设定参数提高准确率
initial_size参数表示预计放入的元素数量,initial_size参数设置错误率,错误率越低,需要的空间越大
特性:当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在
解决去重的问题。比如我们在使用新闻客户端看新闻时,它会给我们不停地推荐新的内容,它每次推荐时要去重
处理缓存穿透
redis命令
检测是否有redis进程
ps -ef | grep redis
连接
$ redis-cli -h host -p port -a password
key
del key
删除key,删除成功返回1,删除失败返回0,如果key不存在也不会报错,返回0
dump key
序列号key,并返回序列号后的值,如果key值不存在返回NIL
exists key
判断key值是否存在,存在返回1,不存在返回0
expire key seconds
给key按秒设置过期时间,成功返回1,key不存在或者失败返回0
expireat key timestamp
给key按时间戳设置过期时间
pexpire key milliseconds
给key按毫秒设置过期时间
pexpireat key milliseconds-timestamp
设置 key 过期时间的时间戳(unix timestamp) 以毫秒计
keys pattern
查找所有符合给定模式的key
move key db
将当期的key移动到给定的db中
persist key
移除key过期时间,key将永远保持持久
pttl key
以毫秒为单位,返回key的过期时间
ttl key
以秒为单位,返回key的过期时间
randomkey
从数据库中随机返回一个key
rename key newkey
给key重命名,如果key不存在会报错
renamenx key newkey
给key重命名,只有当newkey不存在才会成功
type key
返回 key 所储存的值的类型
主从同步
增量同步
Redis 同步的是指令流,主节点会将那些对自己的状态产生修改性影响的指令记录在本地的内存 buffer 中,然后异步将 buffer中的指令同步到从节点,从节点一边执行同步的指令流来达到和主节点一样的状态,一边向主节点反馈自己同步到哪里了 (偏移量)因为内存的 buffer 是有限的,所以 Redis 主库不能将所有的指令都记录在内存 buffer 中,Redis 的复制内存 buffer 是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容。
快照同步
快照同步是一个非常耗费资源的操作,它首先需要在主库上进行一次 bgsave 将当前内存的数据全部快照到磁盘文件中,然后再将快照文件的内容全部传送到从节点,从节点将快照文件接受完毕后,立即执行一次全量加载,加载之前先要将当前内存的数据清空。加载完毕后通知主节点继续进行增量同步,在整个快照同步进行的过程中,主节点的复制 buffer 还在不停的往前移动,如果快照同步的时间过长或者复制 buffer 太小,都会导致同步期间的增量指令在复制 buffer 中被覆盖,这样就会导致快照同步完成后无法进行增量复制,然后会再次发起快照同步,如此极有可能会陷入快照同步的死循环。
当从节点刚刚加入到集群时,它必须先要进行一次快照同步,同步完成后再继续进行增量同步。
从节点过期key处理:slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。
缓存:热点数据
分库分表的自增id
实时防攻击系统
排行榜
设定有效期的应用
自动去重
session跨域
分布式锁
先用setnx ex来获取锁,并设置过期时间,过期时间主要用来防止业务代码异常,锁没有释放的情况导致死锁的情况
redis分布式锁过期时间到了业务没执行完问题
redssion 中的 watch dog自动延期机制
默认设置过期时间为30秒,只要客户端成功获得锁,就会启动watch dog。每10秒检查一次客户端是否还持有锁,如果有,则延长过期时间
主从异步复制导致的问题
客户端1对某个redis master实例,写入了锁,此时会异步复制给对应的master slave实例
但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master
接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。
此时就会导致多个客户端对一个分布式锁完成了加锁
RedLock算法:https://www.jianshu.com/p/fba7dd6dcef5
异步队列
list结构作为队列,使用rpush/lpush操作入队列,使用lpop 和 rpop来出队列。缺点:没有等待队列里有值就直接消费,可以通过在应用层引入sleep机制来降低请求频率
list中还有另一个指令,BLPOP key [keys ...] timeout:阻塞直到队列有消息或者超时,当 timeout 为 0 是表示阻塞时间无限制,会导致空闲连接问题,服务器会主动断开,抛出异常,客户端需要捕获处理,或重试,并且只能供一个消费者消费
pub/sub:主题订阅者模式 实现1:N的消息队列,但是消费者下线的时候会导致消息丢失,所以当redis宕机的时候,pub/sub的数据不会持久化
Redis5.0后提供 Stream 解决了pub/sub消息不能持久化的问题。https://blog.csdn.net/enmotech/article/details/81230531
延时队列
使用zset结构,将消息序列化成一个字符串作为 zset 的value,这个消息的到期处理时间作为score
用多个线程轮询 zset 获取到期的任务进行处理,多个线程是为了保障可用性,万一挂了一个线程还有其它线程可以继续处理
Redis Cluster
哨兵机制
哨兵+主从 实现redis 集群高可用
集群监控:负责监控Redis master和slave是否征正常进行工作
消息通知:如果某个Redis实例挂了,那么哨兵会发送通知给系统管理员
故障转移:如果master node挂了,会自动转移到slave node上
配置中心:如果故障转移发生,通知客户端最新的master node的地址
Sentinel 无法保证消息完全不丢失,但是也尽可能保证消息少丢失。它有两个选项可以限制主从延迟过大
min-slaves-to-write 1 表示主节点必须至少有一个从节点在进行正常复制,否则就停止对外写服务,丧失可用性
min-slaves-max-lag 10 表示如果 10s 没有收到从节点的反馈,就意味着从节点同步不正常
https://segmentfault.com/a/1190000017578588
0 条评论
回复 删除
下一页