1. Redis 数据结构
主要的数据类型:
扩展数据类型
- Pub/Sub 简单的发布/订阅,当订阅的 key 的值有变化的时候,会通知到订阅的客户端,回调。
- HyperLogLog: 基数统计(B 树,bitmap,概率算法(LC,LLC,HLL)),统计一个大的集合(可能出现重复数据)中不同元素的个数。比如网站的 UV,链接访问的 UV,以及做合并的功能,还有留存。
- Geo 地址位置信息
Redis Module : Redis 拓展模块
BloomFilter: 布隆过滤器,快速判断一个元素是否在集合中。
- 就是一个很长的二进制 bit 位的数组,全部初始化为 0.
- K 个 hash 函数,每个 hash 函数会生成一个 hash 值。这个 hash 值对应了二进制 数组的某个点,然后将这个点标记为 1.
- 查询一个数据存在不存在时,需要判断 这 K 个点的位置是否都未为 1.
- 布隆过滤器添加元素
- 将要添加的元素给k个哈希函数
- 得到对应于位数组上的k个位置
- 将这k个位置设为1
- 布隆过滤器查询元素
- 将要查询的元素给k个哈希函数
- 得到对应于位数组上的k个位置
- 如果k个位置有一个为0,则肯定不在集合中
- 如果k个位置全部为1,则可能在集合中
- 优点: 是占用空间小,效率高。
- 缺点: 有误判,不允许删除。如果需要删除,可以CBF,每一位是一个 counter,不再是0和1两种结果。
RedisSearch
Redis-ML,
2. Redis 分布式锁
- setnx抢锁,然后设置一个 过期时间。不能先 set 抢锁,再 expire,必须保证原子性。
- spring-data-redis:2.1版本后,使用 setIfAbsent(K key, V value, long timeout, TimeUnit unit) 方法来实现。
3. Redis 查找指定格式的 key
- 如果使用 keys ,但是会卡住 redis,因为 redis 是单线程的。所以可以用 scan,但是会有重复,需要客户端做一次去重复。
4. Redis 做异步队列
- 一般用 list 作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,适当的 sleep 一定的时间再重试,如果不用 sleep。可以用 blpop 命令,如果没有消息,会一直阻塞到消息来为止。
- 通过 pub/sub 订阅者模式 来做一次生产,多次消费,可以实现 1:N 的消息队列。pub/sub 的缺点是,在消费者下线过后,生产的消息会丢失,如果需要保证不丢失,需要使用 MQ.
- redis 实现延时队列,用时间戳做 score,消息内容做 member, 然后通过 ZADD 添加消息,消费者用 zrangebyscore 指令获取 N 秒之前的数据轮询处理。不过不建议,太占用内容。队列还是建议使用 MQ, Kafka
5. key 的过期时间
- 如果有大量的 key 在同一个时间过期,防止 redis 暂时的卡顿,在时间上面加一个随机值,使得过期时间分散一些。
6. Redis 持久化
- http://oldblog.antirez.com/post/redis-persistence-demystified.html
- 持久化方式:
- RDB 指定间隔时间的某个时间点的快照。
- AOF 持久化操作日志。当 redis 重启的时候,需要根据 AOF 的 log 文件来重构数据。AOF 日志文件是redis 的自定义格式。当 AOF文件太大,redis 会重写该日志文件,减少命令数,但是结果一致。比如多次累加一个 key 100次。aof 就会有100条语句,BGREWRITEAOF会精简命令。
- 可以禁用 redis 的持久化,只要我们想让我们的数据只在 redis 运行时存在。
- 可以同时使用 AOF 和 RDB 来持久化 redis 中的数据。需要注意的是,此时,Redis 重启时,AOF 的日志文件会被用来重构 redis 中的数据,以此来保证数据的完整性。
- RDB 做全量持久化,AOF 做增量持久化。RDB 每次消耗的时间长,down 机时,会丢失两次持久化之间的数据。所以,需要配合 AOF 来使用。Redis 重启时,先用 RDB 持久化的文件重构内存,然后使用 AOF 回放最近的操作指令来实现完整恢复重启之前的状态。
- 对于突然断电的结果,取决于 AOF 刷新日志到磁盘的时间间隔 sync。建议是 1s 刷新一次。
- RDB 的原理,就是 fork & COW. fork 过后,子进程和父进程共享数据段,此时,可以看做没有占用额外的内存开销。当父进程的数据有修改时,才会复制一份到子进程保存。所以,只有在极限情况,所有的父进程数据有修改,及其的物理内存使用率才会是 50%。
- RDB 的优点是重启快,缺点是会丢失数据,备份一次的时间长。AOF 的优点是可以做到不丢失数据或者丢失很少的数据,但是重启很慢,因为需要重新根据日志来构建 redis 数据。所以往往是 RDB 和 AOF 搭配使用。
7. Pipline
- Pipline 的好处是可以将多次 IO 减少为 1次。前提是这些之类之间没有因果相关性
8. Redis 的同步机制
- Redis 可以使用主从同步,从从同步。
- 启动时,做第一次同步,主节点做一次 rdb,同时将后续修改操作放入 buffer,待 rdb 完成后。将 rdb 文件全量同步到 从节点,从节点接受完成后讲 rdb 镜像加载到内存。加载完成后,再通知主节点讲期间修改的 缓存 buffer 发送过来。
- 以上是第一次启动时候的同步,当机器都启动完成后,后面通过 AOF 做同步就是近乎实时。
9. Redis 集群
Redis-sentinal 是着眼于高可用性。在 master down 机时,能在 slave 中选举一个新的 master,继续提供服务。
Redis-cluster 着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。
redis 集群的 键分布模型,
- 采用的 一种 hash slot(hash槽) 的 sharding 方式,而不是一致性 hash
- Redis 集群的键空间被分割为 16384 个槽(slot), 集群的最大节点数量也是 16384 个,推荐的最大节点数量为 1000 个左右。
- 每个主节点都负责处理 16384 个槽中的一部分。
- 使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽
- 删除某个节点:只需要将删除的节点中的槽移动到其它的节点,然后再移除空白槽需要删除的节点。
- 增加一个节点:只需要将当前所有节点中的某些槽移动到新的节点。
因为将一个 hash 槽从一个节点移动到另一个节点,不会造成节点堵塞,所以无论是添加还是移除已经存在的节点,又或者改变某个节点包含的 hash 槽数,不会造成集群下线。
Redis 集群不保证数据的强一致性(strong consistency): 在特定条件下, Redis 集群可能会丢失已经被执行过的写命令。
10. Redis 集群搭建
11. 参考
https://zhuanlan.zhihu.com/p/32540678
http://blog.codinglabs.org/articles/algorithms-for-cardinality-estimation-part-i.html
https://bindog.github.io/blog/2015/02/14/cardinality-counting/
https://blog.csdn.net/firenet1/article/details/77247649