1、redis的数据类型
有5种,String、Map、List、Set、SortedSet
1.1 String
1.1.1 String类型基本介绍
字符串类型是redis最基础的数据结构,首先键是字符串类型,而且其他几种结构都是在字符串类型基础上构建的,
所以字符串类型能为其他四种数据结构的学习尊定基础。
字符串类型实际上可以是字符串
(简单的字符串、复杂的字符串(xml、json)、数字(整数、浮点数)、二进制(图片、音频、视频)),
但最大不能超过512M。
1.1.2 常见命令
字符串类型是Redis的最基本类型,它可以存储任何形式的字符串。其它的四种类型都是字符串类型的不同形式。
最基本的命令:GET、SET 语法:GET key,SET key value value如果有空格需要双引号以示区分
整数递增:INCR 语法:INCR key 默认值为0,所以首先执行命令得到 1 ,不是整型提示错误
增加指定的整数:INCRBY 语法:INCRBY key increment
整数递减:DECR 语法:DECR key 默认值为0,所以首先执行命令得到 -1,不是整型提示错误
减少指定的整数:DECRBY 语法:DECRBY key increment
增加指定浮点数:INCRBYFLOAT 语法:INCRBYFLOAT key increment 与INCR命令类似,只不过可以递增一个双精度浮点数
向尾部追加值:APPEND 语法:APPEND key value redis客户端并不是输出追加后的字符串,而是输出字符串总长度
获取字符串长度:STRLEN 语法:STRLEN key 如果键不存在返回0,注意如果有中文时,一个中文长度是3,redis是使用UTF-8编码中文的
获取多个键值:MGET 语法:MGET key [key …] 例如:MGET key1 key2
设置多个键值:MSET 语法:MSET key value [key value …] 例如:MSET key1 1 key2 “hello redis”
二进制指定位置值:GETBIT 语法:GETBIT key offset 例如:GETBIT key1 2 ,key1为hello 返回 1,返回的值只有0或1,
当key不存在或超出实际长度时为0
设置二进制位置值:SETBIT 语法:SETBIT key offset value ,返回该位置的旧值
二进制是1的个数:BITCOUNT 语法:BITCOUNT key [start end] ,start 、end为开始和结束字节
位运算:BITOP 语法:BITOP operation destkey key [key …] ,operation支持AND、OR、XOR、NOT
偏移:BITPOS 语法:BITPOS key bit [start] [end]
1.1.3 使用场景
-
缓存功能:字符串最经典的使用场景,redis最为缓存层,Mysql作为储存层,绝大部分请求数据都是redis中获取,由于redis具有支撑高并发特性,所以缓存通常能起到加速读写和降低 后端压力的作用。
-
计数器:许多运用都会使用redis作为计数的基础工具,他可以实现快速计数、查询缓存的功能,同时数据可以一步落地到其他的数据源。如:视频播放数系统就是使用redis作为视频播放数计数的基础组件。
-
共享session:出于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器上,用户刷新一次访问可能会需要重新登录,为避免这个问题可以用redis将用户session集中管理,在这种模式下只要保证redis的高可用和扩展性的,每次获取用户更新或查询登录信息都直接从redis中集中获取。
-
限速:处于安全考虑,每次进行登录时让用户输入手机验证码,为了短信接口不被频繁访问,会限制用户每分钟获取验证码的频率。
1.2 哈希
1.2.1 哈希类型基本介绍
hash 类型很像一个关系型数据库的数据表,hash 的 Key 是一个唯一值,Value 部分是一个 hashmap 的结构。
在redis中哈希类型是指键本身又是一种键值对结构,如 value={{field1,value1},…{fieldN,valueN}}
1.2.2 哈希类型常用命令
设置单个:HSET 语法:HSET key field value,不存在时返回1,存在时返回0,没有更新和插入之分
设置多个:HMSET 语法:HMSET key field value [field value …]
读取单个:HGET 语法:HGET key field,不存在是返回nil
读取多个:HMGET 语法:HMGET key field [field …]
读取全部:HGETALL 语法:HGETALL key,返回时字段和字段值的列表
判断字段是否存在:HEXISTS 语法:HEXISTS key field,存在返回1 ,不存在返回0
字段不存在时赋值:HSETNX 语法:HSETNX key field value,与hset命令不同,hsetnx是键不存在时设置值
增加数字:HINCRBY 语法:HINCRBY key field increment ,返回增加后的数,不是整数时会提示错误
删除字段:HDEL 语法:HDEL key field [field …] ,返回被删除字段的个数
只获取字段名:HKEYS 语法:HKEYS key ,返回键的所有字段名
只获取字段值:HVALS 语法:HVALS key ,返回键的所有字段值
字段数量:HLEN 语法:HLEN key ,返回字段总数
1.2.3 使用场景
哈希结构相对于字符串序列化缓存信息更加直观,并且在更新操作上更加便捷。
所以常常用于用户信息等管理,但是哈希类型和关系型数据库有所不同,哈希类型是稀疏的,而关系型数据库是完全结构化的,关系型数据库可以做复杂的关系查询,而redis去模拟关系型复杂查询
开发困难,维护成本高。
1.3 列表(list)
1.3.1 列表类型基本介绍
列表类型是用来储存多个有序的字符串,列表中的每个字符串成为元素(element),一个列表最多可以储存
2的32次方-1个元素,在redis中,可以队列表两端插入(pubsh)和弹出(pop),还可以获取指定范围的元素
列表、获取指定索引下表的元素等,列表是一种比较灵活的数据结构,它可以充当栈和队列的角色,
在实际开发中有很多应用场景。
优点:
1. 列表的元素是有序的,这就意味着可以通过索引下标获取某个或某个范围内的元素列表。
2. 列表内的元素是可以重复的。
1.3.2 列表类型常用命令
内部使用双向链表实现,所以获取越接近两端的元素速度越快,但通过索引访问时会比较慢
添加左边元素:LPUSH 语法:LPUSH key value [value ...] ,返回添加后的列表元素的总个数
添加右边元素:RPUSH 语法:RPUSH key value [value ...] ,返回添加后的列表元素的总个数
移除左边第一个元素:LPOP 语法:LPOP key ,返回被移除的元素值
移除右边第一个元素:RPOP 语法:RPOP key ,返回被移除的元素值
列表元素个数:LLEN 语法:LLEN key, 不存在时返回0,redis是直接读取现成的值,并不是统计个数
获取列表片段:LRANGE 语法:LRANGE key start stop,如果start比stop靠后时返回空列表,0 -1 返回整个列表
正数时:start 开始索引值,stop结束索引值(索引从0开始)
负数时:例如 lrange num -2 -1,-2表示最右边第二个,-1表示最右边第一个,
删除指定值:LREM 语法:LREM key count value,返回被删除的个数
count>0,从左边开始删除前count个值为value的元素
count<0,从右边开始删除前|count|个值为value的元素
count=0,删除所有值为value的元素
索引元素值:LINDEX 语法:LINDEX key index ,返回索引的元素值,-1表示从最右边的第一位
设置元素值:LSET 语法:LSET key index value
保留列表片段:LTRIM 语法:LTRIM key start stop,start、top 参考lrange命令
一个列表转移另一个列表:RPOPLPUSH 语法:RPOPLPUSH source desctination ,从source列表转移到desctination列表,
该命令分两步看,首先source列表RPOP右移除,再desctination列表LPUSH
1.3.3 应用场景
消息队列: redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端是用lupsh从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞时的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性
使用列表技巧:
lpush+lpop=Stack(栈)
lpush+rpop=Queue(队列)
lpush+ltrim=Capped Collection(有限集合)
lpush+brpop=Message Queue(消息队列)
1.4 集合(set)
1.4.1 集合类型基本介绍
集合类型也是用来保存多个字符串的元素,但和列表不同的是集合中不允许有重复的元素,并且集合中的元素是无序的,不能通过索引下标获取元素,redis除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集,并合理的使用好集合类型,能在实际开发中解决很多实际问题。
1.4.2 集合类型常用命令
集合类型值具有唯一性,常用操作是向集合添加、删除、判断某个值是否存在,集合内部是使用值为空的散列表实现的。
添加元素:SADD 语法:SADD key member [member ...] ,向一个集合添加一个或多个元素,因为集合的唯一性,所以添加相同值时会被忽略。
返回成功添加元素的数量。
删除元素:SREM 语法:SREM key member [member ...] 删除集合中一个或多个元素,返回成功删除的个数。
获取全部元素:SMEMBERS 语法:SMEMBERS key ,返回集合全部元素
值是否存在:SISMEMBER 语法:SISMEMBER key member ,如果存在返回1,不存在返回0
差运算:SDIFF 语法:SDIFF key [key ...] ,例如:集合A和集合B,差集表示A-B,在A里有的元素B里没有,返回差集合;多个集合(A-B)-C
交运算:SINTER 语法:SINTER key [key ...],返回交集集合,每个集合都有的元素
并运算:SUNION 语法:SUNION key [key ...],返回并集集合,所有集合的元素
集合元素个数:SCARD 语法:SCARD key ,返回集合元素个数
集合运算后存储结果 语法:SDIFFSTROE destination key [key ...] ,差运算并存储到destination新集合中
SINTERSTROE destination key [key ...],交运算并存储到destination新集合中
SUNIONSTROE destination key [key ...],并运算并存储到destination新集合中
随机获取元素:SRANDMEMGER 语法:SRANDMEMBER key [count],根据count不同有不同结果,count大于元素总数时返回全部元素
count>0 ,返回集合中count不重复的元素
count<0,返回集合中count的绝对值个元素,但元素可能会重复
弹出元素:SPOP 语法:SPOP key [count] ,因为集合是无序的,所以spop会随机弹出一个元素
1.4.3 使用场景
标签(tag):集合类型比较典型的使用场景,如一个用户对娱乐、体育比较感兴趣,另一个可能对新闻感兴趣,这些兴趣就是标签,有了这些数据就可以得到同一标签的人,以及用户的共同爱好的标签,这些数据对于用户体验以及增强用户粘度比较重要。
(用户和标签的关系维护应该放在一个事物内执行,防止部分命令失败造成数据不一致)
sadd=tagging(标签)
spop/srandmember=random item(生成随机数,比如抽奖)
sadd+sinter=social Graph(社交需求)
1.5 有序集合
1.5.1 基本介绍
有序集合和集合有着必然的联系,他保留了集合不能有重复成员的特性,但不同得是,有序集合中的元素是可以排序的,但是它和列表的使用索引下标作为排序依据不同的是,它给每个元素设置一个分数,作为排序的依据。
(有序集合中的元素不可以重复,但是csore可以重复,就和一个班里的同学学号不能重复,但考试成绩可以相同)。
1.5.2 常用命令
添加集合元素:ZADD 语法:ZADD key [NX|XX] [CH] [INCR] score member [score member ...],不存在添加,存在更新。
获取元素分数:ZSCORE 语法:ZSCORE key member ,返回元素成员的score 分数
元素小到大:ZRANGE 语法:ZRANGE key start top [WITHSCORES] ,参考LRANGE ,加上withscores 返回带元素,即元素,分数
当分数一样时,按元素排序
元素大到小:ZREVRANGE 语法:ZREVRANGE key start [WITHSCORES] ,与zrange区别在于zrevrange是从大到小排序
指定分数范围元素:ZRANGEBYSCORE 语法:ZRANGEBYSCORE key min max [WITHSCORE] [LIMIT offest count]
返回从小到大的在min和max之间的元素,( 符号表示不包含,例如:80-100,(80 100,
withscore返回带分数
limit offest count 向左偏移offest个元素,并获取前count个元素
指定分数范围元素:ZREVRANGESCORE 语法:ZREVRANGEBYSCORE key max min [WITHSCORE] [LIMIT offest count]
与zrangebyscore类似,只不过该命令是从大到小排序的。
增加分数:ZINCRBY 语法:ZINCRBY key increment member ,注意是增加分数,返回增加后的分数;如果成员不存在,则添加一个为0的成员。
1.5.3 使用场景
排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜,榜单维护可能是多方面:
按照时间、按照播放量、按照获得的赞数等。
2、redis的一致性哈希算法实现
一致性哈希算法基础:https://blog.csdn.net/zhaohong_bo/article/details/90519123
3、redis集群部署方案
Redis3.0版本之前,只能通过Redis Sentinel(哨兵)来实现高可用 ( HA ),从3.0版本之后,又提供了Redis Cluster,它的主要用途是实现数据分片(Data Sharding),不过同样可以实现HA。
在Redis Sentinel模式中,每个节点需要保存全量数据,冗余比较多,而在Redis Cluster模式中,每个分片只需要保存一部分的数据,对于内存数据库来说,还是要尽量的减少冗余,内存实在是太贵了。
Redis Cluster的具体实现细节是采用了Hash槽的概念,集群会预先分配16384个槽,并将这些槽分配给具体的服务节点,通过对Key进行CRC16(key)%16384运算得到对应的槽是哪一个,从而将读写操作转发到该槽所对应的服务节点。当有新的节点加入或者移除的时候,再来迁移这些槽以及其对应的数据。在这种设计之下,我们就可以很方便的进行动态扩容或缩容,个人也比较倾向于这种集群模式。
当然,关于高可用的实现方案,也可以将这两种模式结合起来使用,不过比较复杂,不太推荐。
拓展: https://www.jianshu.com/p/53a9f98976a7
redis cluster:
https://www.cnblogs.com/liyasong/p/redis_jiqun.html?utm_source=itdadao&utm_medium=referral
https://segmentfault.com/p/1210000009708869/read
http://wemedia.ifeng.com/91301018/wemedia.shtml
https://www.cnblogs.com/mengchunchen/p/10059436.html
4、redis的Sentinel(哨兵)模式原理
https://segmentfault.com/a/1190000018478725
-
Sentinel集群通过配置文件发现master,启动时会监控master;
-
向master发送info命令,获取其所有slave节点;
-
Sentinel集群向Redis主从服务器发送hello信息(心跳),包括Sentinel本身的ip、端口、id等内容,以此来向其他Sentinel宣告自己的存在;
-
Sentinel集群通过订阅接收其他Sentinel发送的hello信息,以此来发现监视同一个主服务器的其他Sentinel;集群之间会互相创建命令连接用于通信,因为已经有主从服务器作为发送和接收hello信息的中介,Sentinel之间不会创建订阅连接;
-
Sentinel集群使用ping命令来检测实例的状态,如果在指定的时间内(down-after-milliseconds)没有回复或则返回错误的回复,那么该实例被判为下线;
-
当failover主备切换被触发后,并不会马上进行,还需要Sentinel中的大多数sentinel授权后才可以进行failover,即进行failover的Sentinel会去获得指定quorum个的Sentinel的授权,成功后进入ODOWN状态。如在5个Sentinel中配置了2个quorum,等到2个Sentinel认为master死了就执行failover。
-
Sentinel向选为master的slave发送 SLAVEOF NO ONE 命令,选择slave的条件是Sentinel首先会根据slaves的优先级来进行排序,优先级越小排名越靠前。如果优先级相同,则查看复制的下标,哪个从master接收的复制数据多,哪个就靠前。如果优先级和下标都相同,就选择进程ID较小的。
-
Sentinel被授权后,它将会获得宕掉的master的一份最新配置版本号(config-epoch),当failover执行结束以后,这个版本号将会被用于最新的配置,通过广播形式通知其它sentinel,其它的sentinel则更新对应master的配置。