redis慢查詢?nèi)罩?/h3>
慢查詢?nèi)罩揪褪窍到y(tǒng)在命令執(zhí)行前后計(jì)算每條命令的執(zhí)行時間,當(dāng)超過預(yù)設(shè)閾值,就將這條命令的相關(guān)信息(例如:發(fā)生時間、耗時、命令的詳細(xì)信息)記錄下來。
慢查詢記錄的是執(zhí)行命令的時間,不包括這個命令排隊(duì)的時間,客戶端發(fā)送請求的等待時間,返回?cái)?shù)據(jù)的時間
設(shè)置慢查詢
slowlog-log-slower-than : 用來設(shè)置超過時間的閾值,默認(rèn)是10000,單位是微秒
slowlog-log-slower-than=0,那么系統(tǒng)會記錄所有的命令;如果slowlog-log-slower-than<0,那么對任何命令都不會記錄
127.0.0.1:6379> config set slowlog-log-slower-than 10000
OK
127.0.0.1:6379> config get slowlog-log-slower-than
1) "slowlog-log-slower-than"
2) "10000"
slowlog-max-len : 慢查詢?nèi)罩咀疃啻鎯Χ嗌贄l,記錄超過了舊刪除最前面的數(shù)據(jù)
127.0.0.1:6379> config set slowlog-max-len 200
OK
127.0.0.1:6379> config get slowlog-max-len
1) "slowlog-max-len"
2) "200"
127.0.0.1:6379> config rewrite #重置設(shè)置
獲取慢查詢?nèi)罩?/h5>
命令slowlog get [n] 獲取慢查詢?nèi)罩?n表示獲取前面幾條
先用redis自帶的性能測試工具生成10萬條數(shù)據(jù),然后執(zhí)行keys * 命令,由于生成了10萬條數(shù)據(jù),keys * 會執(zhí)行很長時間
./redis-benchmark -r 100000 -n 100000 -q
127.0.0.1:6379> keys *
127.0.0.1:6379> slowlog get 2
1) 1) (integer) 86 [命令id]
2) (integer) 1554139864 [執(zhí)行命令的時間戳]
3) (integer) 231982 [命令耗時]
4) 1) "keys"
2) "*"
5) "127.0.0.1:43925"
6) ""
2) 1) (integer) 85
2) (integer) 1554137629
3) (integer) 10714
4) 1) "LRANGE"
2) "mylist"
3) "0"
4) "599"
5) "127.0.0.1:47661"
6) ""
127.0.0.1:6379> slowlog reset #重置慢查詢?nèi)罩?
redis管道pipeline
Pipeline指的是管道技術(shù),指的是客戶端允許將多個請求依次發(fā)給服務(wù)器,過程中而不需要等待請求的回復(fù),在最后再一并讀取結(jié)果即可。
例如每次執(zhí)行一次redis命令發(fā)起請求然后返回結(jié)果,這樣每次都需要建立連接,對于批量的命令執(zhí)行會花費(fèi)大量時間,管道命令支持客戶端允許將多個請求一次發(fā)給服務(wù)器,過程中不需要等待請求的回復(fù),最后一并讀取結(jié)果,只需要一次IO


深入源碼(普通jedis命令)
Redis客戶端與Redis之間使用TCP協(xié)議進(jìn)行連接,一個客戶端可以通過一個socket連接發(fā)起多個請求命令。每個請求命令發(fā)出后client通常會阻塞并等待redis服務(wù)處理,redis處理完后請求命令后會將結(jié)果通過響應(yīng)報(bào)文返回給client,因此當(dāng)執(zhí)行多條命令的時候都需要等待上一條命令執(zhí)行完畢才能執(zhí)行。
深入查看jedis的get方法
JedisConnectionFactory factory = (JedisConnectionFactory)applicationContext.getBean("jedisConnectionFactory");
Jedis jedis = factory.getConnection().getNativeConnection();
String value = jedis.get("key");
進(jìn)入get方法內(nèi)部,每次執(zhí)行一次命令后都會flush,這樣就將數(shù)據(jù)發(fā)送給redis-server并等待數(shù)據(jù)返回



深入源碼(管道)
Jedis jedis = factory.getConnection().getNativeConnection();
Pipeline pipeline = jedis.pipelined();
for (int i = 0; i < 10; i++) {
pipeline.set("key_" + i, UUID.randomUUID().toString());
}
pipeline.sync();
jedis.close();
管道的方式先將所有的cmd與參數(shù)都寫入了outputstream,但還沒有傳到redis客戶端,Pipeline對象sync方法里面執(zhí)行了flush將請求發(fā)給redis-server



pipeline通過減少客戶端與redis的通信次數(shù)來實(shí)現(xiàn)降低延時時間,而且Pipeline 實(shí)現(xiàn)的原理是隊(duì)列,而隊(duì)列的原理是時先進(jìn)先出,這樣就保證數(shù)據(jù)的順序性。pipeline會將命令返回的數(shù)據(jù)緩存到內(nèi)存,所以如果命令越多返回的數(shù)據(jù)也會越多,這樣會消耗內(nèi)存,所以也不是將所有的操作都放到管道會最好
pipeline使用
public void test00(){
JedisConnectionFactory factory = (JedisConnectionFactory)applicationContext.getBean("jedisConnectionFactory");
Jedis jedis = factory.getConnection().getNativeConnection();
Pipeline pipeline = jedis.pipelined();
for (int i = 0; i < 10; i++) {
pipeline.set("key_" + i, UUID.randomUUID().toString());
}
//pipeline.sync(); 提交命令
List<Object> objectList = pipeline.syncAndReturnAll(); //提交命令并獲取返回值
System.out.println(objectList);
jedis.close();
}
redis的過期策略和內(nèi)存淘汰機(jī)制
過期策略
redis采用的是定期刪除 + 惰性刪除策略
定期刪除
Redis默認(rèn)每個100ms檢查是否有過期的key,有過期的key則刪除。這個檢查刪除不是說說所有的key全部檢查過去,而是隨機(jī)抽取檢查。因此,如果只采用定期刪除策略,會導(dǎo)致很多Key到時間沒有刪除。
惰性刪除
由于定期刪除的缺陷會導(dǎo)致部分key不能在規(guī)定時間內(nèi)刪除,惰性刪除就派上用場了,所謂的惰性刪除就是在你獲取某個key的時候,redis會檢查一下是否過期,如果過期了就會刪除
定期刪除+惰性刪除是否就沒有其他問題了?
不是的,如果定期刪除沒刪除Key。然后你也沒及時去請求Key,也就是說惰性刪除也沒生效。這樣,Redis的內(nèi)存會越來越高,這時候必須采用內(nèi)存淘汰機(jī)制
內(nèi)存淘汰機(jī)制
# maxmemory-policy volatile-lru
Noeviction:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,新寫入操作會報(bào)錯。應(yīng)該沒人使用吧;
Allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最近最少使用的Key。推薦使用,目前項(xiàng)目在用這種;
Allkeys-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,隨機(jī)移除某個key,應(yīng)該也沒人使用吧;
Volatile-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,移除最近最少使用的Key。這種情況一般是把Redis既當(dāng)緩存又做持久化存儲的時候才用。不推薦;
Volatile-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,隨機(jī)移除某個Key。依然不推薦;
Volatile-ttl:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,有更早過期時間的Key優(yōu)先移除。不推薦。