8、Redis阻塞

前言

通过前面那么多我们这里应该很明确知道Rdis单线程结构,在高并发的时候,如果出现阻塞,哪怕是很短时间,都将会是异常噩梦

1、发现阻塞

当Redis阻塞发生的时候,线上应用服务应该最先感知到,这个是,应用房,会收到大量的Redis超时异常,常见的作坊是通过邮件,短信预警。借助于日志系统可以查看异常信息。以及借助Redis监控系统发现阻塞问题

2、内在原因

上面是定位到Redis异常节点后,首先应该排除是不是redis自身原因导致

2.1、API或者数据结构使用不合理

例如,hgetall 包含了成千上万个数据,势必会引发阻塞。不过这种是我们在项目中可以避免的使用hscan ,一般情况下标题的这种情况的发送,是慢查询或者是大对象。

2.1.1、如何发现慢查询

之前我们说过,默认执行超过10毫秒的,会被记录到定长的队列中,显示实际建议即使发现毫秒级以上的命令,如果命令执行时间在毫秒级别。

slowlog get n(n代表最近n条慢查询命令) 

发现慢查询后,可以按照下面两个方向去调整
1>修改为低算法命令,如hgetall改为hmget,禁用keys,sort等命令

2>调整大对象,缩减大对象活把大对象拆分为多个小对象。防止一次命令操作度过多的数据

2.1.2、如果发现大对象

redis本身提供发现大对象的工具,对应命令如下,内部原理是采用scan操作。将历史扫描过的最大对象统计出来便于优化,根据汇总结果可以非常方便的获取到最大对象的键,以及不同类型数据结构的使用情况

redis-cli -p 6379 -h 127.0.0.1  --bigkeys
JeandeMBP:src healerjean$ redis-cli -p 6379 -h 127.0.0.1  --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 'hello' with 5 bytes

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

Sampled 1 keys in the keyspace!
Total key length in bytes is 5 (avg len 5.00)

Biggest string found 'hello' has 5 bytes

1 strings with 5 bytes (100.00% of keys, avg size 5.00)
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)
JeandeMBP:src healerjean$ 

2.2、CPU饱和

单线程的Redis处理命令只能使用一个CPU,CPU饱和是非常危险的,首先判断当前Redis的并发量是否达到极限。

redis-cli --stat

WX20180418-112946@2x

解释:
+为每秒处理请求

2.3、持久化阻塞

2.3.1、fork阻塞

在RDB和AOF重写的时候,Redis主线程调用fork操作产生共享内存的子进程,由于进程完成持久化文件重写工作,如何fork操作本身耗时过长,必然会导致主线程的阻塞。表示最近一次fork的操作耗时,如果耗时很大,比如超过1秒,则需要作出优化调整。info stats

latest_fork_usec:658
127.0.0.1:6380> info stats
# Stats
total_connections_received:1
total_commands_processed:2421
instantaneous_ops_per_sec:0
total_net_input_bytes:34608
total_net_output_bytes:915107
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.04
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:1
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:658
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
127.0.0.1:6380> 

2.3.2、AOF刷盘阻塞

当我们开启AOF持久化功能的时候,文件刷盘的方式一般采用每秒一次,当硬盘压力过大的时候,fsync操作需要等待,知道写入完成。info persistence

127.0.0.1:6380> info persistence
# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1523958029
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0
127.0.0.1:6380> 

2、外在原因

2.1、CPU竞争

1、进程竞争:Redis是典型的CPU密集型应用,不建议和其他多核CPU密集型服务部署到一起,当其他进程过度消耗CPU的时候,将严重影响Redis

2、绑定CPU:对于开启持久化或者复制的主节点不建议绑定CPU。否则父进程和子进程就会相互竞争

2.2、内存交换

Redis保持高性能最重要的一个原因是它的数据保存到内存中,如果保存一部分到硬盘上,会由于读写速度相差太大而出现很大的问题:
查看redis进程号info server

process_id:8313

通过进程号查找 cat /proc/8313/smaps | grep Swap
如果Swap都是0Kb或个别是4kb,则是正常现象,说明Redis进程内存没有被交换。


127.0.0.1:6380> info server
# Server
redis_version:4.0.8
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:ad83a037ffc67071
redis_mode:standalone
os:Darwin 16.7.0 x86_64
arch_bits:64
multiplexing_api:kqueue
atomicvar_api:atomic-builtin
gcc_version:4.2.1
process_id:8313
run_id:d2099de68745a3bba3c7643535a5a47a8957f18b
tcp_port:6380
uptime_in_seconds:82858
uptime_in_days:0
hz:10
lru_clock:14083679
executable:/usr/local/redis-4.0.9_2/src/redis-server
config_file:/usr/local/redis-4.0.9_2/redis.conf
127.0.0.1:6380> 

2.3、网络问题

2.3.1、连接拒绝





如果满意,请打赏博主任意金额,感兴趣的请下方留言吧。可与博主自由讨论哦

支付包 微信 微信公众号
支付宝 微信 微信公众号
posted @ 2018-04-19 22:01  HealerJean  阅读(146)  评论(0编辑  收藏  举报