一、Redis监控方法
1、redis info命令
Redis的监控指标主要通过INFO命令获取,该命令可以返回丰富的运行监控信息。info主要有以下几项,因版本不同可能略有差别:
# Server
redis_version:7.2.4
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:ee3f37b1e139265
redis_mode:standalone
os:Linux 3.10.0-693.el7.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:4.8.5
process_id:710649
process_supervised:no
run_id:d18cddfec1ae8e55e35c83079be0b5f31ae9dc4f
tcp_port:6379
server_time_usec:1710384474327851
uptime_in_seconds:580373
uptime_in_days:6
hz:10
configured_hz:10
lru_clock:15885658
executable:/usr/local/redis/bin/./redis-server
config_file:/usr/local/redis/bin/./redis.conf
io_threads_active:0
listener0:name=tcp,bind=127.0.0.1,bind=-::1,port=6379
# Clients
connected_clients:1
cluster_connections:0
maxclients:10000
client_recent_max_input_buffer:20480
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0
total_blocking_keys:0
total_blocking_keys_on_nokey:0
# Memory
used_memory:1064464
used_memory_human:1.02M
used_memory_rss:4321280
used_memory_rss_human:4.12M
used_memory_peak:1283112
used_memory_peak_human:1.22M
used_memory_peak_perc:82.96%
used_memory_overhead:888632
used_memory_startup:865896
used_memory_dataset:175832
used_memory_dataset_perc:88.55%
allocator_allocated:1350328
allocator_active:1617920
allocator_resident:6791168
total_system_memory:33568501760
total_system_memory_human:31.26G
used_memory_lua:31744
used_memory_vm_eval:31744
used_memory_lua_human:31.00K
used_memory_scripts_eval:0
number_of_cached_scripts:0
number_of_functions:0
number_of_libraries:0
used_memory_vm_functions:32768
used_memory_vm_total:64512
used_memory_vm_total_human:63.00K
used_memory_functions:184
used_memory_scripts:184
used_memory_scripts_human:184B
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.20
allocator_frag_bytes:267592
allocator_rss_ratio:4.20
allocator_rss_bytes:5173248
rss_overhead_ratio:0.64
rss_overhead_bytes:-2469888
mem_fragmentation_ratio:4.07
mem_fragmentation_bytes:3258640
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_total_replication_buffers:0
mem_clients_slaves:0
mem_clients_normal:22400
mem_cluster_links:0
mem_aof_buffer:0
mem_allocator:jemalloc-5.3.0
active_defrag_running:0
lazyfree_pending_objects:0
lazyfreed_objects:0
# Persistence
loading:0
async_loading:0
current_cow_peak:0
current_cow_size:0
current_cow_size_age:0
current_fork_perc:0.00
current_save_keys_processed:0
current_save_keys_total:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1710320429
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
rdb_saves:2
rdb_last_cow_size:569344
rdb_last_load_keys_expired:0
rdb_last_load_keys_loaded: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_rewrites:0
aof_rewrites_consecutive_failures:0
aof_last_write_status:ok
aof_last_cow_size:0
module_fork_in_progress:0
module_fork_last_cow_size:0
# Stats
total_connections_received:20
total_commands_processed:40
instantaneous_ops_per_sec:0
total_net_input_bytes:989
total_net_output_bytes:1037319
total_net_repl_input_bytes:0
total_net_repl_output_bytes:0
instantaneous_input_kbps:0.02
instantaneous_output_kbps:124.94
instantaneous_input_repl_kbps:0.00
instantaneous_output_repl_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
expire_cycle_cpu_milliseconds:10942
evicted_keys:0
evicted_clients:0
total_eviction_exceeded_time:0
current_eviction_exceeded_time:0
keyspace_hits:8
keyspace_misses:3
pubsub_channels:0
pubsub_patterns:0
pubsubshard_channels:0
latest_fork_usec:747
total_forks:2
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
total_active_defrag_time:0
current_active_defrag_time:0
tracking_total_keys:0
tracking_total_items:0
tracking_total_prefixes:0
unexpected_error_replies:0
total_error_replies:3
dump_payload_sanitizations:0
total_reads_processed:61
total_writes_processed:52
io_threaded_reads_processed:0
io_threaded_writes_processed:0
reply_buffer_shrinks:8
reply_buffer_expands:2
eventloop_cycles:5789265
eventloop_duration_sum:718037603
eventloop_duration_cmd_sum:8342
instantaneous_eventloop_cycles_per_sec:11
instantaneous_eventloop_duration_usec:181
acl_access_denied_auth:0
acl_access_denied_cmd:0
acl_access_denied_key:0
acl_access_denied_channel:0
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:4a0c850d2ca9045fc42a3fb5d506348bf5d8f738
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:317.508411
used_cpu_user:507.646145
used_cpu_sys_children:0.005300
used_cpu_user_children:0.000140
used_cpu_sys_main_thread:317.505063
used_cpu_user_main_thread:507.643396
# Modules
# Errorstats
errorstat_ERR:count=3
# Cluster
cluster_enabled:0
# Keyspace
db0:keys=3,expires=0,avg_ttl=0
127.0.0.1:6379>
1.1、Server
有关redis服务器的常规信息
redis_version : 2.8.19 # Redis服务器版本
redis_git_sha1:00000000 #Git SHA1
redis_git_dirty: 0 #Git dirty flag
os: Linux 3.2.0-23-generic x86_64 #Redis服务器的宿主操作系统
arch_bits: 64 #服务器系统架构(32位或64位)
multiplexing_api: epoll #Redis使用的事件处理机制
gcc_version:4.6.3 #编译Redis时所使用的GCC版本
process_id:7573 #Redis服务的进程PID
run_id:f1c233c4194cba88616c5bfff2d97fc3074865c1 #Redis服务器的随机标识符(用于Sentinel和集群)
tcp_port:6379 #Redis服务监听的TCP端口
uptime_in_seconds:7976 #自Redis服务器启动以来,经过的秒数
uptime_in_days:0 #自Redis服务器启动以来,经过的天数. 这里还不到1天,故显示为0
hz:10 # Redis调用内部函数来执行许多后台任务的频率为每秒10次
lru_clock:1133773 #以分钟为单位进行自增的时钟,用于LRU管理
config_file:/data/redis_6379/redis.conf #redis.conf配置文件所在路径
1.2、 Clients:
客户端连接部分。
因为Redis是单线程模型(只能使用单核),来处理所有客户端的请求,且Redis默认允许客户端连接的最大数量是10000。若是看到连接数超过5000以上,那可能会影响Redis的性能。因此监控客户端连接数是非常重要的,因为客户端创建连接数的数量可能超出预期的数量,也可能是客户端端没有有效的释放连接。
connected_clients:2 #已连接客户端的数量(不包括通过从服务器连接的客户端)
client_longest_output_list:0 #当前的客户端连接中,最长的输出列表
client_biggest_input_buf:0 #当前连接的客户端中,最大的输入缓存
blocked_clients:0 #正在等待阻塞命令(BLOP、BRPOP、BRPOPLPUSH)的客户端的数量
1.3、Memory:
内存消耗相关信息,记录了服务器的内存信息:
used_memory:894216 #Redis分配器分配给Redis的内存。例如,当Redis增加了存储数据时,需要的内存直接从分配器分配给它的内存里面取就可以了,也就是直接从used_memory取。而Redis分配器分配给Redis的内存,是从操作系统分配给Redis的内存里面取的(单位是字节)
used_memory_human:873.26K #以人类可读格式显示Redis消耗的内存
used_memory_rss:2691072 #操作系统分配给Redis的内存。也就是Redis占用的内存大小。这个值和top指令输出的RES列结果是一样的。RES列结果就表示Redis进程真正使用的物理内存(单位是字节)
used_memory_peak:914160 #Redis的内存消耗峰值(单位是字节)
used_memory_peak_human:892.73K #以人类可读的格式返回Redis的内存消耗峰值
used_memory_lua:35840 #Lua引擎所使用的内存大小(单位是字节)
mem_fragmentation_ratio:3.01 # used_memory_rss和used_memory之间的比率
mem_allocator:jemalloc-3.6.0 #在编译时指定的,Redis所使用的内存分配器。可以是libc、jemalloc或者tcmalloc
理想情况下,used_memory_rss的值应该只比used_memory稍微高一点。
当rss >used,且两者的值相差较大时,表示存在(内部或者外部的)内存碎片。内存碎片的比率可以通过mem_fragmentation_ratio的值看出;
当used>rss时,表示Redis的部分内存被操作系统换出到交换空间,在这种情况下,操作可能会产生明显的延迟。
used_memory #是你的Redis实例中所有key及其value占用的内存大小;
used_memory_rss #是操作系统实际分配给Redis进程的内存。这个值一般是大于used_memory的,因为Redis的内存分配策略会产生内存碎片。
used_fragmentation_ratio #就是内存碎片的比率,正常情况下是1左右,如果大于1比如1.8说明内存碎片很严重了
在使用redis经常会因为memory引发一些列的问题。像因为内存交换产生的性能问题以及延迟问题等。
(1)使用Hash Redis在储存小于100个字段的Hash结构上,其存储效率是非常高的
(2)设置key的过期时间
(3)回收key
(4)另外一定要配置/proc/sys/vm/min_free_kbytes 让系统及时回收内存
echo 102400 > /proc/sys/vm/min_free_kbytes 设置100m开始回收内存
1.4、Persistence:
记录了RDB持久化和AOF持久化有关的信息
loading:0 #一个标志值,记录了服务器是否正在载入持久化文件
rdb_changes_since_last_save:0 #距离最后一次成功创建持久化文件之后,改变了多少个键值
rdb_bgsave_in_progress:0 #一个标志值,记录服务器是否正在创建RDB文件
rdb_last_save_time:1427189587 #最近一次成功创建RDB文件的UNIX时间戳
rdb_last_bgsave_status:ok #一个标志值,记录了最后一次创建RDB文件的结果是成功还是失败
rdb_last_bgsave_time_sec:0 #记录最后一次创建RDB文件耗费的秒数
rdb_current_bgsave_time_sec:-1 #如果服务器正在创建RDB文件,那么这个值记录的就是当前的创建RDB操作已经耗费了多长时间(单位为秒)
aof_enabled:0 #一个标志值,记录了AOF是否处于打开状态
aof_rewrite_in_progress:0 #一个标志值,记录了服务器是否正在创建AOF文件
aof_rewrite_scheduled:0 #一个标志值,记录了RDB文件创建完之后,是否需要执行预约的AOF重写操作
aof_last_rewrite_time_sec:-1 #记录了最后一次AOF重写操作的耗时
aof_current_rewrite_time_sec:-1 #如果服务器正在进行AOF重写操作,那么这个值记录的就是当前重写操作已经耗费的时间(单位是秒)
aof_last_bgrewrite_status:ok #一个标志值,记录了最后一次重写AOF文件的结果是成功还是失败
如果AOF持久化功能处于开启状态,那么在Persistence部分还会加上以下域:
aof_current_size:14301 #AOF文件目前的大小
aof_base_size:14301 #服务器启动时或者最近一次执行AOF重写之后,AOF文件的大小
aof_pending_rewrite:0 #一个标志值,记录了是否有AOF重写操作在等待RDB文件创建完之后执行
aof_buffer_length:0 # AOF缓冲区的大小
aof_rewrite_buffer_length:0 #AOF重写缓冲区的大小
aof_pending_bio_fsync:0 #在后台I/0队列里面,等待执行的fsync数量
aof_delayed_fsync:0 #被延迟执行的fsync数量
1.5、Stats:
一般统计
total_connections_received:8 #服务器已经接受的连接请求数量
total_commands_processed:10673 #服务器已经执行的命令数量
instantaneous_ops_per_sec:0 #服务器每秒中执行的命令数量
rejected_connections:0 #因为最大客户端数量限制而被拒绝的连接请求数量
expired_keys:0 #因为过期而被自动删除的数据库键数量
evicted_keys:0 #因为最大内存容量限制而被驱逐(evict)的键数量
keyspace_hits:1 #查找数据库键成功的次数
keyspace_misses:0 #查找数据库键失败的次数
pubsub_channels:0 #目前被订阅的频道数量
pubsub_patterns:0 #目前被订阅的模式数量
latest_fork_usec:159 #最近一次fork()操作耗费的时间(毫秒)
因为Redis是个单线程模型,客户端过来的命令是按照顺序执行的。因此网络问题、慢命令会造成阻塞导致redis性能下降。
如果发生命令阻塞就可以看到每秒命令处理数在明显下降。要分析解决这个性能问题,需要跟踪命令处理数的数量和延迟时间。
1.6、CPU
CPU消耗统计
used_cpu_sys:75.46 #Redis服务器耗费的系统CPU
used_cpu_user:90.12 #Redis服务器耗费的用户CPU
used_cpu_sys_children:0.00 #Redis后台进程耗费的系统CPU
used_cpu_user_children:0.00 #Redis后台进程耗费的用户CPU
1.7、Replication:
主从同步信息
1.8、Cluster:
集群部分
1.9、Keyspace:
数据库相关统计
1.10、错误指标:
包括Error相关参数,这些指标显示了错误日志和错误类型。
2、其他命令
Redis的监控还可以通过其他命令进行,例如:
- get命令:用于获取慢查询日志条目数、重置慢查询日志。2
- len命令:用于获取慢查询日志条目数。
- reset命令:用于重置慢查询日志。
3、工具监控redis
如 lepus
二、cpu高常见原因
在使用Redis时,总会碰到一些redis-server端CPU及内存占用比较高的问题,下面看下常见原因:
1、短连接导致CPU高
QPS(每秒查询率,Queries-per-second)不高,从监控看CPU确实偏高。
短连接与长连接差距比较大,原因来自两方面:
- 每次重新建连接引入的网络开销。
- 释放连接时,redis-server需消耗额外的CPU周期做清理工作。(这一点可以尝试从redis-server端做优化)
2、info命令导致CPU高
频繁执行info时通过perf分析发现getClientsMaxBuffers、getClientOutputBufferMemoryUsage及getMemoryOverheadData这几个函数占用CPU比较高。
3、pipeline导致内存占用高
4、Big Key导致内存占用高
4.1、Big Key介绍
Big Key就是某个key对应的value很大,占用的redis空间很大,本质上是大value问题。key往往是程序可以自行设置的,value往往不受程序控制,因此可能导致value很大。
4.2、降低性能原因
redis中这些Big Key对应的value值很大,在序列化/反序列化过程中花费的时间很大,因此当我们操作Big Key时,通常比较耗时,这就可能导致redis发生阻塞,从而降低redis性能。
4.3、危害
(1)阻塞请求
Big Key对应的value较大,我们对其进行读写的时候,需要耗费较长的时间,这样就可能阻塞后续的请求处理。Redis的核心线程是单线程,单线程中请求任务的处理是串行的,前面的任务完不成,后面的任务就处理不了。
(2)内存增大
读取Big Key耗费的内存比正常Key会有所增大,如果不断变大,可能会引发OOM(内存溢出),或达到redis的最大内存maxmemory设置值引发写阻塞或重要Key被逐出。
(3)阻塞网络
读取单value较大时会占用服务器网卡较多带宽,自身变慢的同时可能会影响该服务器上的其他Redis实例或者应用。
(4)影响主从同步、主从切换
删除一个大Key造成主库较长时间的阻塞并引发同步中断或主从切换。
三、优化方法
1、尽量不要使用短连接;
2、尽量不要在连接数比较高的场景下频繁使用info;
3、使用pipeline时,要及时接收请求处理结果,且pipeline不宜一次打包太多请求;
4、Big Key问题
4.1、识别方法
(1)使用redis自带的命令识别
Redis官方客户端redis-cli加上--bigkeys参数,可以找到某个实例5种数据类型(String、hash、list、set、zset)的最大key。
优点是可以在线扫描,不阻塞服务;缺点是信息较少,内容不够精确。
(2)使用debug object key命令
根据传入的对象(Key的名称)来对Key进行分析并返回大量数据,其中serializedlength的值为该Key的序列化长度,需要注意的是,Key的序列化长度并不等同于它在内存空间中的真实长度,此外,debug object属于调试命令,运行代价较大,并且在其运行时,进入Redis的其余请求将会被阻塞直到其执行完毕。并且每次只能查找单个key的信息,官方不推荐使用。
(3)redis-rdb-tools开源工具
这种方式是在redis实例上执行bgsave,bgsave会触发redis的快照备份,生成rdb持久化文件,然后对dump出来的rdb文件进行分析,找到其中的大key。
4.2、解决方法
对于String数据结构的话,减少存储的字符串的长度;对于List、Hash、Set、ZSet数据结构则是减少集合中元素的个数。
(1)对大Key进行拆分
将一个Big Key拆分为多个key-value这样的小Key,并确保每个key的成员数量或者大小在合理范围内,然后再进行存储,通过get不同的key或者使用mget批量获取。
(2)对大Key进行清理
对Redis中的大Key进行清理,从Redis中删除此类数据。Redis自4.0起提供了UNLINK命令,该命令能够以非阻塞的方式缓慢逐步的清理传入的Key,通过UNLINK,你可以安全的删除大Key甚至特大Key。
(3)监控Redis的内存、网络带宽、超时等指标
通过监控系统并设置合理的Redis内存报警阈值来提醒我们此时可能有大Key正在产生,如:Redis内存使用率超过70%,Redis内存1小时内增长率超过20%等。
(4)定期清理失效数据
如果某个Key有业务不断以增量方式写入大量的数据,并且忽略了其时效性,这样会导致大量的失效数据堆积。可以通过定时任务的方式,对失效数据进行清理。
(5)压缩value
使用序列化、压缩算法将key的大小控制在合理范围内,但是需要注意序列化、反序列化都会带来一定的消耗。如果压缩后,value还是很大,那么可以进一步对key进行拆分。