本章目錄
0x00 Redis 性能指標監控
(1) 性能指標
1.基本活動指標:Basic activity
2.性能指標:Performance
3.記憶體指標: Memory
4.持久性指標: Persistence
5.錯誤指標:Error
6.其他指標說明
(2) 性能測驗工具
1.redis-benchmark 命令
2.redisbench 工具
3.rdb 記憶體分析工具
(3) 基準測驗實踐
3.1 K8s中單實體redis測驗
0x01 Redis 安全優化
1.Security
非特權運行
檔案權限
介面系結
更改默認服務埠
認證配置
禁用特定命令
日志記錄
防范字串轉義和 NoSQL 注入
防范由外部客戶端精心挑選的輸入觸發的攻擊
防火墻限制訪問
禁止redis中存盤敏感的明文資料
Redis 安全配置總結示例
2.Performance Optimization
關鍵優化項
Redis 性能優化總結示例
前置知識學習補充
1.Redis資料庫基礎入門介紹與安裝 - https://blog.weiyigeek.top/2019/4-17-49.html
2.Redis資料庫基礎資料型別介紹與使用 - https://blog.weiyigeek.top/2020/5-17-50.html
3.Redis基礎運維之原理介紹和主從配置 - https://blog.weiyigeek.top/2019/4-17-97.html
4.Redis基礎運維之哨兵和集群安裝配置 - https://blog.weiyigeek.top/2019/4-17-576.html
5.Redis基礎運維之在K8S中的安裝與配置 - https://blog.weiyigeek.top/2019/4-17-524.html
7.Redis資料庫容災備份企業實戰 - https://blog.weiyigeek.top/2019/4-17-51.html
8.Redis資料庫客戶端操作實踐及入坑出坑 - https://blog.weiyigeek.top/2019/4-17-577.html
0x00 Redis 性能指標監控
(1) 性能指標
Redis 服務端常見指標引數:
redis-cli -a password info > redis-Performance.txt # 我們可以將redis服務端info相關資訊匯出到檔案之中
# 2.clients:
# 3.memory:
# 4.persistence:
# 5.stats:通用統計資料
# 6.Replication:
# 7.CPU:CPU使用情況
# 8.cluster:
# 9.Keypass:鍵值對統計數量資訊
10.20.172.108:6379> info # (1) Redis 服務端資訊互動式查看
# Server 服務器運行的環境引數
redis_version:6.2.5
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:cb556a016f8668d
redis_mode:standalone
os:Linux 5.11.0-25-generic x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:9.3.0
process_id:187640
process_supervised:no
run_id:97838216d4fe0de4739e7814b5a2e1d0d32d0982
tcp_port:6379
server_time_usec:1630241617439942
uptime_in_seconds:10930
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:2851665
executable:/opt/databases/redis-6.2.5/src/./redis-server
config_file:/home/weiyigeek/redis/6379/redis-6379.conf
io_threads_active:0
# Clients 客戶端相關資訊
connected_clients:7
cluster_connections:0
maxclients:10000
client_recent_max_input_buffer:32
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0
# Memory 服務器運行記憶體統計資料
used_memory:2050432
used_memory_human:1.96M
used_memory_rss:5140480
used_memory_rss_human:4.90M
used_memory_peak:2253512
used_memory_peak_human:2.15M
used_memory_peak_perc:90.99%
used_memory_overhead:1982152
used_memory_startup:810376
used_memory_dataset:68280
used_memory_dataset_perc:5.51%
allocator_allocated:2204376
allocator_active:2555904
allocator_resident:5230592
total_system_memory:12442619904
total_system_memory_human:11.59G
used_memory_lua:37888
used_memory_lua_human:37.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.16
allocator_frag_bytes:351528
allocator_rss_ratio:2.05
allocator_rss_bytes:2674688
rss_overhead_ratio:0.98
rss_overhead_bytes:-90112
mem_fragmentation_ratio:2.59
mem_fragmentation_bytes:3153776
mem_not_counted_for_evict:124
mem_replication_backlog:1048576
mem_clients_slaves:0
mem_clients_normal:123000
mem_aof_buffer:128
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
lazyfreed_objects:0
# Persistence 持久化資料相關資訊
loading: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:3
rdb_bgsave_in_progress:0
rdb_last_save_time:1630230687
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
aof_enabled:1
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:0
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:462848
module_fork_in_progress:0
module_fork_last_cow_size:0
aof_current_size:150
aof_base_size:92
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0
# Stats 通用統計資料資訊
total_connections_received:25
total_commands_processed:50482
instantaneous_ops_per_sec:4
total_net_input_bytes:2758703
total_net_output_bytes:22330756
instantaneous_input_kbps:0.23
instantaneous_output_kbps:0.55
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:0
evicted_keys:0
keyspace_hits:1
keyspace_misses:0
pubsub_channels:1
pubsub_patterns:0
latest_fork_usec:310
total_forks:1
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
tracking_total_keys:0
tracking_total_items:0
tracking_total_prefixes:0
unexpected_error_replies:0
total_error_replies:8
dump_payload_sanitizations:0
total_reads_processed:48899
total_writes_processed:97139
io_threaded_reads_processed:0
io_threaded_writes_processed:0
# Replication 主從相關指標資訊
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:32da05299a5a36de431b4c05122f7d2b93eca169
master_replid2:3e15749ad586d60bd0d1c93854f6f719a22316ce
master_repl_offset:8915
second_repl_offset:829
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:8915
# CPU 處理器模式占用資訊
used_cpu_sys:12.012184
used_cpu_user:9.453505
used_cpu_sys_children:0.002158
used_cpu_user_children:0.000000
used_cpu_sys_main_thread:11.802969
used_cpu_user_main_thread:9.286577
# Modules 模塊加載情況
# Errorstats 錯誤狀態資訊
errorstat_NOAUTH:count=6
errorstat_READONLY:count=1
errorstat_WRONGPASS:count=1
# Cluster 集群資訊
cluster_enabled:0
# Keyspace 庫id與鍵數量相關資訊
db0:keys=1,expires=0,avg_ttl=0
1.基本活動指標:Basic activity
| Name | Description |
|---|---|
| connected_clients | 客戶端連接數 |
| conected_laves | slave數量 |
| master_last_io_seconds_ago | 最近一次主從互動之后的秒數 |
| keyspace | 資料庫中的key值總數 |
grep -En "connected_clients|conected_laves|master_last_io_seconds_ago|keyspace" redis-Performance.txt
27:connected_clients:7 # # 客戶端連接數量
28:connected_slaves:1 # # slave連接數量
128:keyspace_hits:1
129:keyspace_misses:0
2.性能指標:Performance
| Name | Description |
|---|---|
| latency | Redis回應一個請求的時間 |
| instantaneous_ops_per_sec | 平均每秒處理請求總數 |
| hi rate(calculated) | 快取命中率(計算出來的) |
grep -En "latency|instantaneous_ops_per_sec|hi rate" redis-Performance.txt
114:instantaneous_ops_per_sec:3
3.記憶體指標: Memory
| Name | Description |
|---|---|
| used_memory | 已使用記憶體 |
| mem_fragmentation_ratio | 記憶體碎片率 |
| evicted_keys | 由于最大記憶體限制被移除的key的數量 |
| blocked_clients | 由于BLPOP,BRPOP,or BRPOPLPUSH而備阻塞的客戶端 |
grep -En "used_memory|mem_fragmentation_ratio|evicted_keys|blocked_clients" redis-Performance.txt
32:blocked_clients:0
37:used_memory:2050432
38:used_memory_human:1.96M # # 記憶體分配器從作業系統分配的記憶體總量
39:used_memory_rss:5234688
40:used_memory_rss_human:4.99M # # 作業系統看到的記憶體占用,top命令看到的記憶體
41:used_memory_peak:2253512
42:used_memory_peak_human:2.15M # # redis記憶體消耗的峰值
43:used_memory_peak_perc:90.99%
44:used_memory_overhead:1982152
45:used_memory_startup:810376
46:used_memory_dataset:68280
47:used_memory_dataset_perc:5.51%
53:used_memory_lua:37888
54:used_memory_lua_human:37.00K # # lua腳本引擎占用的記憶體大小
55:used_memory_scripts:0
56:used_memory_scripts_human:0B
67:mem_fragmentation_ratio:2.63
127:evicted_keys:0
4.持久性指標: Persistence
| Name | Description |
|---|---|
| rdb_last_save_time | 最后一次持久化保存磁盤的時間戳 |
| rdb_changes_sice_last_save | 自最后一次持久化以來資料庫的更改數 |
grep -En "rdb_last_save_time|rdb_changes_sice_last_save" redis-Performance.txt
88:rdb_last_save_time:1630230687
89:rdb_changes_since_last_save:0 # 自最后一次持久化以來資料庫的更改數
5.錯誤指標:Error
| Name | Description |
|---|---|
| rejected_connections | 由于達到maxclient限制而被拒絕的連接數 |
| keyspace_misses | key值查找失敗(沒有命中)次數 |
| master_link_down_since_seconds | 主從斷開的持續時間(以秒為單位) |
grep -En "rejected_connections|master_link_down_since_seconds" redis-Performance.txt
9:master_link_down_since_seconds:10937
119:rejected_connections:0
keyspace_misses:0 # key值查找失敗(沒有命中)次數,出現多次可能是被Hacker Attack
6.其他指標說明
# 1.復制積壓緩沖區如果設定得太小,會導致里面的指令被覆寫掉找不到偏移量,從而觸發全量同步
repl_backlog_size: 1048576
# 2.通過查看sync_partial_err變數的次數來決定是否需要擴大積壓緩沖區,它表示主從半同步復制失敗的次數
sync_partial_err:1
(2) 性能測驗工具
1.redis-benchmark 命令
描述: Redis 性能測驗是通過同時執行多個命令實作的,該命令是在 redis 的目錄下執行的;
官網參考: https://redis.io/topics/benchmarks
語法引數:
Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]
# 引數說明:
-h <hostname> Server hostname (default 127.0.0.1)
-p <port> Server port (default 6379)
-s <socket> Server socket (overrides host and port)
-a <password> Password for Redis Auth
-c <clients> Number of parallel connections (default 50)
-n <requests> Total number of requests (default 100000)
-d <size> Data size of SET/GET value in bytes (default 2)
--dbnum <db> SELECT the specified db number (default 0)
-k <boolean> 1=keep alive 0=reconnect (default 1)
-r <keyspacelen> 對SET/GET/INCR使用隨機鍵,對SADD使用隨機值使用此選項基準將擴展引數內的字串_rand_int _uu),該引數的指定范圍為0到keyspacelen-1之間的12位數字,
-P <numreq> Pipeline <numreq> requests. Default 1 (no pipeline).
-q Quiet. Just show query/sec values
--csv Output in CSV format
-l Loop. Run the tests forever
-t <tests> Only run the comma separated list of tests. The test names are the same as the ones produced as output.
-I Idle mode. Just open N idle connections and wait.
基礎實體:
# (1) 同時執行 10000 個請求來檢測性能(所有默認測驗),通過 -q 引數讓結果只顯示每秒執行的請求數
$ ./redis-benchmark -h 127.0.0.1 -p 6379 -t set,lpush -n 10000 -q
$ ./redis-benchmark -n 10000 -q
# PING_INLINE: 41493.78 requests per second
# PING_BULK: 44843.05 requests per second
# SET: 42194.09 requests per second
# GET: 44052.86 requests per second
# INCR: 43290.04 requests per second
# LPUSH: 42194.09 requests per second
# RPUSH: 42372.88 requests per second
# LPOP: 42194.09 requests per second
# RPOP: 42194.09 requests per second
# SADD: 43668.12 requests per second
# HSET: 42372.88 requests per second
# SPOP: 44843.05 requests per second
# LPUSH (needed to benchmark LRANGE): 42553.19 requests per second
# LRANGE_100 (first 100 elements): 21367.52 requests per second
# LRANGE_300 (first 300 elements): 9451.80 requests per second
# LRANGE_500 (first 450 elements): 6807.35 requests per second
# LRANGE_600 (first 600 elements): 5350.46 requests per second
# MSET (10 keys): 36363.64 requests per second
# (2) 運行指定專案的測驗,例如我們要求在安靜模式下僅運行測驗 SET 和 LPUSH 命令
$ redis-benchmark -t set,lpush -n 100000 -q
# SET: 74239.05 requests per second
# LPUSH: 79239.30 requests per second
# (3) 指定eval腳本命令進行基準測驗
$ redis-benchmark -n 100000 -q script load "redis.call('set','foo','bar')"
# script load redis.call('set','foo','bar'): 69881.20 requests per second
# (4) 選擇密鑰空間的大小,默認情況下基準測驗針對單個密鑰運行,而我們通常可以通過使用大鍵來模擬更真實的作業負載空間,
# 例如,如果我想運行 100 萬次 SET 操作,在 10 萬個可能的密鑰中為每個操作使用一個隨機密鑰,
$ redis-cli flushall
$ redis-benchmark -t set -r 100000 -n 1000000
# (5) 默認情況下,每個客戶端僅在收到上一個命令的回復時發送下一個命令, Redis 支持流水線,因此可以一次發送多個命令可以想象為并行,
# 例如: 使用 16 個命令的流水線在 MacBook Air 11" 中運行基準測驗
redis-benchmark -n 1000000 -t set,get -P 16 -q
# SET: 403063.28 requests per second
# GET: 508388.41 requests per second
# (6) 使用 Unix 域套接字形式進行基準測驗
$ numactl -C 6 ./redis-benchmark -q -n 100000 -s /tmp/redis.sock -d 256
# (7) 使用 使用 TCP loopback
$ numactl -C 6 ./redis-benchmark -q -n 100000 -d 256

