redis慢查詢?nèi)罩?/h3>
慢查詢?nèi)罩揪褪窍到y(tǒng)在命令執(zhí)行前后計(jì)算每條命令的執(zhí)行時(shí)間青灼,當(dāng)超過預(yù)設(shè)閾值暴心,就將這條命令的相關(guān)信息(例如:發(fā)生時(shí)間、耗時(shí)杂拨、命令的詳細(xì)信息)記錄下來专普。
慢查詢記錄的是執(zhí)行命令的時(shí)間,不包括這個(gè)命令排隊(duì)的時(shí)間弹沽,客戶端發(fā)送請(qǐng)求的等待時(shí)間檀夹,返回?cái)?shù)據(jù)的時(shí)間
設(shè)置慢查詢
slowlog-log-slower-than : 用來設(shè)置超過時(shí)間的閾值,默認(rèn)是10000,單位是微秒
slowlog-log-slower-than=0,那么系統(tǒng)會(huì)記錄所有的命令策橘;如果slowlog-log-slower-than<0炸渡,那么對(duì)任何命令都不會(huì)記錄
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)罩咀疃啻鎯?chǔ)多少條,記錄超過了舊刪除最前面的數(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自帶的性能測(cè)試工具生成10萬條數(shù)據(jù),然后執(zhí)行keys * 命令,由于生成了10萬條數(shù)據(jù)丽已,keys * 會(huì)執(zhí)行很長(zhǎng)時(shí)間
./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í)行命令的時(shí)間戳]
3) (integer) 231982 [命令耗時(shí)]
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ù)蚌堵,指的是客戶端允許將多個(gè)請(qǐng)求依次發(fā)給服務(wù)器,過程中而不需要等待請(qǐng)求的回復(fù)促脉,在最后再一并讀取結(jié)果即可辰斋。
例如每次執(zhí)行一次redis命令發(fā)起請(qǐng)求然后返回結(jié)果策州,這樣每次都需要建立連接,對(duì)于批量的命令執(zhí)行會(huì)花費(fèi)大量時(shí)間,管道命令支持客戶端允許將多個(gè)請(qǐng)求一次發(fā)給服務(wù)器宫仗,過程中不需要等待請(qǐng)求的回復(fù)够挂,最后一并讀取結(jié)果,只需要一次IO
深入源碼(普通jedis命令)
Redis客戶端與Redis之間使用TCP協(xié)議進(jìn)行連接藕夫,一個(gè)客戶端可以通過一個(gè)socket連接發(fā)起多個(gè)請(qǐng)求命令孽糖。每個(gè)請(qǐng)求命令發(fā)出后client通常會(huì)阻塞并等待redis服務(wù)處理,redis處理完后請(qǐng)求命令后會(huì)將結(jié)果通過響應(yīng)報(bào)文返回給client,因此當(dāng)執(zhí)行多條命令的時(shí)候都需要等待上一條命令執(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í)行一次命令后都會(huì)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對(duì)象sync方法里面執(zhí)行了flush將請(qǐng)求發(fā)給redis-server
pipeline通過減少客戶端與redis的通信次數(shù)來實(shí)現(xiàn)降低延時(shí)時(shí)間,而且Pipeline 實(shí)現(xiàn)的原理是隊(duì)列滩褥,而隊(duì)列的原理是時(shí)先進(jìn)先出病蛉,這樣就保證數(shù)據(jù)的順序性。pipeline會(huì)將命令返回的數(shù)據(jù)緩存到內(nèi)存瑰煎,所以如果命令越多返回的數(shù)據(jù)也會(huì)越多铺然,這樣會(huì)消耗內(nèi)存,所以也不是將所有的操作都放到管道會(huì)最好
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)每個(gè)100ms檢查是否有過期的key,有過期的key則刪除。這個(gè)檢查刪除不是說說所有的key全部檢查過去酒甸,而是隨機(jī)抽取檢查魄健。因此,如果只采用定期刪除策略插勤,會(huì)導(dǎo)致很多Key到時(shí)間沒有刪除沽瘦。
惰性刪除
由于定期刪除的缺陷會(huì)導(dǎo)致部分key不能在規(guī)定時(shí)間內(nèi)刪除,惰性刪除就派上用場(chǎng)了农尖,所謂的惰性刪除就是在你獲取某個(gè)key的時(shí)候,redis會(huì)檢查一下是否過期析恋,如果過期了就會(huì)刪除
定期刪除+惰性刪除是否就沒有其他問題了?
不是的卤橄,如果定期刪除沒刪除Key绿满。然后你也沒及時(shí)去請(qǐng)求Key,也就是說惰性刪除也沒生效窟扑。這樣喇颁,Redis的內(nèi)存會(huì)越來越高,這時(shí)候必須采用內(nèi)存淘汰機(jī)制
內(nèi)存淘汰機(jī)制
# maxmemory-policy volatile-lru
Noeviction:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí)嚎货,新寫入操作會(huì)報(bào)錯(cuò)橘霎。應(yīng)該沒人使用吧;
Allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí)殖属,在鍵空間中姐叁,移除最近最少使用的Key。推薦使用,目前項(xiàng)目在用這種外潜;
Allkeys-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí)原环,在鍵空間中,隨機(jī)移除某個(gè)key处窥,應(yīng)該也沒人使用吧嘱吗;
Volatile-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在設(shè)置了過期時(shí)間的鍵空間中滔驾,移除最近最少使用的Key谒麦。這種情況一般是把Redis既當(dāng)緩存又做持久化存儲(chǔ)的時(shí)候才用。不推薦哆致;
Volatile-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí)绕德,在設(shè)置了過期時(shí)間的鍵空間中,隨機(jī)移除某個(gè)Key摊阀。依然不推薦耻蛇;
Volatile-ttl:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在設(shè)置了過期時(shí)間的鍵空間中驹溃,有更早過期時(shí)間的Key優(yōu)先移除城丧。不推薦延曙。