redis学习笔记 | 青训营
1. API篇
keys和dbsize
keys返回redis实例的所有键,时间复杂度为O(n),因此在需要考虑n的规模,在有大量键的环境中禁止使用。
dbsize返回redis实例的键的个数,时间复杂度为O(1),实现方式是通过维护一个内置计数变量。
tips1:对于内置计数变量,在各种数据库中均有使用,例如在MySQL的MyISAM中,而MySQL的InnoDB中则无法使用这种模式,(因为MVCC的存在)。另外值得思考的点是变量的并发安全性,由于Redis是单线程模型,因此兼容性非常好。
tips2:在并发编程中,对于计数功能一般是通过CAS机制实现的。CAS机制:Compare And Swap,即三个变量,目标值,期望旧值,期望新值,只有在目标值=期望旧值的时候,才会执行更新操作。也是乐观锁的实现思想。
Setnx
多个客户端同时执行,只有一个会成功。可以作为分布式锁的实现方式(乐观锁)。
List -> blpop key timeout
在redis中,等待的客户端会加入到等待队列中,等到可以取值的时候,在队列头的客户端先pop到值。
Rename
Rename oldkey newkey,如果newkey已经存在,则会覆盖;可以用renamenx,如果newkey已经存在,则会失败。
tips: rename的时候,会执行del删除oldkey,因此要注意bigkey的del操作的阻塞问题
过期相关
expire key timeout 或者 expireat key timestamp 设置timeout
ttl key 或者 persist key 查看,清除timeout
前缀+p,如pexpire,可以显示毫秒级
tips1:使用set 会直接清除本来的timeout
tips2:使用setex 相比set+expire,少一次网络通讯时间
渐进式遍历
Scan 0, 将遍历一部分键,并返回cursor,不会阻塞
返回的cursor应作为下一次scan的参数
当返回的cursor为0时,说明所有键都被遍历完全。
类似的命令,hscan遍历hash类型,sscan遍历set类型,zscan遍历zset类型。
缺点:
新姿势
A. Getset, 返回原来的值
B. Setrange key offset value,设置value字符串中offset的值,注意是从零开始。
C. Getrange start end,返回[start,end]闭区间的值
D. Linsert key [before|after] target newV 从左往右遍历找到的第一个target的前面或者后面插值
E. Lrange key 从左[0 - N-1]/从右[-1 - -N]
F. Debug sleep 可以模拟节点阻塞故障
2. 单线程和linux的I/O多路复用
2.1 单线程的优势
A. 无线程切换,上下文管理开销
B. 无并发安全问题
C. 与具体多线程性能解耦
2.2 I/O多路复用
多路复用目的:Linux系统结合硬件(DMA), 大幅度减少I/O产生的中断处理开销。
2.2.1 select()系统调用
基于bitmap+置位管理socket fd,有拷贝,需On遍历。
2.2.2 poll()系统调用
基于结构体,只优化了置位开销。
2.2.3 epoll()系统调用
基于结构体,使用了数组重排(无需On遍历)。
2.2.4 零拷贝
A. fd传递
在进程之间,或者内核态和用户态之间,传递fd,避免了具体数据的拷贝。
B. 内存映射
传统读写文件,需要通过系统调用读到内核态缓冲区中,再读到用户态中。通过内存映射,可以直接将内容读到用户态的虚拟内存空间中。
C. 网络传输
通过DMA,发送时,在用户态直接到发送设备;接收时,直接从发送设备到用户态内存。避免用户态到内核态的拷贝。