[转帖]Redis性能调优万字总结,面试必问!

redis,性能,总结,面试 · 浏览次数 : 0

小编点评

**内存块的使用次数,回收时,按照访问次数排序** * 当缓存不足时,将使用频率最低的内存释放。 * 使用频率最低的内存块,可以减少内存占用和提高性能。 * 当缓存中没有数据时,会从数据库中获取数据。 * 当内存足够时,会将使用频率最高的内存块分配给新数据。 **使用Lazy free特性(Redis4.0新增)删除大键值对比较耗时,造成主线程的阻塞** * 在使用Lazy free特性删除大键值对时,如果主线程阻塞,会导致缓存失效,影响性能。 * 为了避免阻塞主线程,可以使用异步执行删除操作。 **使用其他优化技术** * 使用Redis分布式架构,可以提高读写性能。 * 使用热点数据缓存,可以减少数据库访问次数。 * 使用Bloom过滤器,可以快速判断数据是否存在。 * 使用锁机制,可以保证数据的并发性。 **使用Slowlog优化耗时命令** * Slowlog可以记录高耗时的Redis命令,方便调试。 * 通过设置慢查询参数,可以控制命令执行的效率。 **其他优化** * 使用Redis连接池,可以减少网络传输次数。 * 使用分布式架构,可以提高读写性能。 * 使用Bloom过滤器,可以快速判断数据是否存在。 * 使用锁机制,可以保证数据的并发性。

正文

https://zhuanlan.zhihu.com/p/541745804

 

于哥你好,最近面试挺多的,尤其是在问到java面试题,Redis被问的特别多,比如

Redis的内存模型?

Redis的底层数据结构是怎么的?

Redis的多线程模型 Redis的集群原理

Redis的雪崩,击穿,穿透怎么解决?

Redis它快吗?它为什么快?

等等...

我太难了

关于Redis如何优化,今天分享一篇好的话题,助力大家能在面试的时候有一个好的收成~

一、设计优化

1. 估算Redis内存使用量

以非数字的字符串键值对为例,假设key和value的长度均为12个字节,则内部使用的编码方式为embstr。共计90000个键值对占用的空间

 

 

Redis中存储键值对使用字典,字典内部使用哈希表数组,数组的每个元素dictEntry中共有三个指针(指向键的指针,指向值的指针,指向下一个节点的指针),在64位系统中,每个指针占用8字节,则共计24个字节,向上取2的整数幂,则分配32个字节。

一个key,使用SDS存储,数据大小12字节,len+alloc+flags+空字符共4个字节(3.2版本之后),共计12+4=16个字节

一个value,外层使用对象redisObject并指向一个SDS(存放值内容)。对象内存占用16个字节,SDS需要16个字节

综上,一个dictEntry使用的内存总共为 32 + 16 + 16 + 16 = 80字节。

存储90000个键值对需要的bucket数组大小为90000向上取2的整数幂,即131072;每个bucket元素占用8字节(因为内部存储的指针)。

存储90000个键值对占用的总内存:90000*80 + 131072*8 = 82488576。

当存储的键值对长度由12字节增加到13字节,对应的SDS变成17字节,jemalloc分配32个字节,因此每个dictEntry占用的字节数变成112字节。则存储90000个的内存占用变为 90000*12 + 131072*8 = 11128576。

2. 优化内存占用

1. 利用jemalloc特性进行优化

 

 

jemalloc是Redis的默认内存分配器,在64位系统中,将内存空间划分成小、大、巨大三个范围;每个范围又划分为许多小的内存块单位,当Redis存储数据时,选择适合的内存块进行存储。譬如存储130字节的对象,jemalloc会将其放入到160字节的内存单元中。

2. 使用整型/长整型

Redis存储字符串的编码类型有三种,当字符串为数字时,使用int(8字节)存储代替字符串,可以节省很多空间。

3. 共享对象

共享对象可以减少对象的创建,包括redisObject的创建。Redis中的共享对象目前只有0-9999,可以通过REDIS_SHARED_INTEGERS参数提高,譬如调整到20000,则0-19999都可以共享

4.缩短键值对的存储长度

大键值对,延长写入和读取耗时、延长持久化需要时间,延长网络传输时间,并且占用内存多,更容易触发内存淘汰机制。尽量缩短存储长度,必要时进行压缩和序列化

二、设置键值的过期时间

Redis的serverCron函数定期清除过期键,节约内存占用,避免键值对过多堆积,频繁触发内存淘汰机制

三、限制Redis内存大小

在64位系统中,默认没有设置最大内存,配置项maxmemory被注释了。当物理内存不足时,使用磁盘作为虚拟内存,将物理内存中的部分数据存放到虚拟内存,这个操作会阻塞Redis进程。当设置了最大内存,当超出限制时,触发内存淘汰。内存淘汰策略在Redis4.0后有8种,主要用到以下原理

  • LRU(Least Recently Used,最近最少使用)原理:使用链表保存缓存数据,越靠近表头,存放的数据访问时间越近。当有新数据时插入表头,当有缓存命中时,将数据移至表头,当内存不足时,丢弃表尾数据

