Redis随手记(一)基础与应用
date
Feb 13, 2021
slug
redis-intro
status
Published
tags
Programming
Redis
summary
type
Page
Year
2021
Redis的数据类型
- String
- List(列表)
- 相当于Java中的LinkedList
- 大多数情况下使用右进左出的队列
- 右进右出的栈比较少用
- 快速列表
- 当数据比较少的时候,使用ziplist
- ziplist使用的是一块连续的内存
- 而普通链表使用的是不连续内存, 同时队内元素需要附加指针空间指向下一元素
- 当数据较多时,使用quicklist
- quicklist就是多个ziplist按照普通链表的方式组合起来
- hash(字典)
- 与Java的HashMap一样, 使用closed hashing
- 不同的是Java rehash的时候使用一次性全部rehash的策略
- 而Redis为了不阻塞服务使用渐进式rehash
- 渐进式rehash会在rehash的同时保留新旧两个hash结构
- 查询时会同时查询两个hash结构
- 然后在后续的定时任务以及hash操作指令中将旧hash的内容迁移到新hash里
- 当全部迁移完成后回收旧hash
- set
- 相当于Java里的HashSet
- zset(有序列表)
- 每一个value都会有一个score用以排序
- 使用场景可以为:value(粉丝用户ID)-score(关注时间), value(学生)-score(成绩)
- zset内部的排序功能是通过跳跃列表数据结构来实现的
- list、set、hash、zset通用规则
- create if not exist
- drop if no elements
分布式锁
- 使用 setnx 指令来创建key, 用 expire来防止死锁
- set lock:codehole true ex 5 nx
- 使用setnx和expire组合在一起的原子指令
- 其中"lock:codehole"是key, "true"是value, "ex" -> expire, "nx" -> setnx
- 分布式锁不能解决超时问题, 如果在加锁和释放锁之间的逻辑执行得太长, 以至于超出了锁的超时限制, 就会出现问题
- 因此Redis分布式锁不要用于较长时间的任务
延时队列
- redis的list数据结构常用作异步消息队列使用
- 它可以支持多个producer和consumer并发进出消息, 每个consumer拿到的消息都是不同的列表元素
- 使用阻塞读
- 当队列空了, consumer会陷入pop的死循环
- 这时使用 blpop/brpop
- 阻塞读在队列没有数据的时候立刻进入休眠状态, 一旦数据来时则立刻醒过来
- 锁冲突处理
- 客户端在处理请求时加锁没加成功该怎么办
- 直接抛出特定类型的异常, 通知用户稍后重试
- sleep一会儿, 然后重试
- sleep会阻塞当前的消息处理线程, 会导致队列后续信息处理出现延迟
- 不建议队列消息比较多时使用
- 将请求转移到延时队列, 过一会儿再尝试
- 比较适合异步消息处理, 将当前冲突请求扔到另一个队列延后处理以避开冲突
- 延时队列的实现
- 可以通过zset实现
- 将消息序列化成一个字符串作为zset的value, 消息的expire时间作为score, 然后用多个线程轮询zset获取到期的任务进行处理
- 多个线程保障了可用性, 但是需要注意并发
- 位图
- HyperLogLog
- Bloom Filter
- Geohash