前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis开发与运维学习笔记---(12)

Redis开发与运维学习笔记---(12)

作者头像
AsiaYe
发布2020-04-27 10:35:52
7010
发布2020-04-27 10:35:52
举报
文章被收录于专栏:DBA随笔DBA随笔

//

Redis开发与运维学习笔记---(12)

//

阻塞

Redis是典型的单线程架构,所有的读写都是在一条主线程中完成的,在高并发场景中,一旦这条主线程出现了阻塞,哪怕是很短的时间,对于应用的影响都是巨大的。

Redis的阻塞,一般来讲,是由以下原因构成的:

不合理的使用API或者数据结构、CPU饱和、持久化阻塞等内在原因;

CPU竞争、内存交换、网络问题等外在原因

下面我们分别分析这些原因。

01

API或者数据结构不合理

通常情况下,Redis是内存中进行操作的,理论上执行速度是非常快的,但是如果对象的数据很多,例如包含1w个元素的hash结构执行hgetall操作,该算法的复杂度是O(n),因此执行命令就会变的很慢。

如何发现慢查询?

Redis原生的慢查询统计功能可以很好的统计慢查询情况,使用slowlog get {n}命令可以获取最近的n条慢查询指令,默认对于执行超过10ms的命令,都会记录在一定长队列中,线上实例建议设计为1ms,便于发现毫秒级以上的命令。其实关于慢查询,之前的文章中讲过一点,给出连接:

Redis开发与运维学习笔记---(2)

如何调整慢查询?

慢查询的调整可以按照下面两个方向进行:

1、修改为低算法度的命令,例如hgetall改为hmget等、禁用keys、sort命令

2、调整大对象:缩减大对象数据或者把大对象拆分为多个小对象,防止一次命令中操作过多的数据。

如何发现大对象?

redis本身提供发现大对象(大key)的工具,对应命令:

redis-cli -h {ip} -p {port} bigkeys

代码语言:javascript
复制
[root@VM_48_10_centos ~]# redis-cli --bigkeys

# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).

[00.00%] Biggest string found so far 'backup3' with 101 bytes

-------- summary -------

Sampled 4 keys in the keyspace!
Total key length in bytes is 28 (avg len 7.00)

Biggest string found 'backup3' has 101 bytes

4 strings with 398 bytes (100.00% of keys, avg size 99.50)
0 lists with 0 items (00.00% of keys, avg size 0.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)

02

CPU饱和

单线程的redis处理命令时只能使用一个CPU,而CPU饱和是指redis将单核CPU使用率跑到100%,而不是整个机器的使用率达到100%,使用top命令很容易能够识别出对应redis进程的CPU使用率,CPU饱和是非常危险的,他使得redis无法处理更多命令,严重影响吞吐量和应用的稳定性。

在redis中,可以使用--stat来查看当前redis的使用情况:

代码语言:javascript
复制
[root@VM_48_10_centos ~]# redis-cli --stat
------- data ------ --------------------- load -------------------- - child -
keys       mem      clients blocked requests            connections          
4          1.91M    5       0       425068 (+0)         737         
4          1.91M    5       0       425070 (+2)         737         
4          1.91M    5       0       425072 (+2)         737         
4          1.91M    5       0       425074 (+2)         737         
4          1.91M    5       0       425076 (+2)         737         
4          1.91M    5       0       425078 (+2)         737 

一个常见的案例是滥用ziplist编码(修改hash_max_ziplist_entries值和hash-max-ziplist-value配置),该编码的计算复杂度在O(n)到O(n²)之间,例如一个hash对象中存储了大量的元素,采用该编码方式虽然会降低内存的使用率,但是操作变得更慢,而且更消耗CPU,ziplist压缩编码是Redis用来平衡空间和效率的优化手段,不可过度使用。

03

持久化阻塞

持久化引起的阻塞情况主要有:

fork阻塞、AOF刷盘阻塞、HugePage阻塞等

fork阻塞:

fork操作发生在RDB和AOF重写时,Redis主线程调用fork操作产生共享内存的子进程,有子进程完成持久化文件重写工作,由于fork操作本身耗时较长,必然会导致主线程的阻塞;可以执行info stats命令获取到latest_fork_usec指标,表示redis最近一次fork操作耗时,如果耗时很大,则需要作出优化调整。

AOF刷盘阻塞:

当我们开启AOF持久化功能时,文件刷盘的方式一般采用每秒一次,后台线程每秒对AOF文件做fsync操作,当硬盘压力过大时,fsync操作需要等待。如果主线程发现举例上次的fsync成功超过2秒,为了数据安全性,它会阻塞知道后台线程执行fsync操作完成,这种阻塞是由于磁盘压力引起的。

当然,也可以查看info persistence统计中的aof_delayed_fsync指标,每次发生fdatasync阻塞主线程时该指标会累加。

HugePage写操作阻塞

