redis 安装使用 🔗
redis 安装
wget https://download.redis.io/releases/redis-6.2.4.tar.gz
tar -zvxf redis-6.2.4
mv ~/redis-6.2.4 /usr/local/redis
cd /usr/local/redis
make 编译
make PREFIX=/usr/local/redis install 安装
加prefix指定可执行文件的目录。
不加的话可执行文件会放到/usr/local/bin目录中,
库文件在/usr/local/lib中。
redis 使用
在/usr/local/redis目录下,
/bin/redis-server& ./redis.conf
or /bin/redis-server ./redis.conf
redis-cli -p 6379
redis 高可用 🔗

支持的数据结构 🔗
支持的value类型: 字符串,hash,列表,集合,有序集合
- redis未直接使用上述数据结构, 而是redisObject结构进行封装。
- redisObject结构体: type, encoding, prt, refcount, lru...
- 键对象, 均为字符串对象
- 值对象
- 1字符串对象
- 2列表对象(ziplist, linkedlist)
- 3哈希对象(ziplist, hashtable)
- 4集合对象(intset, hashtable)
- 5有序集合对象(ziplist, skiplist)
hash表的实现方式 🔗
hash表的存储结构: array[ListNode; n]
扩容方式:设计到内存迁移,但不能阻塞线程太长时间。采用了 渐进式 rehash + 定时 rehash。
渐进式rehash:在每次crud时判断hash表如果处于rehash的状态, 则rehash当前的一个节点。
定时rehash:添加时间事件进行迁移。
有序集合的实现方式 🔗
待排集合的大小影响数据结构的选择。
当集合的大小超过可配阈值时,选择skiplist: 一种多层级的链表, 节点有多个指向后序节点的指针。
事件(IO事件 + 时间事件) 🔗
io事件是redis正常的业务请求处理。 时间事件是redis内部为了维持正常状态的需要。
事件驱动框架 🔗
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);
}
}
int aeProcessEvents(aeEventLoop *eventLoop, int flags)
if (eventLoop->beforesleep != NULL && flags & AE_CALL_BEFORE_SLEEP)
eventLoop->beforesleep(eventLoop);
numevents = aeApiPoll(eventLoop, tvp);
/* After sleep callback. */
if (eventLoop->aftersleep != NULL && flags & AE_CALL_AFTER_SLEEP)
eventLoop->aftersleep(eventLoop);
/* 处理io事件 */
for (j = 0; j < numevents; j++) {...}
/* 处理时间事件(del key, rehash..) */
if (flags & AE_TIME_EVENTS)
processed += processTimeEvents(eventLoop);
return processed; /* return the number of processed file/time events */
}
时间事件 (定时事件, 周期性事件) 🔗
- 更新db的统计信息
- 清理过期key, rehash
- 关闭和清理无效的客户端
- 尝试AOF RDB
- 主从同步
io多路复用 🔗
epoll 实例内部维护了两个结构。
分别是记录要监听的文件描述符(rb_tree)和已经就绪的文件描述符(ready_queue)。不用select, poll去遍历文件描述符集合查看是否ready。
Reactor模式
过期键删除 🔗
- 定时删除, 创建定时器添加到时间事件的链表中
- 懒性删除策略(db.c/expireIfNeeded) get key -> expireIfNeeded -> 删除key 并返回nil
- 定期删除策略, 创建时间事件 (redis.c/activeExpireCycle)
- save 生成rdb文件, 不会保存过期键
持久化 🔗
RDB:
- save (阻塞redis服务进程,直到RDB文件生成完毕)
- bgsave 创建子进程来创建全局快照RDB文件
AOF持久化:
- 配置appendfsync
- always 每次写都fsync
- everysec 每秒fsync
- no 由os定
AOF 重写(减少AOF文件的大小), bgrewriteaof创建子进程去执行。 redis中SIGUSR1信号关闭子进程的aof,rdb子进程。
AOF rewrite重写的过程:
- 创建新AOF文件,通过读当前db的键的value用最新的kv记录到新AOF文件中。
- 子进程在AOF重写过程中, 发生的write操作,主服务进程会写到AOF重写缓冲区,等子进程结束后,父进程收到信号,将AOF重写缓冲区的内容append到AOF文件中,完成AOF文件的后台重写。
事务与lua 🔗
redis单线程处理事件,所以事务执行是串行的,所以满足隔离性。
multi, exec, watch。 multi之后 的命令入队列, exec执行队列命令。
- multi之后 redisclient的flags事务标示打开, 请求的命令入队列(入队失败,不会执行事务)
- exec执行队列命令(执行失败,事务继续执行)。
- watch的key被修改后,redisClient的REDIS_DIRTY_CAS会打开, exec时会取消执行
redis实现令牌桶限流 🔗
在redis中维护List对戏那个,作为令牌桶。
生产者每隔interval秒放令牌桶中放r个令牌, lpush。
消费者brpop从list中获取令牌。
redis 和 mysql 如何保证数据一致性 🔗
在满足实时性的条件下,只有最终一致性方案。