内存策略
大家知道现代计算机都有虚拟内存这个概念,当redis内存超出物理内存限制的时候,内存数据就会和磁盘发生频繁交换。严重影响性能。我们一般通过配置参数maxmemory来限定内存大小。当内存要超出maxmemory时以下策略来使用。
noeviction 不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。
volatile-lru 尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。
volatile-ttl 跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。
volatile-random 跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。
allkeys-lru 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰。
allkeys-random 跟上面一样,不过淘汰的策略是随机的 key。
实现 LRU 算法除了需要 key/value 字典外,还需要附加一个链表,链表中的元素按照一定的顺序进行排列。当空间满的时候,会踢掉链表尾部的元素。当字典的某个元素被访问时,它在链表中的位置会被移动到表头。所以链表的元素排列顺序就是元素最近被访问的时间顺序。
redis为了实现类lru算法,采用了它给每个 key 增加了一个额外的小字段,这个字段的长度是 24 个 bit,也就是最后一次被访问的时间戳。Redis 执行写操作时,发现内存超出 maxmemory,就会执行一次 LRU 淘汰算法。这个算法也很简单,就是随机采样出 5(可以配置) 个 key,然后淘汰掉最旧的 key,如果淘汰后内存还是超出 maxmemory,那就继续随机采样淘汰,直到内存低于 maxmemory 为止。
在 LRU 模式下,lru 字段存储的是 Redis 时钟server.lruclock,Redis 时钟是一个 24bit 的整数,默认是 Unix 时间戳对 2^24 取模的结果,大约 97 天清零一次。当某个 key 被访问一次,它的对象头的 lru 字段值就会被更新为server.lruclock。
默认 Redis 时钟值每毫秒更新一次,在定时任务serverCron里主动设置。Redis 的很多定时任务都是在serverCron里面完成的,比如大型 hash 表的渐进式迁移、过期 key 的主动淘汰、触发 bgsave、bgaofrewrite 等等。
如果server.lruclock没有折返 (对 2^24 取模),它就是一直递增的,这意味着对象的 LRU 字段不会超过server.lruclock的值。如果超过了,说明server.lruclock折返了。通过这个逻辑就可以精准计算出对象多长时间没有被访问——对象的空闲时间。
LFU策略:表示按最近的访问频率进行淘汰,它比 LRU 更加精准地表示了一个 key 被访问的热度。redis4.0后出来的。
在 LFU 模式下,lru 字段 24 个 bit 用来存储两个值,分别是ldt(last decrement time)和logc(logistic counter)。
idt:16bit存储上次idt的跟新时间。内存回收时,自己被随机取到的话,自己更新的时间。
logc:对象调用次数,存储的是对数次。每次访问更新。
dt 更新的同时也会一同衰减 logc 的值,衰减也有特定的算法。它将现有的 logc 值减去对象的空闲时间 (分钟数) 除以一个衰减系数,默认这个衰减系数lfu_decay_time是 1。如果这个值大于 1,那么就会衰减的比较慢。如果它等于零,那就表示不衰减,它是可以通过配置参数lfu-decay-time进行配置。
为何不从系统里面取时间?
一次系统调用太耗时了。太多更耗时。
安全
redis有些指令是很危险的,比如flushdb 和 flushall 会让 Redis 的所有数据全部清空。Redis 在配置文件中提供了 rename-command 指令用于将某些危险的指令修改成特别的名称,用来避免人为误操作。比如在配置文件的 security 块增加下面的内容:
rename-command keys abckeysabc
如果还想执行 keys 方法,那就不能直接敲 keys 命令了,而需要键入abckeysabc。 如果想完全封杀某条指令,可以将指令 rename 成空串,就无法通过任何字符串指令来执行这条指令了。
我们可以修改端口号,不用默认端口,避免被入侵。
客户端和服务器的访问时直接暴露在公网上传输,为了安全,我们可以使用ssl代理对通信通道进行加密。
spiped原理
程序通过公网访问redis时,数据暴露在外面,我们可以用ssl对数据加密。使其安全传输,spiped就是其中一个代理,其原理是在2端各起一个进程,来对消息进行加密和解密。