[英]Why does the EVALSHA command come at such a performance cost when compared to native commands run on the redis-cli client?
以下是我針對 redis-benchmark 工具運行的一些測試和結果。
C02YLCE2LVCF:Downloads xxxxxx$ redis-benchmark -p 7000 -q -r 1000000 -n 2000000 JSON.SET fooz . [9999]
JSON.SET fooz . [9999]: 93049.23 requests per second
C02YLCE2LVCF:Downloads xxxxxx$ redis-benchmark -p 7000 -q -r 1000000 -n 2000000 evalsha 8d2d42f1e3a5ce869b50a2b65a8bfaafe8eff57a 1 fooz [5555]
evalsha 8d2d42f1e3a5ce869b50a2b65a8bfaafe8eff57a 1 fooz [5555]: 61132.17 requests per second
C02YLCE2LVCF:Downloads xxxxxx$ redis-benchmark -p 7000 -q -r 1000000 -n 2000000 eval "return redis.call('JSON.SET', KEYS[1], '.', ARGV[1])" 1 fooz [5555]
eval return redis.call('JSON.SET', KEYS[1], '.', ARGV[1]) 1 fooz [5555]: 57423.41 requests per second
對於應該具有運行服務器端的腳本的性能優勢的東西與運行腳本客戶端的客戶端相比,性能顯着下降。
從客戶EVALSHA
= 34% 的性能損失
從EVALSHA
到EVAL
= 6% 的性能損失
非 JSON 插入set
命令的結果相似
C02YLCE2LVCF:Downloads xxxxxx$ redis-benchmark -p 7000 -q -r 1000000 -n 2000000 set fooz 3333
set fooz 3333: 116414.43 requests per second
C02YLCE2LVCF:Downloads xxxxxxx$ redis-benchmark -p 7000 -q -r 1000000 -n 2000000 evalsha e32aba8d03c97f4418a8593ed4166640651e18da 1 fooz [2222]
evalsha e32aba8d03c97f4418a8593ed4166640651e18da 1 fooz [2222]: 78520.67 requests per second
當我執行 info commandstat 並觀察到EVALSHA
命令的性能較差時,我第一次注意到這一點
# Commandstats
cmdstat_ping:calls=331,usec=189,usec_per_call=0.57
cmdstat_eval:calls=65,usec=4868,usec_per_call=74.89
cmdstat_del:calls=2,usec=21,usec_per_call=10.50
cmdstat_ttl:calls=78,usec=131,usec_per_call=1.68
cmdstat_psync:calls=51,usec=2515,usec_per_call=49.31
cmdstat_command:calls=5,usec=3976,usec_per_call=795.20
cmdstat_scan:calls=172,usec=1280,usec_per_call=7.44
cmdstat_replconf:calls=185947,usec=217446,usec_per_call=1.17
****cmdstat_json.set:calls=1056,usec=26635,usec_per_call=25.22**
****cmdstat_evalsha:calls=1966,usec=68867,usec_per_call=35.03**
cmdstat_expire:calls=1073,usec=1118,usec_per_call=1.04
cmdstat_flushall:calls=9,usec=694,usec_per_call=77.11
cmdstat_monitor:calls=1,usec=1,usec_per_call=1.00
cmdstat_get:calls=17,usec=21,usec_per_call=1.24
cmdstat_cluster:calls=102761,usec=23379827,usec_per_call=227.52
cmdstat_client:calls=100551,usec=122382,usec_per_call=1.22
cmdstat_json.del:calls=247,usec=2487,usec_per_call=10.07
cmdstat_script:calls=207,usec=10834,usec_per_call=52.34
cmdstat_info:calls=4532,usec=229808,usec_per_call=50.71
cmdstat_json.get:calls=1615,usec=11923,usec_per_call=7.38
cmdstat_type:calls=78,usec=115,usec_per_call=1.47
從JSON.SET
到EVALSHA
,性能降低了約 30%,這是我在直接測試中觀察到的。
問題是,為什么? 而且,這是否值得關注,或者這種觀察是否在公平的預期之內?
對於上下文,我使用EVALSHA
而不是直接 JSON.SET 命令的原因有兩個。
IORedis 客戶端庫不直接支持使用 RedisJson。
由於先前的事實,我將不得不使用 send_command() 然后將直接命令發送到服務器,但在使用 TypeScript 時不能使用流水線。 因此,我將不得不單獨執行所有其他命令並放棄流水線操作。
我認為這應該是更好的表現?
****** 更新:
所以最后,根據下面的答案,我重構了我的代碼,只包含 1 個EVALSHA
用於寫入,因為它使用了 2 個命令,即 set 和 expire 命令。 同樣,我不能把它單獨放到 RedisJson 中,所以這就是原因。
這是某人參考的代碼:顯示 evalsha 和回退
await this.client.evalsha(this.luaWriteCommand, '1', documentChange.id, JSON.stringify(documentChange), expirationSeconds)
.catch((error) => {
console.error(error);
evalSHAFail = true;
});
if (evalSHAFail) {
console.error('EVALSHA for write not processed, using EVAL');
await this.client.eval("return redis.pcall('JSON.SET', KEYS[1], '.', ARGV[1]), redis.pcall('expire', KEYS[1], ARGV[2]);", '1', documentChange.id, JSON.stringify(documentChange), expirationSeconds);
console.log('SRANS FRUNDER');
this.luaWriteCommand = undefined;
為什么 Lua 腳本在您的情況下速度較慢?
因為EVALSHA
需要做比單個JSON.SET
或SET
命令更多的工作。 運行EVALSHA
,Redis 需要將參數推送到 Lua 堆棧,運行 Lua 腳本,並從 Lua 堆棧彈出返回值。 它應該比JSON.SET
或SET
ac 函數調用慢。
那么服務器端腳本什么時候有性能優勢呢?
首先,您必須在腳本中運行多個命令,否則將不會有我上面提到的任何性能優勢。
其次,服務端腳本比一個一個的向Redis發送serval命令,從Redis獲取結果,在客戶端做計算工作更快。 因為,Lua 腳本節省了大量的往返時間。
第三,如果您需要在 Lua 腳本中進行非常復雜的計算工作。 這可能不是一個好主意。 因為Redis是單線程運行腳本的,如果腳本運行時間過長,會阻塞其他客戶端。 相反,在客戶端,您可以利用多核的優勢來進行復雜的計算。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.