缺点是类似全表扫描时,会将链表数据污染

  • LFU(Least Frequently Used,最不经常使用策略)原理:记录内存块的使用次数,回收时,按照访问次数排序,当缓存不足时,将使用频率最低的内存释放。

缺点是短时间内大量访问的数据很难删除

1. Redis缓存淘汰策略

    1. noeviction:不淘汰任何数据,当内存不足时,新增操作会报错,Redis 默认内存淘汰策略;
    2. allkeys-lru:淘汰整个键值中最久未使用的键值;
    3. allkeys-random:随机淘汰任意键值;
    4. volatile-lru:淘汰所有设置了过期时间的键值中最久未使用的键值;
    5. volatile-random:随机淘汰设置了过期时间的任意键值;
    6. volatile-ttl:优先淘汰更早过期的键值;
    7. volatile-lfu:淘汰所有设置了过期时间的键值中,最少使用的键值;
    8. allkeys-lfu:淘汰整个键值中最少使用的键值;

四、使用Lazy free特性(Redis4.0新增)

删除大键值对比较耗时,造成主线程的阻塞,为此将删除的操作放在子线程中。共有四项配置:

  • lazyfree-lazy-eviction:当Redis运行内存超过最大内存,是否启用lazy free
  • lazyfree-lazy-expire:当设置了过期键,在键过期之后,是否启用lazy free
  • lazyfree-lazy-server-del:有些命令会隐式删除键,比如rename命令,对这些命令执行时是否启用lazy free
  • slave-lazy-flush:从节点加载主节点的RDB文件前,会运行flushall清理原有数据,此时是否启用lazy free

五、禁用长耗时的查询命令

Redis大部分的读写命令的时间复杂度在O(1)到O(N)之间。对于O(N)的命令,需要谨慎使用,如果执行时间过长,将会阻塞Redis

  • 禁用Keys
  • 避免一次查询所有键,使用scan命令进行分批遍历
  • 控制Hash、Set、Sorted Set结构的数据大小
  • 将排序、并集、交集放到客户端进行
  • 删除大数据,使用unlink,启用新线程删除目标数据(Redis 6.0启用多线程的原因,增加I/O操作并发)

六、使用slowlog优化耗时命令

使用slowlog命令找出高耗时的Redis命令。慢查询的配置项:

  • slowlog-log-slower-than:慢查询评定的时间阈值,单位微妙
  • slowlog-max-len:配置慢查询日志的最大记录数

七、避免大量数据同时失效

serverCron函数每100毫秒执行一次过期扫描。随机抽取过期键字典中的20个键,删除其中的已经过期的键,判断过期键的比例是否超过25%,重复执行此流程。如果一次扫描中删除了大量过期键,将会造成阻塞。

在设置过期时间时,加入随机数。

八、检查数据持久化策略

Redis4.0之后,加入混合持久化功能,结合了RDB和AOF。在写入时,将当前数据以RDB的形式写入文件的开头,后续的操作命令以AOF的格式存入文件;在加载时,先加载RDB文件,再加载AOF命令。

RDB持久化,可能存在一定时间内的数据丢失。AOF持久化,文件较大时执行较慢,影响启动速度。在非必须持久化操作时,可以关闭持久化,避免间歇性的卡顿(serverCron函数周期性执行持久化操作)

九、使用Pipeline批量操作数据

 

 

十、客户端使用优化

使用Redis连接池,减少网络传输次数和非必要调用指令。

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

十一、使用分布式架构增加读写速度

Redis分布式架构有:

  • 主从同步:读写分离
  • 哨兵:自动容灾
  • Redis Cluster集群:多读多写,高扩展(集群可添加节点)高可用(某主节点无从节点自动将其他主节点多余的从节点转移),自动容灾

详细:

十二、其他优化

使用物理机非虚拟机。虚拟机和物理机共享物理网口,并且一台物理机可能有多个虚拟机运行,在内存占用和网络延迟上性能较差

十三、禁用THP特性

Linux默认开启,支持大内存页2MB分配。

开启THP之后,fork速度变慢,fork之后每个内存页从4KB变成2MB,大幅增加重写期间父进程内存消耗。同时每次写命令引起的复制内存页单位放大了512倍,会拖慢写操作的执行时间,导致大量写操作慢查询。

Redis雪崩现象:

产生条件:1. 大量缓存同时失效 2.大量并发请求访问失效缓存 导致数据库宕机

解决方案:过期时间设置加入随机数

Redis缓存击穿:

缓存中没有(过期),但数据库中存在数据。此时大量并发请求访问这部分数据,数据库压力陡增。缓存雪崩是大量的缓存击穿。

解决方案:

1.设置热点数据永不过期

2.接口限流熔断和降级

3.布隆过滤器。bloomfilter类似一个哈希表但是不存key,快速判断一个元素是否在集合中。使用多个哈希函数计算入参key得到坐标,在一个bit数组中存储对应位置为1。查找时只要有一个位置为0则不存在,但都为1也有可能不存在。使用多个哈希函数是基于哈希冲突的考量。

4.加锁。这种情况,只允许能有一个线程查询数据库,获取结果后将结果放入缓存,其余线程则直接访问缓存

