标签:复用 aof 主从模式 tab 出现 文件的 失败 get coding
redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库
其具有以下特点:开源、多种数据结构、基于键值的存储服务器、高性能、功能服务
优点:数据类型丰富、效率高、支持集群、支持持久化
缺点:单进程单线程,长命令可能会导致redis阻塞、集群下多key同时操作无法使用
值可以是字符串、数字(整数和浮点)、二进制【其中,整数的取值范围与系统的长整型取值一致[32位系统是32位、64位系统是64位];浮点数的精度为double】
命令 | 说明 | 时间复杂度 |
---|---|---|
GET K | 获取K对应的V | O(1) |
MGET K1 K2 K3 ... | 批量获取K对应的V,原子性操作 | O(N) |
GETSET K V | 设置K-V并返回旧的V | O(1) |
GETRANGE K start end | 获取K对应V字符串的指定下标所有的值 | O(1) |
SET K V | 设置K-V,K存在修改K对应的V,K不存在新增K-V | O(1) |
SETNX K V | K不存在时才设置 | O(1) |
SETRANGE K index V | 设置K对应V字符串的执行下标所对应的值 | O(1) |
APPEND K V | 将V追加到K对应的旧V后 | O(1) |
MSET K1 V1 K2 V2 K3 V3 ... | 批量设置K-V | O(1) |
DEL K | 删除K-V | O(1) |
INCR K | K自增1,如果K不存在,自增后GET K = 1 | O(1) |
DECR K | K自减1,如果K不存在,自减后GET K = -1 | O(1) |
INCRBY K I | K自增I,如果K不存在,自增后GET K = I | O(1) |
DECRBY K I | K自减I,如果K不存在,自减后GET K = -I | O(1) |
INCRBYFLOAT K F | K自增F,如果K不存在,自增后GET K = F | O(1) |
STRLEN K | 返回字符串长度(UTF8下中文占3个字符) | O(1) |
在使用hash的HGETALL指令时应当谨慎小心,因为redis是单线程的,此命令可能需要比较久的处理时间,可能会导致redis阻塞
命令 | 说明 | 时间复杂度 |
---|---|---|
HGET K F | 获取K下的F对应的V | O(1) |
HMGET K F1 F2 F3 ... | 批量获取K下F1、F2、F3的V | O(N) |
HGETALL K | 批量获取K下所有的F-V | O(N) |
HKEYS K | 返回K对应的所有的F | O(N) |
HVALS K | 返回K对应的所有F的V | O(N) |
HSET K F V | 设置K下对应的F-V | O(1) |
HMSET K F1 V1 F2 V2 F3 V3 ... | 批量设置K下的F1-V1、F2-V2、F3-V3 | O(1) |
HSETNX K F V | 设置K-F-V,当F已存在时则设置失败 | O(1) |
HEXISTE K F | 判断K下是否有F | O(1) |
HLEN K | 获取K下F的数量 | O(1) |
HINCRBY K F I | K下的F对应的V自增I | O(1) |
HINCRBYFLOAT K F F | K下的F对应的V自增F | O(1) |
有序,不唯一,链表实现,左右两边都可以执行插入和弹出操作,容量是2的32次方减1个元素
命令 | 说明 | 时间复杂度 |
---|---|---|
RPUSH K V1 V2 V3 ... | 从列表右端依次插入V1、V2、V3 | O(N) |
LPUSH K V1 V2 V3 ... | 从列表左端依次插入V1、V2、V3 | O(N) |
LINSERT K [before/after] V NV | 在K指定的V[前/后]插入NV | O(N) |
LPOP K | 从列表的左端弹出一个V | O(1) |
BLOPO K timeoout | LPOP阻塞版本,timeout为阻塞时间,timeout为0时永远阻塞 | O(1) |
RPOP K | 从列表的右端弹出一个V | O(1) |
BRPOP K | RPOP阻塞版本,timeout为阻塞时间,timeout为0时永远阻塞 | O(1) |
LREM K count V | 1)count>0,从左到右删除最多count个value相等的项 2)count<0,从右到左删除最多count个value相等的项 3)count=0,删除所有value相等的项 |
O(N) |
LTRIM K start end | 按照索引范围修建列表 | O(N) |
LRANGE K start end | 获取列表指定索引范围内所有的V | O(N) |
LINDEX K index | 获取列表指定索引的V | O(1) |
LLEN K | 获取列表的长度 | O(1) |
LSET K index V | 设置列表指定索引的值为V | 0(N) |
无序,唯一,哈希表实现
命令 | 说明 | 时间复杂度 |
---|---|---|
SADD K V | 向集合K中添加V,如果V已经存在,则添加失败 | O(1) |
SREM K V | 将集合K中的V移除 | O(1) |
SCARD K | 计算集合的大小 | O(1) |
SISMEMBER K V | 判断集合K中是否存在V | O(1) |
SRANDMEMBER K count | 从集合K中随机挑选count个V,不会改变集合 | O(1) |
SPOP K | 从集合K中随机弹出一个V,会改变集合 | O(1) |
SMEMBERS K | 获取集合K中所有的V,大数据量场景可能会导致redis阻塞 | O(1) |
SDIFF K1 K2 | 求K1和K2两个集合的差集 | O(1) |
SINTER K1 K2 | 求K1和K2两个集合的交集 | O(1) |
SUNION K1 K2 | 求K1和K2两个集合的并集 | O(1) |
[SDIFF/SINTER/SUNION] K1 K2 store destK | 将K1和K2的[差集、交集、并集]的结果保存到destK中 | O(1) |
有序,唯一,每个元素都会关联一个double类型的分数,通过分数来为集合中的元素进行从小到大的排序,分数可以重复
命令 | 说明 | 时间复杂度 |
---|---|---|
ZADD K S V | 向集合K中添加分数为S的V | O(logN) |
ZREM K V1 V2 V3 ... | 删除集合K中的V1、V2、V3 | O(1) |
ZSCORE K V | 返回集合K中V的分数 | O(1) |
ZINCRBY K increScore V | 将集合K中的V分数自增或自减increScore | O(1) |
ZCARD K | 返回集合K中的V总个数 | O(1) |
ZRANK K menber | 返回集合K中元素的排名 | O(1) |
ZRANGE K start end | 返回集合K中指定索引范围内的升序元素 | O(logN+M) |
ZRANGEBYSCORE K minS maxS | 返回集合K中指定分数范围内的升序元素 | O(logN+M) |
ZCOUNT K minS maxS | 返回集合K中指定分数范围内的元素的个数 | O(logN+M) |
ZREMRANGEBYRANK K start end | 删除集合K中指定排名内的元素 | O(logN+M) |
ZREMRANGEBYSCORE K minS maxS | 删除集合K中指定分数内的元素 | O(logN+M) |
ZINTERSTORE destZ numkeys K1 K2 K3 ... | 计算集合K1 K2 K3的交集,将结果存储在新的destZ有序集合中 | |
ZUNIONSTORE dtstZ numneys K1 K2 K3 ... | 计算集合K1 K2 K3的并集,将结果存储在新的destZ有序集合中 |
地理信息定位,存储经纬度,计算两地距离,范围计算等
命令 | 说明 |
---|---|
GEOADD K LON LAT member [LON1 LON2 member ...] | 向K中添加地理位置,命名为member LAT(维度):取值为[-85.05112878 ~ 85.05112878] |
GEOPOS K menber [member1 ...] | 获取K中的menber地理位置信息 |
GEODIST K member1 member2 [unit] | 获取两个地理坐标之间的距离,默认为m unit:[m(米)、km(千米)、mi(英里)、ft(英尺)] |
GEORADIUS K LON LAT radius unit [withcoord] [withdist] [withhash] [asc/desc] [count n] | 以给定的经纬度为中心,返回K包含的位置元素当中与中心的距离不超错给定最大距离的所有位置元素 unit:[m(米)、km(千米)、mi(英里)、ft(英尺)] withcoord:将位置元素的经纬度一起返回 withdist:在返回元素的同时,将位置与中心位置之间的距离也一起返回,距离的单位和给定的范围单位一致 asc/desc:根据中心位置,按照[从近到远/从远到近]的方式返回位置元素,默认不排序 count n:获取n个匹配的元素 |
GEORADIUSBYMEMBER K menber radius unit [withcoord] [withdist] [withhash] [asc/desc] [count n] | 同上,区别是GEORADIUS以给定的经纬度为中心,GEORADIUSBYMEMBER以给定的member为中心 |
GEOHASH K member [member1 ...] | 将二维经纬度转化为一维字符串,字符串越长表明位置越精确,两个字符串越相似表示距离越近 |
ZREM K member | GEO没有提供删除成员的命令,但是因为GEO的底层实现是zset,所以可以借用zrem命令实现对地理位置信息的删除 |
穿透指K对应的数据在数据库中并不存在,每次针对K的请求从缓存中取不到,请求都会到数据库,从而压垮数据库。比如使用id为负数去获取信息,不论是缓存还是数据库都没有,所以每次都会去数据库里查一次,缓存失去意义。
击穿指K对应的数据非常热点,访问非常频繁,当这个K过期的瞬间,此时如果有大量的请求过来,这些请求发现缓存没有数就会从数据库中查询数据并回设到缓存,这个时候大并发的请求可能会瞬间把数据库压垮。
雪崩指缓存服务器重启或缓存中大量数据在某一时间段过期,然后系统涌入大量的查询请求,因为大部分数据在缓存中已经失效,请求渗透到数据库,引起数据库压力造成查询堵塞甚至宕机。
被multi和exec命令包围的的所有命令会一个一个的执行,知道所有的命令都执行完成。该命令是原子执行,其它客户端仍可能会修改正在操作的数据,在输入命令时如果中间有一条命令有语法错误,那么该命令之后所有的命令都不会执行,但之前的命令会被执行不会被回滚。
在事务开启前watch了某个K,在事务提交的时候会检查K的值与watch时候的值是否一致,如果不一致,说明数据被其他客户端修改,那么事务的命令队列不会被执行。
如果使用unwatch命令,那么之前的对所有的K的监控全部取消,哪怕之前检测到watch的K的V发生变化,也不会对事务产生影响。
如果不存在,则设置一个键值对,它是一个原子性的操作
RDB是redis内存到硬盘的快照,用于持久化,有save(同步)、bgsave(异步)和自动配置三种方式触发
命令 | 同步/异步 | 是否阻塞 | 复杂度 | 优点 | 缺点 |
---|---|---|---|---|---|
save | 同步 | 是 | O(N) | 不会消耗额外的内存 | 阻塞客户端的命令 |
bgsave | 异步 | 是(阻塞发生在fork) | O(N) | 不阻塞客户端的命令 | 需要fork,消耗内存 |
AOF是以文件的形式进行持久化,类似于mysql的binlog,它会将每个客户端的每一次写操作都记录到AOF文件中,然后通过载入AOF文件进行数据恢复
策略 | 说明 | 优点 | 缺点 |
---|---|---|---|
always | redis将写命令刷新到缓冲区,然后把每条命令从缓冲区fsync到硬盘的AOF文件 | 不丢失数据 | IO开销大 |
everysec | redis将写命令刷新到缓冲区,然后每秒从缓冲区fsync到硬盘的AOF文件 | 每秒一次fsync | 丢失一秒的数据 |
no | redis将写命令刷新到缓冲区,由OS决定时机执行fsync到硬盘的AOF文件 | 不用管 | 不可控 |
aof_current_size > auto-aof-rewrite-min-zise && (aof_current_size - aof_base_size) / aof_base_size > auto-aof-rewrite-precentage
命令 | 启动优先级 | 体积 | 恢复速度 | 数据安全性 | 轻重 |
---|---|---|---|---|---|
RDB | 低 | 小 | 快 | 丢数据 | 重 |
AOF | 高 | 大 | 慢 | 根据策略决定 | 轻 |
当K expires超时时,怎么处理超时的K,有三种过期策略,redis中同时使用了惰性过期和定期过期两种过期策略
在设置K的过期时间的同时,为该K创建一个定时器,让定时器在K的过期时间来临时对K进行删除
保证内存被尽快释放
K过期时不删除,每次从redis获取K的时候区检查是否过期,若果已经过期,删除该K,返回NULL
删除操作只发生在从数据库取数据的时候,而且只对该K进行操作,所以对CPU的占比较小,而且此时的删除是已经到了非删不可得地步(如果不删除,那么就会获取到过期得K,违背过期策略)
如果大量得K过期后,很长的时间都没有去获取过,那么可能发生内存泄漏(无用的垃圾占用了大量的内存)
每隔一段时间执行一次删除K的操作
根据服务器运行情况合理的设置执行时长和执行频率
1)通过限制删除操作的时长和频率,来减少删除操作对CPU的时间占用(解决定时删除的缺点)
2)定期删除过期K(解决惰性删除的缺点)
在内存友好方面不如定时删除,在CPU时间友好方面不如惰性删除
redis的内存淘汰策略是指在redis的用于缓存的内存不足时,怎么处理需要写入且申请额外空间的数据
策略 | 说明 |
---|---|
noeviction | 当内存不足以容纳新写入的数据时,新写入操作会报错 |
allkeys-lru | 当内存不足以容纳新写入的数据时,在键空间中,移除最近最少使用的K |
allkeys-random | 当内存不足以容纳新写入的数据时,在键空间中,随机移除K |
volatile-lru | 当内存不足以容纳新写入的数据时,在设置了过期时间的键空间中,移除最近最少使用的K |
volatile-random | 当内存不足以容纳新写入的数据时,在是指了过期时间的键空间中,随机移除K |
volatile-ttl | 当内存不足以容纳新写入的数据时,在设置了过期时间的键空间中,优先移除更早过期时间的K |
所有节点间的数据是同步的,一个master,多个slave,其中slave不能写只能读,只有master能读,在部署好slave后,客户端可以向任意的slave发送读请求,而不必总是把读请求发送给master,达到负载均衡的效果,master节点挂掉后,redis就不能对外提供写服务了,因为剩下的slave不能成为master这个缺点影响很大,所以一般生产环境不会单单只用主从复制模式,而是使用sentinel哨兵模式。
如果有多个slave节点并发的向master发送sync命令,企图建立主从关系,只要第二个slave的sync命令发生在master完成bgsave操作之前,第二个slave将受到和第一个slave相同地快照和后续backlog;否则,第二个slave的sync命令会导致master的第二次bgsave。
主从模式中,所有节点间的数据是同步的,当master节点挂掉后,slave节点不能自动选举出一个master出来,此时会导致redis服务的写操作不可用,我们可以通过一个或多个sentinel来处理这种情况,当sentinel发现master节点挂掉后,sentinel就会从slave中重新选举一个master出来。
sentinel是建立在主从模式的基础上的,所以如果只有一个redis节点,那么sentinel则没有任何意义
主从模式配置密码时,sentinel也会同步的将配置信息修改到配置问文件中
当master挂了以后,sentinel会在slave中选择一个作为新的master,并修改它和其它所有slave节点的配置文件,当旧的master重启后,它将不再是master而是以slave的身份接受新的master节点的同步数据
sentinel因为也是一个进程有挂掉的可能,所以一般也会启动多个sentinel形成sentinel集群,一个sentinel或sentinel集群可以管理多个主从redis
当使用sentinel模式的时候,客户端就不需要直接连接redis,而是应该通过sentinel来操作redis服务,由sentinel来提供具体的可提供服务的redis实现
原理 | 机制 |
---|---|
1 2 3 |
是自动发现机制:以10秒一次的频率,向被监视的master发送info命令,根据回复获取master当前信息;以每秒一次的频率向所有redis服务器和sentinel发送PING命令,通过回复判断服务是否在线;以2秒一次的频率向所有被监视的master、slave发送当前sentinel、master的信息。 |
4 | 是检测机制 |
5 6 |
是failover机制 |
7 | 是更新配置机制 |
redis集群中数据是分片存储的,集群的出现是为了解决单机redis容量有限的问题,将redis的数据根据一定的规则分配到多台机器。
cluster可以说是sentinel和主从复制的结合体,通过cluster可以实现主从和master重选操作,cluster配置至少需要3个主节点(每个主节点对应一个从节点,所以需要6个实例)。
因为redis的数据是根据一定的规则分配到cluster不同机器的,当数据量过大时,可以新增机器进行横向扩容,这种模式适合数据量巨大的缓存要求,通常情况下使用sentinel模式就可以了。
redis-cluster通过分区(partition)来提供一定程度的可用性(availability):即使集群中有一部分节点失效或者无法进行通知,cluster也可以继续处理命令的请求。
在redis官方给出的集群方案中,数据分配是根据槽位来进行分配的,每一个数据的键被哈希函数映射到一个槽位,redis-3.0规定一共有214个槽位,槽位数可以进行配置,当用户GET或者PUT一个数据时,首先会查找数据对应的槽位,然后查找对应的节点,最后把数据放到节点内。这样就做到了把数据均匀的分配到cluster中的每个节点上,从而做到了每一个节点的负载均衡。
计算K字符串对应的映射值,redis 采用了crc16 函数然后与0x3FFF取低16位的方法。crc16以及md5都是比较常用的根据K均匀的分配的函数,就这样,用户传入的一个K我们就映射到一个槽上,然后经过gossip 协议,周期性的和集群中的其他节点交换信息,最终整个集群都会知道K在哪一个槽上。
Redis 集群有16384 个哈希槽,每个K通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分HASH槽,举个例子,比如当前集群有3个节点,那么:
范围映射通常选择K本身而非K的函数计算值来作为数据分布的条件,且每个节点存放的K值域是一段连续的范围。
K的值域时通过业务决定的,业务层需要清楚每个区间的范围和redis实例数量,才能完整的描述数据分布,这使业务层的K值域与系统层的实例数耦合,数据分片无法在纯系统层实现,需要和业务层结合。
首先对K进行hash计算,得到值域有限的hash值,再对hash值做范围映射,确定该K对应的业务数据存放的具体实例,这种方式的优势是节点新增或者退出时,涉及的数据迁移量小(变更节点上涉及的数据只需要和相邻的节点发生迁移关系)
redis-cluster重用了sentinel的选举代码,cluster中每个节点都会定期的向其它节点发送PING消息,以此来交换各个节点的状态信息,节点分为三种状态:【在线、疑似下线、下线】
线程模型-单线程,对于命令处理是单线程的,在IO层面同时面向多个客户端并发的提供服务,IO多路复用。
typedef struct redisObject {
/* 4位type表示具体的数据类型,redis中一共有5中数据类型,24足以表示所有的类型 */
unsingned type:4;
/* 4位encoding表示该类型的物理编码方式,同一种数据类型可能有不同的编码方式,目前redis主要有8种编码方式 */
unsingned encoding:2;
/* 表示当内存超限时采用LRU算法清除内存中的对象 */
unsingned lru:REDIS_LRU_BITS;
/* refcount表示对象的引用计数 */
int refcount;
/* ptr指针指向真正的存储结构 */
void *ptr;
} robj;
编码方式 | 说明 | 数据类型 |
---|---|---|
define REDIS_ENCODING_RAW 0 | Raw representation | 【STRING】 |
define REDIS_ENCODING_INT 1 | Encoded as integer | 【STRING】 |
define REDIS_ENCODING_HT 2 | Encoded as hash table | 【HASH & SET】 |
define REDIS_ENCODING_ZIPMAP 3 | Encoded as zipmap | 【】 |
define REDIS_ENCODING_LINKEDLIST 4 | Encoded as regular linked list | 【LIST】 |
define REDIS_ENCODING_ZIPLIST 5 | Encoded as ziplist | 【HASH & LIST & ZSET】 |
define REDIS_ENCODING_INTSET 6 | Encoded as intset | 【SET】 |
define REDIS_ENCODING_SKIPLIST 7 | Encoded as skiplist | 【ZSET】 |
标签:复用 aof 主从模式 tab 出现 文件的 失败 get coding
原文地址:https://www.cnblogs.com/yanwu0527/p/12932558.html