分布式Redis缓存

凛冬王昭君 2020年03月03日 300次浏览

1 什么是Redis

Redis是由意大利人Salvatore Sanfilippo(网名:antirez)开发的一款内存高速缓存数据库。Redis全称为:Remote Dictionary Server(远程数据服务),该软件使用C语言编写,Redis是一个key-value存储系统,它支持丰富的数据类型,如:string、list、set、zset(sorted set)、hash。
Redis采用的是基于内存的采用的是单进程单线程模型的KV数据库,由C语言编写。官方提供的数据是可以达到100000+的qps

2 Redis应用场景

  • 令牌(Token)生成
  • 短信验证码
  • 发布订阅
    相当于消息系统,ActiveMQ,RocketMQ等工具类似,但是个人觉得简单用一下还行,如果对于数据一致性要求高的话还是用RocketMQ等专业系统。
    由于redis把数据添加到队列是返回添加元素在队列的第几位,所以可以做判断用户是第几个访问这种业务
    队列不仅可以把并发请求变成串行,并且还可以做队列或者栈使用
  • 分布式锁
    验证前端的重复请求(可以自由扩展类似情况),可以通过redis进行过滤:每次请求将request Ip、参数、接口等hash作为key存储redis(幂等性请求),设置多长时间有效期,然后下次请求过来的时候先在redis中检索有没有这个key,进而验证是不是一定时间内过来的重复提交
    秒杀系统,基于redis是单线程特征,防止出现数据库“爆破”
    全局增量ID生成,类似“秒杀”
  • 计数器
    诸如统计点击数等应用。由于单线程,可以避免并发问题,保证不会出错,而且100%毫秒级性能!
  • 缓存(热点数据)
    热点数据(经常会被查询,但是不经常被修改或者删除的数据),首选是使用redis缓存,毕竟强大到冒泡的QPS和极强的稳定性不是所有类似工具都有的,而且相比于memcached还提供了丰富的数据类型可以使用,另外,内存中的数据也提供了AOF和RDB等持久化机制可以选择,要冷、热的还是忽冷忽热的都可选。
    结合具体应用需要注意一下:很多人用spring的AOP来构建redis缓存的自动生产和清除,过程可能如下:
    Select 数据库前查询redis,有的话使用redis数据,放弃select 数据库,没有的话,select 数据库,然后将数据插入redis
    update或者delete数据库钱,查询redis是否存在该数据,存在的话先删除redis中数据,然后再update或者delete数据库中的数据
    上面这种操作,如果并发量很小的情况下基本没问题,但是高并发的情况请注意下面场景:
    为了update先删掉了redis中的该数据,这时候另一个线程执行查询,发现redis中没有,瞬间执行了查询SQL,并且插入到redis中一条数据,回到刚才那个update语句,这个悲催的线程压根不知道刚才那个该死的select线程犯了一个弥天大错!于是这个redis中的错误数据就永远的存在了下去,直到下一个update或者delete。

3 Linux环境下安装Redis

我默认使用集群安装,参考:Docker Compose部署Redis Cluster

4 Redis基本数据类型

Redis目前支持5种数据类型,分别是:
String(字符串)
List(列表)
Hash(字典)
Set(集合)
Sorted Set(有序集合)
下面就分别介绍这五种数据类型及其相应的操作命令。

4.1 String(字符串)

String是简单的 key-value 键值对,value 不仅可以是 String,也可以是数字。String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。
String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。
应用场景:
String是最常用的一种数据类型,普通的key/value存储都可以归为此类,这里就不所做解释了。

redis 127.0.0.1:6379> SET mykey "redis" 
OK 
redis 127.0.0.1:6379> GET mykey 
"redis"

4.2 List(列表)

Redis列表是简单的字符串列表,可以类比到C++中的std::list,简单的说就是一个链表或者说是一个队列。可以从头部或尾部向Redis列表添加元素。列表的最大长度为2^32 - 1,也即每个列表支持超过40亿个元素。

Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。

应用场景
Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表、粉丝列表等都可以用Redis的list结构来实现,再比如有的应用使用Redis的list类型实现一个简单的轻量级消息队列,生产者push,消费者pop/bpop。

redis 127.0.0.1:6379> LPUSH runoobkey redis
(integer) 1
redis 127.0.0.1:6379> LPUSH runoobkey mongodb
(integer) 2
redis 127.0.0.1:6379> LPUSH runoobkey mysql
(integer) 3
redis 127.0.0.1:6379> LRANGE runoobkey 0 10
1) "mysql"
2) "mongodb"
3) "redis"

4.3 Hash(字典)

Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。

127.0.0.1:6379>  HMSET runoobkey name "redis tutorial" 
127.0.0.1:6379>  HGETALL runoobkey
1) "name"
2) "redis tutorial"
3) "description"
4) "redis basic commands for caching"
5) "likes"
6) "20"
7) "visitors"
8) "23000"

4.4 Set(集合)

Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

redis 127.0.0.1:6379> SADD runoobkey redis
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mongodb
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mysql
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mysql
(integer) 0
redis 127.0.0.1:6379> SMEMBERS runoobkey
1) "mysql"
2) "mongodb"
3) "redis"

4.5 Sorted Set(有序集合)

Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

redis 127.0.0.1:6379> ZADD runoobkey 1 redis
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 2 mongodb
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql
(integer) 0
redis 127.0.0.1:6379> ZADD runoobkey 4 mysql
(integer) 0
redis 127.0.0.1:6379> ZRANGE runoobkey 0 10 WITHSCORES
1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "4"

5 Redis主从复制

概述

  • redis的复制功能是支持多个数据库之间的数据同步。一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操作,当发生写操作的时候自动将数据同步到从数据库,而从数据库一般是只读的,并接收主数据库同步过来的数据,一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库。
  • 通过redis的复制功能可以很好的实现数据库的读写分离,提高服务器的负载能力。主数据库主要进行写操作,而从数据库负责读操作。

RedisCopy.jpg

6 Redis哨兵机制

Redis的哨兵(sentinel) 系统用于管理多个 Redis 服务器,该系统执行以下三个任务:

  • 监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。
  • 提醒(Notification):当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
  • 自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master; 当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。

RedisSentinel.jpg

7 Redis集群Cluster

请看以下文章:Redis Cluster