子进程在执行重写期间利用Linux写时复制技术降低内存开销,因此只有写操作时Redis才复制需要修改的内存页,对于开启了Transaparent HugePages的操作系统,每次写命令的复制内存页从4k变为2Mb,会拖慢写操作的执行时间,导致大量写操作慢查询。

04

CPU竞争

CPU竞争问题主要分为下面两类:

进程竞争:Redis是典型的CPU密集型应用,不建议和其他多核CPU密集型服务部署在一起,其他进程过度消耗CPU时,会严重影响Redis吞吐量,可以通过top,sar等命令定位到CPU消耗的时间点和具体进程。

绑定CPU:部署Redis时一般都是单机多实例,这样能够最大程度的利用好多核CPU的优势,我们可以将Redis绑定到CPU上,这样,可以降低CPU频繁进行上下文切换的开销。但是这种方法有一个缺点,在进行RDB或者AOF文件重写时,如果做了绑定CPU的操作,则父进程与子进程将产生激烈的CPU竞争,极大影响Redis稳定性。因此,对于主节点一般不建议进行CPU绑定。

05

内存交换

swap对于Redis来说是非常致命的,Redis的高性能是建立在内存上的,如果系统把Redis的部分内存交换到硬盘,由于内存与硬盘读写速度差好几个数量级,会导致发生交换之后的redis性能急剧下降。

如何识别是否发生了内存交换?

1、使用redis-cli info server|grep process_id找到redis的进程id

2、使用cat /proc/process_id/smaps|grep Swap来查看内存交换信息

代码语言:javascript
复制
[root@VM_48_10_centos ~]# redis-cli info server|grep process_id
process_id:10539
[root@VM_48_10_centos ~]# cat /proc/10539/smaps |grep Swap
Swap:                  0 kB
Swap:                  0 kB
Swap:                  0 kB
Swap:                  0 kB

如果交换量都是0kb或者个别的4kb,则是正常现象说明redis进程内存没有被交换。

为了防止内存被交换,可以降低Linux系统使用swap优先级例如修改/proc/sys/vm/swappiness。

06

网络问题

网络问题经常会引起Redis的阻塞。常见的网络问题有:网络闪断、redis连接拒绝、连接溢出、网络延迟、网卡软中断

分别来介绍,先来看网络闪断:

1、网络闪断

一般发生在带宽耗尽或者网络切换瞬间,通常可以使用sar -n DEV来查看本机的历史流量是否正常。这里强调一点,尽量避免跨机房的Redis调用

2、redis连接拒绝,redis通过maxclients参数控制客户端的最大连接数,默认1000,当连接数大于这个阈值,则会拒绝连接进入,info stats的rejected_connections统计指标记录有被拒绝连接的数量。

代码语言:javascript
复制
[root@VM_48_10_centos ~]# redis-cli info stats|grep rejected_connections
rejected_connections:0

3、连接溢出

连接溢出分为进程限制和backlog队列溢出两种常见情况。

进程限制是指Redis对于进程使用的资源进行限制,其中一项是对进程可打开的最大文件数控制,通过ulimit -n查看,默认是1024

backlog队列溢出

系统对于特定端口的TCP连接使用backlog队列保存,Redis的默认长度是511,通过tcp-backlog参数设置,如果Redis用于高并发场景为了防止缓慢连接占用,可适当增大这个值,让它大于系统允许值(默认是128)。可以使用netstat -s查看因backlog队列溢出造成的连接拒绝统计。

4、网络延迟

常见的网络物理拓扑按照网络延迟由快到慢可分为:同物理机>同机架>跨机架>同机房>同城机房>异地机房,而容灾性恰好相反,同物理机容灾性最低而异地机房容灾性最高。redis提供了测量机器之间网络延迟的工具。分别是--latency,--latency-history,--latency-dist,这三个参数的具体内容:

--latency选项可以测试客户端到目标redis的网络延迟,但是只输出一条信息

--latency-history测试网络延迟,可以分段测试延迟,每15s输出一次

--latency-dist会使用统计表的形式从控制台输出延迟统计信息

网络带宽的占用主要是根据当时使用率是否达到瓶颈有关,如果频繁操作redis的大对象,对于千M网卡都很容易达到网卡瓶颈。因此需要重点监控机器流量,及时发现网络延迟等情况。

5、网卡软中断

网卡软中断是指由于单个网卡队列只能使用一个CPU,高并发下网卡数据交互都集中在一个CPU中,导致无法充分利用多核CPU的情况,网卡软中断一般出现在网络高流量吞吐的场景。软中断指标一般是top命令中CPU性能的si这一项。本例中,si为0

代码语言:javascript
复制
23:25:25 up 38 days,  6:46,  1 user,  load average: 4.44, 4.75, 4.95
Tasks:  83 total,   1 running,  81 sleeping,   0 stopped,   1 zombie
%Cpu0  : 93.0 us,  5.3 sy,  1.7 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DBA随笔 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档