public String getData(String key) throws Exception{

    String data \= redis.get(key);
    if(data == null){
        if(lock.tryLock()){
            data \= redis.get(key);
            if(data == null){
                //查询数据库
                data = mysql.select();
                redis.set(key,data);
            }else{
                return data;
            }
        }else{            
            Thread.sleep(1000);
            return getData(key);
        }
    }
    return data;        
}

Redis缓存穿透:

缓存和数据库中都没有某数据,但有大量的并发请求查询这些数据。导致数据库宕机,主要考虑是漏洞攻击

解决方案:

  1. 接口层加校验,譬如用户鉴权
  2. 将对应的key的value设置为null存入缓存
作者:walker993
链接:
来源:博客园

PS :最近的面试中被问到Redis的底层原理,为什么Redis会那么快,请说说 Redis 的线程模型?

面试官:Redis为何那么快,请说说 Redis 的线程模型? - 知乎 (zhihu.com)

我是程序于小二 @终端研发部,每天分享技术开发小技巧和职场经验哦,原创不易,记得来点赞收藏哦

与[转帖]Redis性能调优万字总结,面试必问!相似的内容:

[转帖]Redis性能调优万字总结,面试必问!

https://zhuanlan.zhihu.com/p/541745804 于哥你好,最近面试挺多的,尤其是在问到java面试题,Redis被问的特别多,比如 Redis的内存模型? Redis的底层数据结构是怎么的? Redis的多线程模型 Redis的集群原理 Redis的雪崩,击穿,穿透怎么

[转帖]Redis入门(数据结构基础,分布式锁,性能调优)

目录 1、Redis基础 1.1 Redis是啥?能干啥? 1.2 安装Redis 1.3 Redis集成Spring 入门Demo 1.4 Redis支持数据类型 2、分布式锁解决方案-Redis(略) 3、Redis性能调优军规 3.1 缩短键值对的存储长度 3.2 使用 lazy free(延

[转帖]Redis 性能优化的 13 条军规!史上最全

https://zhuanlan.zhihu.com/p/118532234 Redis性能优化实战方案 Redis 是基于单线程模型实现的,也就是 Redis 是使用一个线程来处理所有的客户端请求的,尽管 Redis 使用了非阻塞式 IO,并且对各种命令都做了优化(大部分命令操作时间复杂度都是 O

[转帖]Redis性能之内部阻塞式操作及应对方法

文章目录 Redis实例都有哪些阻塞点和客户端交互的阻塞点集合的全量查询和聚合操作bigkey删除操作清空数据库 磁盘交互的阻塞点主从节点交互时的阻塞点切片集群实例交互时的阻塞点可以异步执行的阻塞点异步的子线程总结 Redis的网络IO和键值对读写都是由主线程完成的。 Redis实例都有哪些阻塞点

[转帖]Redis检索性能不足,改造rsbeat解决历史慢日志跟踪

https://www.sohu.com/a/313061840_411876 作者介绍 刘宇,甜橙金融创新中心基础技术架构师,拥有9年IT从业经验、9年数据库开发运维经验、4次大型营销活动经验。目前关注容器、分布式数据库技术等基础技术。 在线上排查redis性能问题时,从redis中找进行优化是一

[转帖]面试官:Redis 性能优化都有哪些方法?

https://cloud.tencent.com/developer/article/2168105?areaSource=104001.13&traceId=zcVNsKTUApF9rNJSkcCbB 前言 Redis作为高性能的内存数据库,在大数据量的情况下也会遇到性能瓶颈,日常开发中只有时刻

[转帖]面试官:Redis 性能优化都有哪些方法?

https://cloud.tencent.com/developer/article/2168105?areaSource=105001.13&traceId=iLuwwg5L5-kYlGSYRZNBH 前言 Redis作为高性能的内存数据库,在大数据量的情况下也会遇到性能瓶颈,日常开发中只有时刻

[转帖]面试官:Redis 性能优化都有哪些方法?

https://cloud.tencent.com/developer/article/2168105?areaSource=&traceId= 前言 Redis作为高性能的内存数据库,在大数据量的情况下也会遇到性能瓶颈,日常开发中只有时刻谨记优化铁则,才能使得Redis性能发挥到极致。 本文将会介

[转帖]Day742.Redis阻塞主线程的问题 -Redis 核心技术与实战

Redis阻塞主线程的问题 Hi,我是阿昌,今天学习记录的内容是Redis阻塞主线程的问题。 Redis 之所以被广泛应用,很重要的一个原因就是它支持高性能访问。 也正因为这样,我们必须要重视所有可能影响 Redis 性能的因素(例如命令操作、系统配置、关键机制、硬件配置等),不仅要知道具体的机制,

[转帖]Redis大集群扩容性能优化实践

https://www.jianshu.com/p/1f5d2abbee7f 一、背景 在现网环境,一些使用Redis集群的业务随着业务量的上涨,往往需要进行节点扩容操作。 之前有了解到运维同学对一些节点数比较大的Redis集群进行扩容操作后,业务侧反映集群性能下降,具体表现在访问时延增长明显。 某