這里的Redis主從結構可以是簡單的主從,sentinel,redis cluster中的主從等,
wait命令的作用:
此命令將阻塞當前客戶端,直到當前Session連接(主節點上)所有的寫命令都被傳送到指定資料量的slave節點,
如果到達超時(以毫秒為單位),則即使尚未完全傳送到達指定數量的salve節點,該命令也會回傳(成功傳送到的節點的個數),
該命令將始侄訓傳確認在WAIT命令之前發送的寫命令的副本數量,無論是在達到指定數量的副本的情況下,還是在達到超時的情況下,
具體說就是:比如對于1主2從的結構,Wait要求3秒鐘之內傳送到2個節點,但是達到超時時間3秒鐘之后只成功傳送到了1個slave節點上,此時wait也不會繼續阻塞,而是回傳成功傳送的節點個數(1),
有點類似于MySQL的半同步復制,但是效果完全不能跟半同步相比,因為Redis本身沒有回滾的功能,這里的wait命令發起之后,即便是超時時間之后沒有送到任何一個slave節點,主節點也不會回滾,
wait命令無法保證Redis主從之間的強一致,不過,在主從、sentinel和Redis群集故障轉移中,wait能夠增強(僅僅是增強,但不是保證)資料的安全性,
既然wait命令在當前連接之后會等待指定數量的從節點確認,其主節點的寫入效率必然會收到一定程度的影響,那么這個影響有多大?
這里做一個簡單的測驗,環境2核4G的宿主機,docker下的集群3主3從的Redis集群,因此不用考慮網路延遲,在執行寫入操作之后,使用兩個Case,對比使不使用wait命令等待傳送到salve的效率,
1,單執行緒回圈寫入100000個key值
2,多執行緒并發,10個執行緒每個執行緒寫入10000個key,一共寫入100000個key
Case1:單執行緒回圈寫入100000個key值
結論:不使用wait命令,整體耗時33秒,集群中單個節點的TPS為1000左右;使用wait命令,整體耗時72秒,集群中單個節點的TPS為480左右,整體效率下降了50%多一點
單執行緒不使用WAIT

單執行緒使用WAIT(redis_conn.execute_command('wait', 1, 0))

Case2:多執行緒回圈寫入100000個key值
結論:不使用wait命令,整體耗時19秒,集群中單個節點的TPS為1700左右;使用wait命令,整體耗時36秒,集群中單個節點的TPS為900左右,整體效率與單執行緒基本上一致,下降了50%多一點
多執行緒不使用WAIT,單節點上TPS可達到1700左右

多執行緒使用WAIT,單節點上TPS可達到850左右

鑒于在多執行緒模式下,CPU負載接近于瓶頸,因此不能再加更多的執行緒數,測驗資料也僅供參考,

總結:
wait能夠在主節點寫入命令之后,通過阻塞的方式等待資料傳送到從節點,wait能夠增強(但不保證)資料的安全性,
其代價或者說性能損耗也是不小的,通過以上測驗可以看出,即便是不考慮網路傳輸延遲的情況下,其性能損耗也超出了50%,
#!/usr/bin/env python# coding:utf-8import sysimport timeimport datetimefrom rediscluster import StrictRedisClusterimport threadingfrom time import ctime,sleepdef redis_cluster_write(): redis_nodes = [ {'host':'172.18.0.11','port':8888}, {'host':'172.18.0.12','port':8888}, {'host':'172.18.0.13','port':8888}, {'host':'172.18.0.14','port':8888}, {'host':'172.18.0.15','port':8888}, {'host':'172.18.0.16','port':8888}] try: redis_conn = StrictRedisCluster(startup_nodes=redis_nodes,password='******') except Exception: raise Exception redis_conn.config_set('cluster-require-full-coverage', 'yes') counter = 0 for i in range(0,100000): counter = counter+1 redis_conn.set('key_'+str(i),'value_'+str(i)) #redis_conn.execute_command('wait', 1, 0) if counter == 1000: print('insert 1000 keys '+str(str(datetime.datetime.now()))) counter = 0def redis_concurrence_test(thread_id): redis_nodes = [ {'host':'172.18.0.11','port':8888}, {'host':'172.18.0.12','port':8888}, {'host':'172.18.0.13','port':8888}, {'host':'172.18.0.14','port':8888}, {'host':'172.18.0.15','port':8888}, {'host':'172.18.0.16','port':8888}] try: redis_conn = StrictRedisCluster(startup_nodes=redis_nodes, password='******') except Exception: raise Exception redis_conn.config_set('cluster-require-full-coverage', 'yes') counter = 0 for i in range(0, 10000): counter = counter + 1 redis_conn.set('key_' + str(thread_id)+'_'+str(counter), 'value_' + str(i)) #redis_conn.execute_command('wait', 1, 0) if counter == 1000: print(str(thread_id)+':insert 1000 keys ' + str(str(datetime.datetime.now()))) counter = 0if __name__ == '__main__': #redis_cluster_write() threads = [] for i in range(10): t = threading.Thread(target=redis_concurrence_test, args=(i,)) threads.append(t) begin_time = ctime() for t in threads: t.setDaemon(True) t.start() for t in threads: t.join()
https://redis.io/commands/wait
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/26263.html
標籤:NoSQL
上一篇:redis主從復制