在Redis、Memcached記憶體資料庫基準測驗對比:
#!/bin/bash
# BIN=./redis-benchmark
BIN=./mc-benchmark
payload=32
iterations=100000
keyspace=100000
for clients in 1 5 10 20 30 40 50 60 70 80 90 100 200 300
do
SPEED=0
for dummy in 0 1 2
do
S=$($BIN -n $iterations -r $keyspace -d $payload -c $clients | grep 'per second' | tail -1 | cut -f 1 -d'.')
if [ $(($S > $SPEED)) != "0" ]
then
SPEED=$S
fi
done
echo "$clients $SPEED"
done
最后以下是使用gnuplot生成的圖形形式的結果:

影響基準測驗要素
-
- 作業負載(連接的客戶端的數量)
-
- 不同版本的Redis
-
- 提供服務的服務器物理配置(磁盤、網路、CPU、記憶體),在多 CPU 插槽服務器上,Redis 性能取決于 NUMA 配置和行程位置,
# 不同虛擬化和裸機服務器上的基準測驗結果,
* 該測驗由 50 個同時執行 200 萬個請求的客戶端完成,
* 使用環回介面執行測驗,
* 使用 100 萬個密鑰的密鑰空間執行測驗,
* 測驗在使用和不使用流水線(16 個命令流水線)的情況下執行,
# Intel(R) Xeon(R) CPU E5520 @ 2.27GHz(帶流水線)/ (無流水線)
$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -P 16 -q # 優于無流水線,
SET: 552028.75 requests per second
GET: 707463.75 requests per second
LPUSH: 767459.75 requests per second
LPOP: 770119.38 requests per second
$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -q
SET: 122556.53 requests per second
GET: 123601.76 requests per second
LPUSH: 136752.14 requests per second
LPOP: 132424.03 requests per second
-
- 與使用相同硬體不使用虛擬化的情況相比,Redis 在 VM 上運行速度較慢(
推薦物理機按照Redis為首選)
- 與使用相同硬體不使用虛擬化的情況相比,Redis 在 VM 上運行速度較慢(
-
- 根據平臺的不同,unix 域套接字可以實作比 TCP/IP 環回(例如在 Linux 上)多約 50% 的吞吐量,
-
- 與 TCP/IP 環回相比,Unix 域套接字的性能優勢在大量使用流水線(即長流水線)時趨于降低,
-
- 當使用以太網網路訪問 Redis 時,當資料大小保持在以太網資料包大小(約 1500 位元組)以下時,使用流水線聚合命令特別有效, 在處理 10 位元組、100 位元組或 1000 位元組的查詢幾憾訓產生相同的吞吐量,
2.redisbench 工具
描述: 官方推薦的redis-benchmark在進行集群的基準測驗時,沒有辦法指定集群模式,此處引入 Redis & Redis Cluster benchmark Tool 更方便對集群基準測驗的處理,下載地址: https://github.com/panjiang/redisbench
redisbench 特點
- 以 Golang 開發構建
- 可以測驗redis單實體
- 可以測驗redis集群
- 可以利用多核
- 支持同時在多臺機器上運行,用于測驗大型redis集群(需要相同的機器硬體)
格式語法:
./redisbench -h
-a string #Redis instance address or Cluster addresses. IP:PORT[,IP:PORT]
-c int #Clients number for concurrence (default 1)
-cluster #true: cluster mode, false: instance mode
-d int #Data size in bytes (default 1000)
-ma string #addresses for run multiple testers at the same time
-mo int #the order current tester is in multiple testers
-n int #Testing times at every client (default 1)
基礎示例:
# 測驗單實體模式
./redisbench -a 127.0.0.1:6379 -c 200 -n 20000 -d 3
# 測驗集群
./redisbench -cluster=true -a 192.168.1.11:6379,192.168.1.11:6380 -c 500 -n 2000 -d 3
# 使用多個測驗節點
./redisbench -cluster=true -a 192.168.1.11:6379,192.168.1.11:6380 -c 500 -n 2000 -d 3 -ma 192.168.1.11:9001,192.168.1.11:9002,192.168.1.11:9003 -mo 1 &
./redisbench -cluster=true -a 192.168.1.11:6379,192.168.1.11:6380 -c 500 -n 2000 -d 3 -ma 192.168.1.11:9001,192.168.1.11:9002,192.168.1.11:9003 -mo 2 &
./redisbench -cluster=true -a 192.168.1.11:6379,192.168.1.11:6380 -c 500 -n 2000 -d 3 -ma 192.168.1.11:9001,192.168.1.11:9002,192.168.1.11:9003 -mo 3
Tips: 測驗結果會自動列印出:請求值,請求時間,TPS 此處不實際演示使用了,感興趣的朋友可以自行下載測驗,
3.rdb 記憶體分析工具
描述: RDR 是決議 redis rdbfile 工具,與redis-rdb-tools相比,RDR 是由golang 實作的,速度更快,
- 分析 Redis 記憶體中那個 Key 值占用的記憶體最多
- 分析出 Redis 記憶體中那一類開頭的 Key 占用最多,有利于記憶體優化
- Redis Key 值以 Dashboard 展示,這樣更直觀
安裝下載地址: https://github.com/xueqiu/rdr/releases
注意事項:
- 1.linux和windows使用前先添加可執行權限
chmod +x rdr_linux
基礎語法:
# RDR 引數解釋
show 網頁顯示 rdbfile 的統計資訊
keys 從 rdbfile 獲取所有 key
help 幫助
基礎實體(以Linux為例):
#1.分析統計多個 Redis rdb中各種型別的使用占比
./rdr-linux keys *.rdb
SEARCH:PROJECTS_BY_ID:68
SEARCH:PROJECTS_BY_ID:64
SEARCH:PROJECTS_BY_PARENTID_LIST:0
SEARCH:PROJECTS_BY_PARENTID_LIST:64
SEARCH:PROJECTS_BY_PARENTID_LIST:66
SEARCH:PROJECTS_BY_PARENTID_LIST:68
SEARCH:PROJECTS_BY_ID:66
SEARCH:PROJECTSINFO_BY_PARENTID_LIST:64
ALLOW:SEARCH_BY_SFZH:230103197805153637
./rdr-linux dump dump.rdb
{"CurrentInstance": "dump.rdb",
"LargestKeyPrefixes": {
"list": [
{
"Type": "list",
"Key": "site",
"Bytes": 144,
"Num": 1
}
],
#2.網頁顯示分析結果
./rdr-linux show -p 8080 *.rdb
start parsing...
parse dump.rdb done
parsing finished, please access http://{$IP}:8080
(3) 基準測驗實踐
3.1 K8s中單實體redis測驗
環境說明:
# 運行該Pod的主機節點
osImage: Ubuntu 20.04.1 LTS
kernelVersion: 5.4.0-42-generic
kubeProxyVersion: v1.19.6
kubeletVersion: v1.19.6
containerRuntimeVersion: docker://19.3.14
$ Server 相關資訊
redis_version:6.2.5
os:Linux 5.4.0-42-generic x86_64
arch_bits:64
gcc_version:10.3.1
process_id:1
process_supervised:no
tcp_port:6379
hz:10
configured_hz:10
lru_clock:3627023
io_threads_active:0
$ redis 配置的記憶體限額
maxmemory:1073741824
maxmemory_human:1.00G
maxmemory_policy:volatile-lru
$ cpu 相關資訊
Model name: Intel(R) Xeon(R) CPU E3-1220 V2 @ 3.10GHz
物理CPU數: 1
邏輯CPU數: 4
CPU核心數: 4
基準測驗:
# 測驗1.執行1千萬次set命令與get命令,其中每次讀取得大小為256位元組, 請求客戶端數默認50,
~$ redis-benchmark -h 10.102.39.181 -a 123456 -d 256 -t set,get -n 10000000 -q
SET: 42445.36 requests per second
GET: 49504.70 requests per second
# - 測驗時 Pod 資源峰值
very 1.0s: kubectl top pod -n database redis-cm-0 Tue Sep 7 20:36:50 2021
NAME CPU(cores) MEMORY(bytes)
redis-cm-0 848 18Mi
# 測驗2.同樣執行1千萬次set命令與get命令,其中每次讀取得大小為256位元組,唯一不同的是采用 流水線 -P 16 進行測驗(可以看出每秒set、get請求數顯著提升),
~$ redis-benchmark -h 10.102.39.181 -a 123456 -d 256 -t set,get -n 10000000 -P 16 -q
SET: 96019.98 requests per second
GET: 316575.91 requests per second
# - 測驗時 Pod 資源峰值
very 1.0s: kubectl top pod -n database redis-cm-0 Tue Sep 7 20:46:50 2021
NAME CPU(cores) MEMORY(bytes)
redis-cm-0 457m 337Mi
實踐測驗
-
- 通過shell pipe 與 redis pipe插入10萬資料進行對比
## Shell-pipe.sh
#!/bin/bash
echo "開始時間: $(date +%s)"
for ((i=0;i<100000;i++));do
echo -en "helloworld-redis-${i}" | redis-cli -h 10.102.39.181 --no-auth-warning -a 123456 -x set username${i} >> ok.txt
done
echo "完成時間: $(date +%s)"
## redis-pipe.sh
#!/bin/bash
echo "開始時間: $(date +%s)"
python3 redis-set.py >> set-command.txt
cat set-command.txt | redis-cli -h 10.102.39.181 -a 123456 --no-auth-warning --pipe
echo "完成時間: $(date +%s)"
## redis-set.py
tee redis-set.py <<'EOF'
#!/usr/bin/python
for i in range(100000):
print('set name'+str(i)+' helloworld-redis-'+str(i))
EOF
-
- 利用time命令記錄了腳本插入的執行效率
## redis pipe 方式插入資料
~/k8s/benchmark$ time ./redis-pipe.sh
# 開始時間:1631020862
# All data transferred. Waiting for the last reply...
# Last reply received from server.
# errors: 0, replies: 100000
# 完成時間: 1631020862
# real 0m0.466s
# user 0m0.126s
# sys 0m0.035s
# Keyspace
db0:keys=100000,expires=0,avg_ttl=0
## shell pipe 方式插入資料
~/k8s/benchmark$ time ./shell-pip.sh
# 開始時間: 1631021312
# 完成時間: 1631021921
# real 10m9.265s # 程式開始至結束總用時(包括CPU),
# user 3m44.411s # 程式本身以及呼叫子行程的時間,
# sys 1m55.435s # 由程式本身或者間接呼叫的系統呼叫執行時間,
# Keyspace
db0:keys=200000,expires=0,avg_ttl=0
Tips : 可以從上面的結果看出兩種方式real總耗時量相差之巨大,redis pipe方式效率相比較普通shell pipe方式不是一個量級,所以在開發程式中盡量使用redis pipe管道方式進行提交資料,
# 為了方便后續演示,握又向資料庫中插入了80W條資料,只用了大約4s,
開始時間: 1631022423
All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 800000
完成時間: 1631022427
real 0m4.023s
user 0m0.885s
sys 0m0.187s
0x01 Redis 安全優化
1.Security
描述: Redis提供的訪問控制、代碼安全問題、選擇惡意輸入可從外部觸發的攻擊等功能,需要我們運維人員進行相應的配置提高安全性,
非特權運行
描述: Redis 不需要 root 權限即可運行,建議以僅用于此目的的非特權redis用戶身份運行它,此種方式能最大程度防止CONFIG SET/GET 目錄和其他類似運行時配置指令的可能性,,
#設定一個單獨的redis賬戶很有必要,redis crackit就利用到了root用戶的特性來重置authorized_keys,首先創建一個redis賬戶,然后通過該賬戶啟動,
$ useradd redis
$ setsid sudo -u redis redis-server /etc/redis.conf
$ ps -elf|grep redis #可以看到是redis用戶啟動
# 4 S root 9048 1 0 80 0 - 59753 poll_s 19:43 ? 00:00:00 sudo -u redis redis-server /etc redis.conf
# 4 S redis 9049 9048 0 80 0 - 38471 ep_pol 19:43 ? 00:00:00 redis-server
檔案權限
描述: 因為redis密碼明文存盤在組態檔中,所以我們需要限制redis檔案目錄訪問權限,如設定redis的主目錄權限為700(rwx------),如果redis.conf組態檔獨立于redis主目錄權限修過為600(rw-------),
# 檔案權限
chmod 700 /opt/redis/redis-5.0.4/
chmod 600 /etc/redis.conf
# 所屬者、組
chown redis:redis /etc/redis.conf
chown redis:redis /opt/redis/redis-5.0.4/
介面系結
描述: 除了網路中受信任的客戶端之外,每個人都應該拒絕訪問 Redis 埠,因此運行 Redis 的服務器應該只能由使用 Redis 實作應用程式的計算機直接訪問,
假如服務器有兩個網路介面(一個A區域、一個B區域),如果只需要A區域的機器訪問則只系結到A區域網路介面中,如服務器自身訪問則只系結到本地回環介面上,
# 通過在redis.conf檔案中添加如下一行,可以將 Redis 系結到單個介面:
bind 127.0.0.1 192.168.1.200
Tips:注意除了您可以系結IPV4以為你還可系結IPV6
更改默認服務埠
描述: 除了我們可以指定系結的介面外,我們還可以更改默認的redis服務埠,可以防止黑客針對于Redis服務掃描探測,
# 將默認的服務斷開從6379變成63791
port 63791
認證配置
描述: 為Redis服務端設定一個認證密碼是非常必須,下面講解 Redis 配置密碼認證的幾種方式總結:
操作流程:
# 1.通過redis.conf檔案中進行配置,此種方式修改后需要重啟Redis,
vim /etc/redis.conf
requirepass WeiyiGeek # WeiyiGeek 即認證密碼
masterauth WeiyiGeek # 配置主節點認證密碼, 注意若master配置了密碼則slave也要配置相應的密碼引數否則無法進行正常復制的
# 2.通過命令列進行配置,此種方式的優點無需重啟Redis,
redis 127.0.0.1:6379[1]> config set requirepass my_redis
OK
redis 127.0.0.1:6379[1]> config get requirepass
1) "requirepass"
2) "my_redis"
使用密碼驗證登陸Redis服務器:
# 方式1:密碼明文會被記錄到系統命令執行歷史中(極其不推薦/不安全)
redis-cli -h 127.0.0.1 -p 6379 -a WeiyiGeek
# 方式2:互動式進行配置
redis-cli -h 127.0.0.1 -p 6379
redis 127.0.0.1:6379> auth WeiyiGeek # OK
非常注意: AUTH 命令與其他所有 Redis 命令一樣,以未加密的方式發送,因此它無法防范對網路有足夠訪問權限以執行竊聽的攻擊者, 所以對應高敏感的資料建議配置TLS 支持(Redis 在所有通信通道上都可選地支持 TLS)以加密資料與命令傳輸,
禁用特定命令
描述: 我們可以禁用 Redis 中的命令或將它們重命名為不可猜測的名稱,以便普通客戶端僅限于指定的一組命令,比如漏洞就利用config/save兩個命令完成攻擊 ,
由于redis無用戶權限限制,建議將危險的命令使用rename配置項進行禁用或重命名,這樣外部不了解重命名規則攻擊者,就不能執行這類命令FLUSHDB, FLUSHALL, KEYS, PEXPIRE, DEL, CONFIG, SHUTDOWN, BGREWRITEAOF, BGSAVE, SAVE, SPOP, SREM, RENAME, DEBUG, EVAL
例如: 普通用戶可能無法呼叫Redis CONFIG 命令來更改實體的配置,但提供和洗掉實體的系統應該能夠這樣做,
# redis.conf 組態檔
# 方式1.CONFIG / FLUSHALL命令被重命名為一個不可猜測的名稱
rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
rename-command FLUSHALL b840fc02d524045429941cc15f59e41cb7be6c53
# 方式2.通過將其重命名為空字串來完全禁用它(或任何其他命令)
rename-command CONFIG ""
rename-command FLUSHALL ""
Tips: 注意配置后需要重新redis-server服務,
日志記錄
描述: 為Redis創建訪問(或Debug)日志(根據需求設定),在建立Redis蜜罐時,如果有攻擊嘗試時,就開業及時發現監控redis安全狀態, 以及可以監控cmdstat_*指標資訊報警;
# 執行info commandstats 看出命令執行的次數、命令耗費的 CPU 時間(單位毫秒)、執行每個命令耗費的平均 CPU 時間(單位毫秒)
cmdstat_get:calls=2,usec=15,usec_per_call=7.50
cmdstat_select:calls=1,usec=9,usec_per_call=9.00
cmdstat_keys:calls=4,usec=1948,usec_per_call=487.00
cmdstat_auth:calls=3123,usec=8291,usec_per_call=2.65
日志記錄配置:
logfile "/usr/local/redis/redis.log" #日志檔案存放目錄
loglevel verbose #記錄訪問資訊
防范字串轉義和 NoSQL 注入
描述: Redis 協議沒有字串轉義的概念,所以一般情況下使用普通客戶端庫是不可能注入的, 但有可能會通過EVAL和EVALSHA命令執行的 Lua 腳本來構造惡意腳本,
> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
解決辦法: 應用程式應該避免使用從不受信任的來源獲得的字串來組成 Lua 腳本的主體,
Tips : EVALSHA 通過其 SHA1 摘要評估快取在服務器端的腳本,腳本使用SCRIPT LOAD命令快取在服務器端,該命令在其他方面與EVAL相同,
防范由外部客戶端精心挑選的輸入觸發的攻擊
描述: 有可能攻擊者構造惡意的資料結構插入到 Redis 資料庫中, 這可能會觸發Redis 內部實作的資料結構的病態(最壞情況)演算法復雜性,
例如,攻擊者可以通過 Web 表單將一組已知散列到同一桶的字串提供到散串列中,以便將 O(1)預期時間(平均時間)變為O(N )最壞的情況,消耗比預期更多的 CPU,并最終導致拒絕服務,
解決辦法: 為了防止這種特定的攻擊,Redis 對哈希函式使用了每次執行的偽隨機種子,
防火墻限制訪問
描述: 前面針對Redis-server服務層面進行安全配置,此處針對網路層面進行限制,只允許指定的IP地址進行訪問,在主機上配置防火墻的優點是防止同一網段的東西流量,
在Linux上系統防火墻設定命令:
iptables -A INPUT -s x.x.x.x -p tcp --dport 6379 -j ACCEPT #如果需要其他機器訪問或者設定了slave模式,那就記得加上相應的防火墻設定(Centos6)
firewall-cmd --add-rich-rule="rule family="ipv4" source address="x.x.x.x" port protocol="tcp" port="6379" accept" --permanent #(Centos7)
在Windows上系統防火墻設定命令:
New-NetFirewallRule -Name "redis-server-access" -DisplayName "redis-server" -Description "redis-server 客戶端訪問防火墻規則" -Direction Inbound -LocalPort 6379 -RemoteAddress x.x.x.x -Protocol TCP -Action Allow -Enabled True
Get-NetFirewallRule -Name "redis-server-access" | Format-Table
禁止redis中存盤敏感的明文資料
描述: Redis設計旨在提供高性能的KV服務,至少目前在權限訪問控制和資料持久化方面比較榷訓,所以從應用層面上,不建議使用Redis來存盤敏感資訊,例如鑒權的密碼,
Redis 安全配置總結示例
安全配置示例:
# 組態檔 vim /etc/redis/redis.conf
# 1.信任的內網運行,盡量避免有公網訪問(如果存在內網中其他固定IP則需要設定防火墻)
bind 127.0.0.1
# 2.系結redis監聽的網路介面(通過redis配置項bind,可同時系結多個IP), 把6379改為其他得埠(或者采用unix管道進行資料管理)
port 63791
# 3.開啟redis密碼認證,并設定高復雜度密碼設定,因查詢效率高,auth這種命令每秒能處理10w次以上(所以需要增加強度)
# echo -e "weiyigeek"|sha256sum
requirepass 097575a79efcd7ea7b1efa2bcda78a4fc7cbd0820736b2f2708e72c3d21f8b61
# 4.日志檔案存放目錄以及記錄redis訪問資訊,
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably) 默認
# warning (only very important / critical messages are logged)
logfile "/usr/local/redis/redis.log"
loglevel verbose
# 5.默認情況下,啟用保護模式,只有在以下情況下才應禁用(no)它
# - 您確定希望其他主機的客戶端連接到Redis
# - 即使沒有配置身份驗證,也沒有特定的介面集
# - 使用“bind”指令顯式列出,
protected-mode yes
# 6.重命名特殊命令(根據需求)
# `FLUSHDB, FLUSHALL, KEYS, PEXPIRE, DEL, CONFIG, SHUTDOWN, BGREWRITEAOF, BGSAVE, SAVE, SPOP, SREM, RENAME, DEBUG, EVAL`
rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
rename-command FLUSHDB b840fc02d524045429941cc15f59e41cb7be6c53
rename-command FLUSHALL b840fc02d524045429941cc15f59e41cb7be6c54
rename-command EVAL b840fc02d524045429941cc15f59e41cb7be6c55
rename-command DEBUG b840fc02d524045429941cc15f59e41cb7be6c56
rename-command SHUTDOWN b840fc02d524045429941cc15f59e41cb7be6c7
2.Performance Optimization
描述: Redis開發和運維人員更加關注的是Redis本身的一些配置優化,例如AOF和RDB的配置優化、資料結構的配置優化等,但是對于作業系統是否需要針對Redis做一些配置優化不甚了解或者不太關心,然而事實證明一個良好的系統操作配置能夠為Redis服務良好運行保駕護航,
關鍵優化項
- Step 1.vm.overcommit_memory 最佳實踐
Redis在啟動時可能會出現這樣的日志, 然后弄清楚什么是overcommit?
描述: Linux 作業系統對大部分申請記憶體的請求都回復yes以便能運行更多的程式,因為申請記憶體后并不會馬上使用記憶體,這種技術叫做overcommit,
# 如果Redis在啟動時有上面的日志,說明`vm.overcommit_memory=0`,Redis提示把它設定為1,
# WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the
command 'sysctl -w vm.overcommit_memory=1' for this to take effect.
# 注意:本文的可用記憶體代表物理記憶體與swap之和,
# 最佳實踐
- Redis建議把這個值設定為1是為了讓fork能夠在低記憶體下也執行成功(設定合理的maxmemory保證機器有20%~30%的閑置記憶體),
- 集中化管理aof重寫和rdb的bgsave,
Tips : 日志中的 Background save 代表的是 bgsave 和 bgrewriteaof,如果當前可用記憶體不足,作業系統應該如何處理fork,如果vm.overcommit_memory=0,代表如果沒有可用記憶體,就申請記憶體失敗,對應到Redis就是fork執行失敗,在Redis的日志會出現:Cannot allocate memory
- Step 2.vm.swapniess 最佳實踐
描述: swap對于作業系統來比較重要,當物理記憶體不足時,可以swap out一部分記憶體頁,以解燃眉之急,但世界上沒有免費午餐,swap空間由硬碟提供,對于需要高并發、高吞吐的應用來說,磁盤IO通常會成為系統瓶頸,在Linux中,并不是要等到所有物理記憶體都使用完才會使用到swap,系統引數swppiness會決定作業系統使用swap的傾向程度,swappiness的取值范圍是0~100,swappiness的值越大,說明作業系統可能使用swap的概率越高,swappiness值越低,表示作業系統更加傾向于使用物理記憶體,
如果Linux > 3.5的情況下 vm.swapniess=1 (寧愿swap也不要OOM killer) 否則 vm.swapniess=0 (寧愿OOM killer也不用swap) 從而實作如下兩個目標:
1.物理記憶體充足時候,使Redis足夠快,
2.物理記憶體不足時候,避免Redis死掉(如果當前Redis為高可用,死掉比阻塞更好),
運維提示:OOM(Out Of Memory) killer機制是指Linux作業系統發現可用記憶體不足時,強制殺死一些用戶行程(非內核行程),來保證系統有足夠的可用記憶體進行分配,
- Step 3.kernel.mm.transparent_hugepage.enabled 最佳實踐
Redis在啟動時可能會看到如下日志:
WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
Tips : 從提示看Redis建議修改Transparent Huge Pages (THP)的相關配置,Linux kernel在2.6.38內核增加了Transparent Huge Pages (THP)特性 ,支持大記憶體頁(2MB)分配,默認開啟,當開啟時可以降低fork子行程的速度,但fork之后,每個記憶體頁從原來4KB變為2MB,會大幅增加重寫期間父行程記憶體消耗,同時每次寫命令引起的復制記憶體頁單位放大了512倍,會拖慢寫操作的執行時間,導致大量寫操作慢查詢,
因此Redis日志中建議將此特性進行禁用,禁用方法如下:echo never > /sys/kernel/mm/transparent_hugepage/enabled
- Step 4.Transparent Huge Pages
Redis在啟動時可能會看到如下日志:WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
從提示看Redis建議修改Transparent Huge Pages (THP)的相關配置,Linux kernel在2.6.38內核增加了Transparent Huge Pages (THP)特性 ,支持大記憶體頁(2MB)分配,默認開啟,當開啟時可以降低fork子行程的速度,但fork之后,每個記憶體頁從原來4KB變為2MB,會大幅增加重寫期間父行程記憶體消耗,同時每次寫命令引起的復制記憶體頁單位放大了512倍,會拖慢寫操作的執行時間,導致大量寫操作慢查詢,例如簡單的incr命令也會出現在慢查詢中,因此Redis日志中建議將此特性進行禁用,禁用方法如下:
# 配置機器重啟后THP配置依然生效
tee -a /etc/rc.local <<'EOF'
echo never > /sys/kernel/mm/transparent_hugepage/enabled
EOF
- Step 5.OOM killer 優化配置
OOM killer會在可用記憶體不足時選擇性的殺掉用戶行程,它會為每個用戶行程設定一個權值,這個權值越高,被“下手”的概率就越高,反之概率越低,每個行程的權值存放在/proc/{progress_id}/oom_score中,這個值是受/proc/{progress_id}/oom_adj的控制,oom_adj在不同的Linux版本的最小值不同,可以參考Linux原始碼中oom.h(從-15到-17)
當oom_adj設定為最小值時,該行程將不會被OOM killer殺掉,設定方法如下:
# 命令
echo {value} > /proc/${process_id}/oom_adj
# 腳本
for redis_pid in $(pgrep -f "redis-server")
do
echo -17 > /proc/${redis_pid}/oom_adj
done
- Step 6.設定其打開檔案數句柄數以及單個用戶最大行程數
描述: 下面得引數主要設定是單個行程能夠使用得Linux最大檔案句柄數, 解決在高并發的情況下不會例外報錯,在Redis官方提到的建議
# You requested maxclients of 10000 requiring at least 10032 max file descriptors.
第一行:Redis建議把open files至少設定成10032,那么這個10032是如何來的呢?因為maxclients的默認是10000,這些是用來處理客戶端連接的,除此之外,Redis內部會使用最多32個檔案描述符,所以這里的10032 = 10000 + 32,
# Redis can’t set maximum open files to 10032 because of OS error: Operation not permitted.
第二行:Redis不能將open files設定成10032,因為它沒有權限設定,
# Current maximum open files is 4096. Maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase ‘ulimit –n’.
第三行:當前系統的open files是4096,所以maxclients被設定成4096-32=4064個,如果你想設定更高的maxclients,請使用ulimit -n來設定,從上面的三行日志分析可以看出open files的限制優先級比maxclients大,
解決辦法:
# 臨時
ulimit –Sn 10032
# 永久
tee etc/security/limits.conf <<'EOF'
* soft nofile 10032
* hard nofile 10032
* soft nproc 65535
* hard nproc 65535
EOF
- Step 7.TCP backlog 日志佇列優化
描述: Redis 默認的 tcp-backlog 為511 我們可以通過修改配置 tcp-backlog 進行調整,如果Linux的tcp-backlog 小于Redis設定的 tcp-backlog,那么在Redis啟動時會看到如下日志:
# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
解決方法:
# 查看
cat /proc/sys/net/core/somaxconn
128
# 修改
echo 511 > /proc/sys/net/core/somaxconn
- Step 8.保證Redis服務器時鐘的一致性
描述: 我們知道像Redis Sentinel和Redis Cluster這兩種需要多個Redis實體的型別,可能會涉及多臺服務器,雖然Redis并沒有對多個服務器的時鐘有嚴格的要求,但是假如多個Redis實體所在的服務器時鐘不一致,對于一些例外情況的日志排查是非常困難的,例如Redis Cluster的故障轉移,如果日志時間不一致,對于我們排查問題帶來很大的困擾(注:但不會影響集群功能,集群節點依賴各自時鐘),一般公司里都會有NTP服務用來提供標準時間服務,從而達到糾正時鐘的效果
例如:每小時的同步1次NTP服務
0 * * * * /usr/sbin/ntpdate ntp.xx.com > /dev/null 2>&1
Redis 性能優化總結示例
系統優化配置
# - 設定記憶體分配策略
sudo sysctl -w vm.overcommit_memory=1
# - 盡量使用物理記憶體(速度快)針對內核版本大于>=3.x (寧愿swap也不要OOM killer)
sudo sysctl -w vm.swapniess=1
# - 禁用 THP 特性減少記憶體消耗
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# - OOM killer 特性優化
for redis_pid in $(pgrep -f "redis-server")
do
echo -17 > /proc/${redis_pid}/oom_adj
done
# - 設定其打開檔案數句柄數以及單個用戶最大行程數
tee etc/security/limits.conf <<'EOF'
* soft nofile 10032
* hard nofile 10032
* soft nproc 65535
* hard nproc 65535
EOF
# - SYN佇列長度設定此引數可以容納更多等待連接的網路,
echo 511 > /proc/sys/net/core/somaxconn
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=2048
# - 每個小時同步一次時間
0 * * * * /usr/sbin/ntpdate ntp.xx.com > /dev/null 2>&1
應用配置優化
# 最大客戶端上限連接數(需根據實際情況調整與系統的open files有關,其數量值為open files(10032) - 32)
maxclients 10000
# 集群配置優化關鍵項
# 集群超時時間,如果此時間設定太小時由于網路波動可能會導致進行重新選Master的操作
cluster-node-timeout 5000
# 主節點寫入后必須同步到一臺從上,防止資料丟失的有效方法(要求是其從節點必須>=1)
min‐replicas‐to‐write 1
應用使用中優化
# (1) 查詢執行時間指的是不包括像客戶端回應(talking)、發送回復等 IO 操作,而單單是執行一個查詢命令所耗費的時間
redis> SLOWLOG LEN # 管理 redis 的慢日志查看當前日志的數量
redis> SLOWLOG RESET # 清空 slowlog 此時上面 LEN 變成 0
# (2) 斷開耗時連接
# 列出所有已連接客戶端
redis 127.0.0.1:6379> CLIENT LIST
addr=127.0.0.1:43501 fd=5 age=10 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
# 殺死當前客戶端的連接
redis 127.0.0.1:6379> CLIENT KILL 127.0.0.1:43501
OK
文章書寫不易,如果您覺得這篇文章還不錯的,請給這篇專欄 【點個贊、投個幣、收個藏、關個注,轉個發】(人間五大情),這將對我的肯定,謝謝!,
本文章來源 我的Blog站點 或 WeiyiGeek 公眾賬號 以及 我的BiliBili專欄 (
技術交流、友鏈交換請郵我喲),謝謝支持!(?′?‵?) ?
歡迎各位志同道合的朋友一起學習交流,如文章有誤請留下您寶貴的知識建議,通過郵箱【master#weiyigeek.top】聯系我喲!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/458179.html
標籤:其他
上一篇:幫助團隊成長是唯一的出路
下一篇:幫助團隊成長是唯一的出路
