1.redisåmemcachedçåºå«
2.Redis慢查询日志(Slow Log)详解
3.å°åºå¦ä½å¨springä¸ä½¿ç¨redis
redisåmemcachedçåºå«
Redisçä½è Salvatore Sanfilippoæ¾ç»å¯¹è¿ä¸¤ç§åºäºå åçæ°æ®åå¨ç³»ç»è¿è¡è¿æ¯è¾ï¼1ãRedisæ¯ææå¡å¨ç«¯çæ°æ®æä½ï¼Redisç¸æ¯Memcachedæ¥è¯´ï¼æ¥ææ´å¤çæ°æ®ç»æå并æ¯ææ´ä¸°å¯çæ°æ®æä½ï¼é常å¨Memcachedéï¼ä½ éè¦å°æ°æ®æ¿å°å®¢æ·ç«¯æ¥è¿è¡ç±»ä¼¼çä¿®æ¹åsetåå»ãè¿å¤§å¤§å¢å äºç½ç»IOç次æ°åæ°æ®ä½ç§¯ãå¨Redisä¸ï¼è¿äºå¤æçæä½é常åä¸è¬çGET/SETä¸æ ·é«æãæ以ï¼å¦æéè¦ç¼åè½å¤æ¯ææ´å¤æçç»æåæä½ï¼é£ä¹Redisä¼æ¯ä¸éçéæ©ã
2ãå å使ç¨æç对æ¯ï¼ä½¿ç¨ç®åçkey-valueåå¨çè¯ï¼Memcachedçå åå©ç¨çæ´é«ï¼èå¦æRediséç¨hashç»ææ¥åkey-valueåå¨ï¼ç±äºå ¶ç»åå¼çå缩ï¼å ¶å åå©ç¨çä¼é«äºMemcachedã
3ãæ§è½å¯¹æ¯ï¼ç±äºRedisåªä½¿ç¨åæ ¸ï¼èMemcachedå¯ä»¥ä½¿ç¨å¤æ ¸ï¼æ以平åæ¯ä¸ä¸ªæ ¸ä¸Rediså¨åå¨å°æ°æ®æ¶æ¯Memcachedæ§è½æ´é«ãèå¨k以ä¸çæ°æ®ä¸ï¼Memcachedæ§è½è¦é«äºRedisï¼è½ç¶Redisæè¿ä¹å¨åå¨å¤§æ°æ®çæ§è½ä¸è¿è¡ä¼åï¼ä½æ¯æ¯èµ·Memcachedï¼è¿æ¯ç¨æéè²ã
å ·ä½ä¸ºä»ä¹ä¼åºç°ä¸é¢çç»è®ºï¼ä»¥ä¸ä¸ºæ¶éå°çèµæï¼
1ãæ°æ®ç±»åæ¯æä¸å
ä¸Memcachedä» æ¯æç®åçkey-valueç»æçæ°æ®è®°å½ä¸åï¼Redisæ¯æçæ°æ®ç±»åè¦ä¸°å¯å¾å¤ãæ为常ç¨çæ°æ®ç±»å主è¦ç±äºç§ï¼StringãHashãListãSetåSorted SetãRediså é¨ä½¿ç¨ä¸ä¸ªredisObject对象æ¥è¡¨ç¤ºææçkeyåvalueãredisObjectæ主è¦çä¿¡æ¯å¦å¾æ示ï¼
type代表ä¸ä¸ªvalueå¯¹è±¡å ·ä½æ¯ä½ç§æ°æ®ç±»åï¼encodingæ¯ä¸åæ°æ®ç±»åå¨rediså é¨çåå¨æ¹å¼ï¼æ¯å¦ï¼type=string代表valueåå¨çæ¯ä¸ä¸ªæ®éå符串ï¼é£ä¹å¯¹åºçencodingå¯ä»¥æ¯rawæè æ¯intï¼å¦ææ¯intå代表å®é rediså é¨æ¯ææ°å¼åç±»åå¨å表示è¿ä¸ªå符串çï¼å½ç¶åææ¯è¿ä¸ªå符串æ¬èº«å¯ä»¥ç¨æ°å¼è¡¨ç¤ºï¼æ¯å¦:ââ³ ââè¿æ ·çå符串ãåªææå¼äºRedisçèæå ååè½ï¼vmå段å段æä¼çæ£çåé å åï¼è¯¥åè½é»è®¤æ¯å ³éç¶æçã
1ï¼String
常ç¨å½ä»¤ï¼set/get/decr/incr/mgetçï¼
åºç¨åºæ¯ï¼Stringæ¯æ常ç¨çä¸ç§æ°æ®ç±»åï¼æ®éçkey/valueåå¨é½å¯ä»¥å½ä¸ºæ¤ç±»ï¼
å®ç°æ¹å¼ï¼Stringå¨rediså é¨åå¨é»è®¤å°±æ¯ä¸ä¸ªå符串ï¼è¢«redisObjectæå¼ç¨ï¼å½éå°incrãdecrçæä½æ¶ä¼è½¬ææ°å¼åè¿è¡è®¡ç®ï¼æ¤æ¶redisObjectçencodingå段为intã
2ï¼Hash
常ç¨å½ä»¤ï¼hget/hset/hgetallç
åºç¨åºæ¯ï¼æ们è¦åå¨ä¸ä¸ªç¨æ·ä¿¡æ¯å¯¹è±¡æ°æ®ï¼å ¶ä¸å æ¬ç¨æ·IDãç¨æ·å§åãå¹´é¾åçæ¥ï¼éè¿ç¨æ·IDæ们å¸æè·å该ç¨æ·çå§åæè å¹´é¾æè çæ¥ï¼
å®ç°æ¹å¼ï¼RedisçHashå®é æ¯å é¨åå¨çValue为ä¸ä¸ªHashMapï¼å¹¶æä¾äºç´æ¥ååè¿ä¸ªMapæåçæ¥å£ãå¦å¾æ示ï¼Keyæ¯ç¨æ·ID,码日 valueæ¯ä¸ä¸ªMapãè¿ä¸ªMapçkeyæ¯æåçå±æ§åï¼valueæ¯å±æ§å¼ãè¿æ ·å¯¹æ°æ®çä¿®æ¹åååé½å¯ä»¥ç´æ¥éè¿å ¶å é¨MapçKey(Redisé称å é¨Mapçkey为field), ä¹å°±æ¯éè¿ key(ç¨æ·ID) + field(å±æ§æ ç¾) å°±å¯ä»¥æä½å¯¹åºå±æ§æ°æ®ãå½åHashMapçå®ç°æ两ç§æ¹å¼ï¼å½HashMapçæåæ¯è¾å°æ¶Redis为äºèçå åä¼éç¨ç±»ä¼¼ä¸ç»´æ°ç»çæ¹å¼æ¥ç´§ååå¨ï¼èä¸ä¼éç¨çæ£çHashMapç»æï¼è¿æ¶å¯¹åºçvalueçredisObjectçencoding为zipmapï¼å½æåæ°éå¢å¤§æ¶ä¼èªå¨è½¬æçæ£çHashMap,æ¤æ¶encoding为htã
3ï¼List
常ç¨å½ä»¤ï¼lpush/rpush/lpop/rpop/lrangeçï¼
åºç¨åºæ¯ï¼Redis listçåºç¨åºæ¯é常å¤ï¼ä¹æ¯Redisæéè¦çæ°æ®ç»æä¹ä¸ï¼æ¯å¦twitterçå ³æ³¨å表ï¼ç²ä¸å表çé½å¯ä»¥ç¨Redisçlistç»ææ¥å®ç°ï¼
å®ç°æ¹å¼ï¼Redis listçå®ç°ä¸ºä¸ä¸ªååé¾è¡¨ï¼å³å¯ä»¥æ¯æååæ¥æ¾åéåï¼æ´æ¹ä¾¿æä½ï¼ä¸è¿å¸¦æ¥äºé¨åé¢å¤çå åå¼éï¼Rediså é¨çå¾å¤å®ç°ï¼å æ¬åéç¼å²éåçä¹é½æ¯ç¨çè¿ä¸ªæ°æ®ç»æã
4ï¼Set
常ç¨å½ä»¤ï¼sadd/spop/smembers/sunionçï¼
åºç¨åºæ¯ï¼Redis set对å¤æä¾çåè½ä¸list类似æ¯ä¸ä¸ªå表çåè½ï¼ç¹æ®ä¹å¤å¨äºsetæ¯å¯ä»¥èªå¨æéçï¼å½ä½ éè¦åå¨ä¸ä¸ªå表æ°æ®ï¼åä¸å¸æåºç°éå¤æ°æ®æ¶ï¼setæ¯ä¸ä¸ªå¾å¥½çéæ©ï¼å¹¶ä¸setæä¾äºå¤ææ个æåæ¯å¦å¨ä¸ä¸ªsetéåå çéè¦æ¥å£ï¼è¿ä¸ªä¹æ¯listæä¸è½æä¾çï¼
å®ç°æ¹å¼ï¼set çå é¨å®ç°æ¯ä¸ä¸ª valueæ°¸è¿ä¸ºnullçHashMapï¼å®é å°±æ¯éè¿è®¡ç®hashçæ¹å¼æ¥å¿«éæéçï¼è¿ä¹æ¯setè½æä¾å¤æä¸ä¸ªæåæ¯å¦å¨éåå çåå ã
5ï¼Sorted Set
常ç¨å½ä»¤ï¼zadd/zrange/zrem/zcardçï¼
åºç¨åºæ¯ï¼Redis sorted setç使ç¨åºæ¯ä¸set类似ï¼åºå«æ¯setä¸æ¯èªå¨æåºçï¼èsorted setå¯ä»¥éè¿ç¨æ·é¢å¤æä¾ä¸ä¸ªä¼å 级(score)çåæ°æ¥ä¸ºæåæåºï¼å¹¶ä¸æ¯æå ¥æåºçï¼å³èªå¨æåºãå½ä½ éè¦ä¸ä¸ªæåºç并ä¸ä¸éå¤çéåå表ï¼é£ä¹å¯ä»¥éæ©sorted setæ°æ®ç»æï¼æ¯å¦twitter çpublic timelineå¯ä»¥ä»¥å表æ¶é´ä½ä¸ºscoreæ¥åå¨ï¼è¿æ ·è·åæ¶å°±æ¯èªå¨ææ¶é´æ好åºçã
å®ç°æ¹å¼ï¼Redis sorted setçå é¨ä½¿ç¨HashMapåè·³è·è¡¨(SkipList)æ¥ä¿è¯æ°æ®çåå¨åæåºï¼HashMapéæ¾çæ¯æåå°scoreçæ å°ï¼èè·³è·è¡¨éåæ¾çæ¯ææçæåï¼æåºä¾æ®æ¯HashMapéåçscore,使ç¨è·³è·è¡¨çç»æå¯ä»¥è·å¾æ¯è¾é«çæ¥æ¾æçï¼å¹¶ä¸å¨å®ç°ä¸æ¯è¾ç®åã
2ãå å管çæºå¶ä¸å
å¨Redisä¸ï¼å¹¶ä¸æ¯ææçæ°æ®é½ä¸ç´åå¨å¨å åä¸çãè¿æ¯åMemcachedç¸æ¯ä¸ä¸ªæ大çåºå«ãå½ç©çå åç¨å®æ¶ï¼Rediså¯ä»¥å°ä¸äºå¾ä¹ 没ç¨å°çvalue交æ¢å°ç£çãRedisåªä¼ç¼åææçkeyçä¿¡æ¯ï¼å¦æRedisåç°å åç使ç¨éè¶ è¿äºæä¸ä¸ªéå¼ï¼å°è§¦åswapçæä½ï¼Redisæ ¹æ®âswappability = age*log(size_in_memory)â计ç®åºåªäºkey对åºçvalueéè¦swapå°ç£çãç¶ååå°è¿äºkey对åºçvalueæä¹ åå°ç£çä¸ï¼åæ¶å¨å åä¸æ¸ é¤ãè¿ç§ç¹æ§ä½¿å¾Rediså¯ä»¥ä¿æè¶ è¿å ¶æºå¨æ¬èº«å å大å°çæ°æ®ãå½ç¶ï¼æºå¨æ¬èº«çå åå¿ é¡»è¦è½å¤ä¿æææçkeyï¼æ¯ç«è¿äºæ°æ®æ¯ä¸ä¼è¿è¡swapæä½çãåæ¶ç±äºRediså°å åä¸çæ°æ®swapå°ç£çä¸çæ¶åï¼æä¾æå¡ç主线ç¨åè¿è¡swapæä½çå线ç¨ä¼å ±äº«è¿é¨åå åï¼æ以å¦ææ´æ°éè¦swapçæ°æ®ï¼Rediså°é»å¡è¿ä¸ªæä½ï¼ç´å°å线ç¨å®æswapæä½åæå¯ä»¥è¿è¡ä¿®æ¹ãå½ä»Redisä¸è¯»åæ°æ®çæ¶åï¼å¦æ读åçkey对åºçvalueä¸å¨å åä¸ï¼é£ä¹Rediså°±éè¦ä»swapæ件ä¸å è½½ç¸åºæ°æ®ï¼ç¶ååè¿åç»è¯·æ±æ¹ã è¿éå°±åå¨ä¸ä¸ªI/O线ç¨æ± çé®é¢ãå¨é»è®¤çæ åµä¸ï¼Redisä¼åºç°é»å¡ï¼å³å®æææçswapæ件å è½½åæä¼ç¸åºãè¿ç§çç¥å¨å®¢æ·ç«¯çæ°éè¾å°ï¼è¿è¡æ¹éæä½çæ¶åæ¯è¾åéãä½æ¯å¦æå°Redisåºç¨å¨ä¸ä¸ªå¤§åçç½ç«åºç¨ç¨åºä¸ï¼è¿æ¾ç¶æ¯æ æ³æ»¡è¶³å¤§å¹¶åçæ åµçãæ以Redisè¿è¡æ们设置I/O线ç¨æ± ç大å°ï¼å¯¹éè¦ä»swapæ件ä¸å è½½ç¸åºæ°æ®ç读å请æ±è¿è¡å¹¶åæä½ï¼åå°é»å¡çæ¶é´ã
对äºåRedisåMemcachedè¿ç§åºäºå åçæ°æ®åºç³»ç»æ¥è¯´ï¼å å管ççæçé«ä½æ¯å½±åç³»ç»æ§è½çå ³é®å ç´ ãä¼ ç»Cè¯è¨ä¸çmalloc/freeå½æ°æ¯æ常ç¨çåé åéæ¾å åçæ¹æ³ï¼ä½æ¯è¿ç§æ¹æ³åå¨çå¾å¤§ç缺é·ï¼é¦å ï¼å¯¹äºå¼å人åæ¥è¯´ä¸å¹é çmallocåfree容æé æå åæ³é²ï¼å ¶æ¬¡é¢ç¹è°ç¨ä¼é æ大éå åç¢çæ æ³åæ¶éæ°å©ç¨ï¼éä½å åå©ç¨çï¼æåä½ä¸ºç³»ç»è°ç¨ï¼å ¶ç³»ç»å¼éè¿è¿å¤§äºä¸è¬å½æ°è°ç¨ãæ以ï¼ä¸ºäºæé«å åç管çæçï¼é«æçå å管çæ¹æ¡é½ä¸ä¼ç´æ¥ä½¿ç¨malloc/freeè°ç¨ãRedisåMemcachedå使ç¨äºèªèº«è®¾è®¡çå å管çæºå¶ï¼ä½æ¯å®ç°æ¹æ³åå¨å¾å¤§çå·®å¼ï¼ä¸é¢å°ä¼å¯¹ä¸¤è çå å管çæºå¶åå«è¿è¡ä»ç»ã
Memcachedé»è®¤ä½¿ç¨Slab Allocationæºå¶ç®¡çå åï¼å ¶ä¸»è¦ææ³æ¯æç §é¢å è§å®ç大å°ï¼å°åé çå ååå²æç¹å®é¿åº¦çå以åå¨ç¸åºé¿åº¦çkey-valueæ°æ®è®°å½ï¼ä»¥å®å ¨è§£å³å åç¢çé®é¢ãSlab Allocationæºå¶åªä¸ºåå¨å¤é¨æ°æ®è设计ï¼ä¹å°±æ¯è¯´ææçkey-valueæ°æ®é½åå¨å¨Slab Allocationç³»ç»éï¼èMemcachedçå ¶å®å å请æ±åéè¿æ®éçmalloc/freeæ¥ç³è¯·ï¼å 为è¿äºè¯·æ±çæ°éåé¢çå³å®äºå®ä»¬ä¸ä¼å¯¹æ´ä¸ªç³»ç»çæ§è½é æå½±åSlab Allocationçåçç¸å½ç®åã å¦å¾æ示ï¼å®é¦å ä»æä½ç³»ç»ç³è¯·ä¸å¤§åå åï¼å¹¶å°å ¶åå²æåç§å°ºå¯¸çåChunkï¼å¹¶æ尺寸ç¸åçååæç»Slab Classãå ¶ä¸ï¼Chunkå°±æ¯ç¨æ¥åå¨key-valueæ°æ®çæå°åä½ãæ¯ä¸ªSlab Classç大å°ï¼å¯ä»¥å¨Memcachedå¯å¨çæ¶åéè¿å¶å®Growth Factoræ¥æ§å¶ãåå®å¾ä¸Growth Factorçåå¼ä¸º1.ï¼å¦æ第ä¸ç»Chunkç大å°ä¸ºä¸ªåèï¼ç¬¬äºç»Chunkç大å°å°±ä¸ºä¸ªåèï¼ä¾æ¤ç±»æ¨ã
å½Memcachedæ¥æ¶å°å®¢æ·ç«¯åéè¿æ¥çæ°æ®æ¶é¦å ä¼æ ¹æ®æ¶å°æ°æ®ç大å°éæ©ä¸ä¸ªæåéçSlab Classï¼ç¶åéè¿æ¥è¯¢Memcachedä¿åçç该Slab Classå 空é²Chunkçå表就å¯ä»¥æ¾å°ä¸ä¸ªå¯ç¨äºåå¨æ°æ®çChunkãå½ä¸æ¡æ°æ®åºè¿ææè 丢å¼æ¶ï¼è¯¥è®°å½æå ç¨çChunkå°±å¯ä»¥åæ¶ï¼éæ°æ·»å å°ç©ºé²å表ä¸ãä»ä»¥ä¸è¿ç¨æ们å¯ä»¥çåºMemcachedçå å管çå¶æçé«ï¼èä¸ä¸ä¼é æå åç¢çï¼ä½æ¯å®æ大ç缺ç¹å°±æ¯ä¼å¯¼è´ç©ºé´æµªè´¹ãå 为æ¯ä¸ªChunké½åé äºç¹å®é¿åº¦çå å空é´ï¼æ以åé¿æ°æ®æ æ³å åå©ç¨è¿äºç©ºé´ãå¦å¾ æ示ï¼å°ä¸ªåèçæ°æ®ç¼åå°ä¸ªåèçChunkä¸ï¼å©ä½ç个åè就浪费æäºã
Redisçå å管ç主è¦éè¿æºç ä¸zmalloc.håzmalloc.c两个æ件æ¥å®ç°çãRedis为äºæ¹ä¾¿å åç管çï¼å¨åé ä¸åå åä¹åï¼ä¼å°è¿åå åç大å°åå ¥å ååç头é¨ãå¦å¾æ示ï¼real_ptræ¯redisè°ç¨mallocåè¿åçæéãrediså°å ååç大å°sizeåå ¥å¤´é¨ï¼sizeæå æ®çå å大å°æ¯å·²ç¥çï¼ä¸ºsize_tç±»åçé¿åº¦ï¼ç¶åè¿året_ptrãå½éè¦éæ¾å åçæ¶åï¼ret_ptrè¢«ä¼ ç»å å管çç¨åºãéè¿ret_ptrï¼ç¨åºå¯ä»¥å¾å®¹æçç®åºreal_ptrçå¼ï¼ç¶åå°real_pträ¼ ç»freeéæ¾å åã
Rediséè¿å®ä¹ä¸ä¸ªæ°ç»æ¥è®°å½ææçå ååé æ åµï¼è¿ä¸ªæ°ç»çé¿åº¦ä¸ºZMALLOC_MAX_ALLOC_STATãæ°ç»çæ¯ä¸ä¸ªå ç´ ä»£è¡¨å½åç¨åºæåé çå ååç个æ°ï¼ä¸å ååç大å°ä¸ºè¯¥å ç´ çä¸æ ãå¨æºç ä¸ï¼è¿ä¸ªæ°ç»ä¸ºzmalloc_allocationsãzmalloc_allocations[]代表已ç»åé çé¿åº¦ä¸ºbytesçå ååç个æ°ãzmalloc.cä¸æä¸ä¸ªéæåéused_memoryç¨æ¥è®°å½å½ååé çå åæ»å¤§å°ãæ以ï¼æ»çæ¥çï¼Rediséç¨çæ¯å è£ çmallc/freeï¼ç¸è¾äºMemcachedçå å管çæ¹æ³æ¥è¯´ï¼è¦ç®åå¾å¤ã
3ãæ°æ®æä¹ åæ¯æ
Redisè½ç¶æ¯åºäºå åçåå¨ç³»ç»ï¼ä½æ¯å®æ¬èº«æ¯æ¯æå åæ°æ®çæä¹ åçï¼èä¸æä¾ä¸¤ç§ä¸»è¦çæä¹ åçç¥ï¼RDBå¿«ç §åAOFæ¥å¿ãèmemcachedæ¯ä¸æ¯ææ°æ®æä¹ åæä½çã
1ï¼RDBå¿«ç §
Redisæ¯æå°å½åæ°æ®çå¿«ç §åæä¸ä¸ªæ°æ®æ件çæä¹ åæºå¶ï¼å³RDBå¿«ç §ãä½æ¯ä¸ä¸ªæç»åå ¥çæ°æ®åºå¦ä½çæå¿«ç §å¢ï¼Redisåå©äºforkå½ä»¤çcopy on writeæºå¶ãå¨çæå¿«ç §æ¶ï¼å°å½åè¿ç¨forkåºä¸ä¸ªåè¿ç¨ï¼ç¶åå¨åè¿ç¨ä¸å¾ªç¯ææçæ°æ®ï¼å°æ°æ®åæ为RDBæ件ãæ们å¯ä»¥éè¿Redisçsaveæ令æ¥é ç½®RDBå¿«ç §çæçæ¶æºï¼æ¯å¦é ç½®åéå°±çæå¿«ç §ï¼ä¹å¯ä»¥é ç½®æ次åå ¥å°±çæå¿«ç §ï¼ä¹å¯ä»¥å¤ä¸ªè§åä¸èµ·å®æ½ãè¿äºè§åçå®ä¹å°±å¨Redisçé ç½®æ件ä¸ï¼ä½ ä¹å¯ä»¥éè¿RedisçCONFIG SETå½ä»¤å¨Redisè¿è¡æ¶è®¾ç½®è§åï¼ä¸éè¦éå¯Redisã
RedisçRDBæ件ä¸ä¼åæï¼å ä¸ºå ¶åæä½æ¯å¨ä¸ä¸ªæ°è¿ç¨ä¸è¿è¡çï¼å½çæä¸ä¸ªæ°çRDBæ件æ¶ï¼Redisçæçåè¿ç¨ä¼å å°æ°æ®åå°ä¸ä¸ªä¸´æ¶æ件ä¸ï¼ç¶åéè¿ååæ§renameç³»ç»è°ç¨å°ä¸´æ¶æ件éå½å为RDBæ件ï¼è¿æ ·å¨ä»»ä½æ¶ååºç°æ éï¼RedisçRDBæ件é½æ»æ¯å¯ç¨çãåæ¶ï¼RedisçRDBæ件ä¹æ¯Redis主ä»åæ¥å é¨å®ç°ä¸çä¸ç¯ãRDBæä»çä¸è¶³ï¼å°±æ¯ä¸æ¦æ°æ®åºåºç°é®é¢ï¼é£ä¹æ们çRDBæ件ä¸ä¿åçæ°æ®å¹¶ä¸æ¯å ¨æ°çï¼ä»ä¸æ¬¡RDBæ件çæå°Redisåæºè¿æ®µæ¶é´çæ°æ®å ¨é¨ä¸¢æäºãå¨æäºä¸å¡ä¸ï¼è¿æ¯å¯ä»¥å¿åçã
2ï¼AOFæ¥å¿
AOFæ¥å¿çå ¨ç§°æ¯append only fileï¼å®æ¯ä¸ä¸ªè¿½å åå ¥çæ¥å¿æ件ãä¸ä¸è¬æ°æ®åºçbinlogä¸åçæ¯ï¼AOFæ件æ¯å¯è¯å«ç纯ææ¬ï¼å®çå 容就æ¯ä¸ä¸ªä¸ªçRedisæ åå½ä»¤ãåªæé£äºä¼å¯¼è´æ°æ®åçä¿®æ¹çå½ä»¤æä¼è¿½å å°AOFæ件ãæ¯ä¸æ¡ä¿®æ¹æ°æ®çå½ä»¤é½çæä¸æ¡æ¥å¿ï¼AOFæ件ä¼è¶æ¥è¶å¤§ï¼æ以Redisåæä¾äºä¸ä¸ªåè½ï¼å«åAOF rewriteãå ¶åè½å°±æ¯éæ°çæä¸ä»½AOFæ件ï¼æ°çAOFæ件ä¸ä¸æ¡è®°å½çæä½åªä¼æä¸æ¬¡ï¼èä¸åä¸ä»½èæ件é£æ ·ï¼å¯è½è®°å½äºå¯¹åä¸ä¸ªå¼çå¤æ¬¡æä½ãå ¶çæè¿ç¨åRDB类似ï¼ä¹æ¯forkä¸ä¸ªè¿ç¨ï¼ç´æ¥éåæ°æ®ï¼åå ¥æ°çAOF临æ¶æ件ãå¨åå ¥æ°æ件çè¿ç¨ä¸ï¼ææçåæä½æ¥å¿è¿æ¯ä¼åå°åæ¥èçAOFæ件ä¸ï¼åæ¶è¿ä¼è®°å½å¨å åç¼å²åºä¸ãå½éå®æä½å®æåï¼ä¼å°ææç¼å²åºä¸çæ¥å¿ä¸æ¬¡æ§åå ¥å°ä¸´æ¶æ件ä¸ãç¶åè°ç¨ååæ§çrenameå½ä»¤ç¨æ°çAOFæ件å代èçAOFæ件ã
AOFæ¯ä¸ä¸ªåæ件æä½ï¼å ¶ç®çæ¯å°æä½æ¥å¿åå°ç£çä¸ï¼æ以å®ä¹åæ ·ä¼éå°æ们ä¸é¢è¯´çåæä½çæµç¨ãå¨Redisä¸å¯¹AOFè°ç¨writeåå ¥åï¼éè¿appendfsyncé项æ¥æ§å¶è°ç¨fsyncå°å ¶åå°ç£çä¸çæ¶é´ï¼ä¸é¢appendfsyncçä¸ä¸ªè®¾ç½®é¡¹ï¼å®å ¨å¼ºåº¦éæ¸å强ã
appendfsync no å½è®¾ç½®appendfsync为noçæ¶åï¼Redisä¸ä¼ä¸»å¨è°ç¨fsyncå»å°AOFæ¥å¿å 容åæ¥å°ç£çï¼æ以è¿ä¸åå°±å®å ¨ä¾èµäºæä½ç³»ç»çè°è¯äºã对大å¤æ°Linuxæä½ç³»ç»ï¼æ¯æ¯ç§è¿è¡ä¸æ¬¡fsyncï¼å°ç¼å²åºä¸çæ°æ®åå°ç£çä¸ã
appendfsync everysec å½è®¾ç½®appendfsync为everysecçæ¶åï¼Redisä¼é»è®¤æ¯éä¸ç§è¿è¡ä¸æ¬¡fsyncè°ç¨ï¼å°ç¼å²åºä¸çæ°æ®åå°ç£çãä½æ¯å½è¿ä¸æ¬¡çfsyncè°ç¨æ¶é¿è¶ è¿1ç§æ¶ãRedisä¼éå延è¿fsyncççç¥ï¼åçä¸ç§éãä¹å°±æ¯å¨ä¸¤ç§ååè¿è¡fsyncï¼è¿ä¸æ¬¡çfsyncå°±ä¸ç®¡ä¼æ§è¡å¤é¿æ¶é´é½ä¼è¿è¡ãè¿æ¶åç±äºå¨fsyncæ¶æ件æ述符ä¼è¢«é»å¡ï¼æ以å½åçåæä½å°±ä¼é»å¡ãæ以ç»è®ºå°±æ¯ï¼å¨ç»å¤§å¤æ°æ åµä¸ï¼Redisä¼æ¯éä¸ç§è¿è¡ä¸æ¬¡fsyncãå¨æåçæ åµä¸ï¼ä¸¤ç§éä¼è¿è¡ä¸æ¬¡fsyncæä½ãè¿ä¸æä½å¨å¤§å¤æ°æ°æ®åºç³»ç»ä¸è¢«ç§°ä¸ºgroup commitï¼å°±æ¯ç»åå¤æ¬¡åæä½çæ°æ®ï¼ä¸æ¬¡æ§å°æ¥å¿åå°ç£çã
appednfsync always å½è®¾ç½®appendfsync为alwaysæ¶ï¼æ¯ä¸æ¬¡åæä½é½ä¼è°ç¨ä¸æ¬¡fsyncï¼è¿æ¶æ°æ®æ¯æå®å ¨çï¼å½ç¶ï¼ç±äºæ¯æ¬¡é½ä¼æ§è¡fsyncï¼æä»¥å ¶æ§è½ä¹ä¼åå°å½±åã
对äºä¸è¬æ§çä¸å¡éæ±ï¼å»ºè®®ä½¿ç¨RDBçæ¹å¼è¿è¡æä¹ åï¼åå æ¯RDBçå¼é并ç¸æ¯AOFæ¥å¿è¦ä½å¾å¤ï¼å¯¹äºé£äºæ æ³å¿æ°æ®ä¸¢å¤±çåºç¨ï¼å»ºè®®ä½¿ç¨AOFæ¥å¿ã
4ãé群管ççä¸å
Memcachedæ¯å ¨å åçæ°æ®ç¼å²ç³»ç»ï¼Redisè½ç¶æ¯ææ°æ®çæä¹ åï¼ä½æ¯å ¨å åæ¯ç«ææ¯å ¶é«æ§è½çæ¬è´¨ãä½ä¸ºåºäºå åçåå¨ç³»ç»æ¥è¯´ï¼æºå¨ç©çå åç大å°å°±æ¯ç³»ç»è½å¤å®¹çº³çæ大æ°æ®éãå¦æéè¦å¤ççæ°æ®éè¶ è¿äºåå°æºå¨çç©çå å大å°ï¼å°±éè¦æ建åå¸å¼é群æ¥æ©å±åå¨è½åã
Memcachedæ¬èº«å¹¶ä¸æ¯æåå¸å¼ï¼å æ¤åªè½å¨å®¢æ·ç«¯éè¿åä¸è´æ§åå¸è¿æ ·çåå¸å¼ç®æ³æ¥å®ç°Memcachedçåå¸å¼åå¨ãä¸å¾ç»åºäºMemcachedçåå¸å¼åå¨å®ç°æ¶æãå½å®¢æ·ç«¯åMemcachedé群åéæ°æ®ä¹åï¼é¦å ä¼éè¿å ç½®çåå¸å¼ç®æ³è®¡ç®åºè¯¥æ¡æ°æ®çç®æ èç¹ï¼ç¶åæ°æ®ä¼ç´æ¥åéå°è¯¥èç¹ä¸åå¨ãä½å®¢æ·ç«¯æ¥è¯¢æ°æ®æ¶ï¼åæ ·è¦è®¡ç®åºæ¥è¯¢æ°æ®æå¨çèç¹ï¼ç¶åç´æ¥å该èç¹åéæ¥è¯¢è¯·æ±ä»¥è·åæ°æ®ã
ç¸è¾äºMemcachedåªè½éç¨å®¢æ·ç«¯å®ç°åå¸å¼åå¨ï¼Redisæ´ååäºå¨æå¡å¨ç«¯æ建åå¸å¼åå¨ãææ°çæ¬çRediså·²ç»æ¯æäºåå¸å¼åå¨åè½ãRedis Clusteræ¯ä¸ä¸ªå®ç°äºåå¸å¼ä¸å 许åç¹æ éçRedisé«çº§çæ¬ï¼å®æ²¡æä¸å¿èç¹ï¼å ·æ线æ§å¯ä¼¸ç¼©çåè½ãä¸å¾ç»åºRedis Clusterçåå¸å¼åå¨æ¶æï¼å ¶ä¸èç¹ä¸èç¹ä¹é´éè¿äºè¿å¶åè®®è¿è¡éä¿¡ï¼èç¹ä¸å®¢æ·ç«¯ä¹é´éè¿asciiåè®®è¿è¡éä¿¡ãå¨æ°æ®çæ¾ç½®çç¥ä¸ï¼Redis Clusterå°æ´ä¸ªkeyçæ°å¼ååæ个åå¸æ§½ï¼æ¯ä¸ªèç¹ä¸å¯ä»¥åå¨ä¸ä¸ªæå¤ä¸ªåå¸æ§½ï¼ä¹å°±æ¯è¯´å½åRedis Clusteræ¯æçæ大èç¹æ°å°±æ¯ãRedis Cluster使ç¨çåå¸å¼ç®æ³ä¹å¾ç®åï¼crc( key ) % HASH_SLOTS_NUMBERã
为äºä¿è¯åç¹æ éä¸çæ°æ®å¯ç¨æ§ï¼Redis Clusterå¼å ¥äºMasterèç¹åSlaveèç¹ãå¨Redis Clusterä¸ï¼æ¯ä¸ªMasterèç¹é½ä¼æ对åºç两个ç¨äºåä½çSlaveèç¹ãè¿æ ·å¨æ´ä¸ªé群ä¸ï¼ä»»æ两个èç¹çå®æºé½ä¸ä¼å¯¼è´æ°æ®çä¸å¯ç¨ãå½Masterèç¹éåºåï¼é群ä¼èªå¨éæ©ä¸ä¸ªSlaveèç¹æ为æ°çMasterèç¹ã
Redis慢查询日志(Slow Log)详解
慢查询日志主要用于记录Redis实例中执行时间超过指定阈值的命令。它的码日使用场景包括对Redis实例性能监控与问题定位,有助于快速识别并优化那些执行效率低下的码日Redis命令。
慢查询日志的码日rpcx系统源码相关配置主要有:slowlog-log-slower-than,表示执行时间超过此值(单位为毫秒)的码日命令会被记录;slowlog-max-len,表示日志最多保存的码日Kicad 源码命令条数,遵循先进先出原则。码日
配置慢查询日志的码日方式包括在redis.conf文件中设置,或通过动态配置命令CONFIG SET进行调整,码日重启Redis实例生效。码日
通过SLOWLOG GET命令可以获取最新count条慢查询日志,码日不指定count时默认返回条记录。码日利用SLOWLOG LEN命令可以查询日志长度,码日quickcut源码SLOWLOG RESET命令则用于清空日志内容。码日
慢查询日志的码日获取与分析可以结合其他命令如GREP、LIMIT等进行,tscancode源码实现更精确的日志过滤和分析。
文章深入浅出地介绍了慢查询日志的原理,包括其数据结构和慢日志记录的pdown源码调用链分析。通过理解这些原理和源码版本(以6.2.5为例),读者能够全面掌握慢查询日志的实现机制。
慢查询日志是Redis性能调优的重要工具,合理配置它可以帮助快速定位并优化Redis实例中的慢查询问题,提高系统整体性能。综上所述,慢查询日志的使用、配置、命令操作以及基本原理解析,对于理解和利用Redis性能监控工具提供了全面的指导。
å°åºå¦ä½å¨springä¸ä½¿ç¨redis
1. Redis使ç¨åºæ¯
Redisæ¯ä¸ä¸ªå¼æºç使ç¨ANSI Cè¯è¨ç¼åãæ¯æç½ç»ãå¯åºäºå å亦å¯æä¹ åçæ¥å¿åãKey-Valueæ°æ®åºï¼å¹¶æä¾å¤ç§è¯è¨çAPIã
æ们é½ç¥éï¼å¨æ¥å¸¸çåºç¨ä¸ï¼æ°æ®åºç¶é¢æ¯æ容æåºç°çãæ°æ®é太大åé¢ç¹çæ¥è¯¢ï¼ç±äºç£çIOæ§è½çå±éæ§ï¼å¯¼è´é¡¹ç®çæ§è½è¶æ¥è¶ä½ã
è¿æ¶åï¼åºäºå åçç¼åæ¡æ¶ï¼å°±è½è§£å³æ们å¾å¤é®é¢ãä¾å¦Memcacheï¼Redisçãå°ä¸äºé¢ç¹ä½¿ç¨çæ°æ®æ¾å ¥ç¼å读åï¼å¤§å¤§éä½äºæ°æ®åºçè´æ ãæåäºç³»ç»çæ§è½ã
å ¶å®ï¼å¯¹äºhibernateçäºçº§ç¼åï¼æ¯åæ ·çéçãå©ç¨å åé«éç读åé度ï¼æ¥è§£å³ç¡¬ççç¶é¢ã
2. é 置使ç¨redis
é¦å ï¼æ们éè¦å¼å ¥åºæ¬çjarå ãmavenä¸çåºæ¬å¼ç¨å¦ä¸ï¼
ãããã<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.6.2</version>
</dependency>
ç¶åï¼å¨applicationContextä¸é ç½®å¦ä¸:
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${ redis.maxIdle}" />
<property name="maxTotal" value="${ redis.maxActive}" />
<property name="maxWaitMillis" value="${ redis.maxWait}" />
<property name="testOnBorrow" value="${ redis.testOnBorrow}" />
</bean>
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${ redis.host}" p:port="${ redis.port}" p:password="${ redis.pass}"
p:pool-config-ref="poolConfig" />
<bean id="stringSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<!-- å¼å¯äºå¡ï¼å¯ä»¥éè¿transcational注解æ§å¶ -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="keySerializer" ref="stringSerializer" />
<property name="enableTransactionSupport" value="true" />
</bean>
对äºhibernateçé ç½®å¯ç¥ï¼ç¬¬ä¸ä¸ªpoolconfigæ¯å¯¹è¿æ¥æ± çé ç½®ãå æ¬æ大è¿æ¥æ°ï¼éåæ°ï¼åæ´»æ¶é´ï¼æ大çå¾ æ¶é´ççï¼è¿æä¸äºé¢å¤çé ç½®ï¼è¯·ç´æ¥ç¹å»JedisPoolConfigç±»æºç ï¼è¿è¡æ¥çã
è¿äºé ç½®çææå¦æä¸æç½çè¯ï¼ä¸å®è¦å»æ线ç¨æ± 好好å¦ä¹ ä¸ã
第ä¸ä¸ªé ç½®æ¯è¿æ¥å·¥åï¼é¡¾åæä¹ï¼æåºæ¬ç使ç¨ä¸å®æ¯å¯¹è¿æ¥çæå¼åå ³éãæ们éè¦ä¸ºå ¶é ç½®redisæå¡å¨çè´¦æ·å¯ç ï¼ç«¯å£å·ãï¼è¿éè¿å¯ä»¥é ç½®æ°æ®åºçindexï¼ä½æ¯æ使ç¨æ¶åä¸ç´ä½¿ç¨redisçé»è®¤æ°æ®åºï¼ä¹å°±æ¯ç¬¬0个ï¼
æåä¸ä¸ªé ç½®ç¹å«éè¦ãè¿ä¸ªç±»ä¼¼äºspringæä¾çHibernateDaoSupportã
æ¥ä¸æ¥ï¼å ¨é¨è®²è§£é½å°å´ç»è¿ä¸ªç±»å±å¼ã
3. RedisTemplateç使ç¨
è¿ä¸ªç±»ä½ä¸ºä¸ä¸ªæ¨¡çç±»ï¼æä¾äºå¾å¤å¿«é使ç¨redisçapiï¼èä¸éè¦èªå·±æ¥ç»´æ¤è¿æ¥ï¼äºå¡ã
æåçæ¶åï¼æå建çBaseRedisDaoæ¯ç»§æ¿èªè¿ä¸ªç±»çã继æ¿ç好å¤æ¯æçæ¯ä¸ªDaoä¸ï¼é½å¯ä»¥èªç±çæ§å¶åºååå¨ï¼èªç±çæ§å¶èªå·±æ¯å¦éè¦äºå¡ï¼è¿ä¸ªå ä¸éè¦äºè§£ï¼è·çæç®åçè¿ç§é ç½®æ¹æ³æ¥å³å¯ã
templateæä¾äºä¸ç³»åçoperation,æ¯å¦valueOperation,HashOperation,ListOperation,SetOperationçï¼ç¨æ¥æä½ä¸åæ°æ®ç±»åçRedisã
并ä¸ï¼RedisTemplateè¿æä¾äºå¯¹åºç*OperationsEditorï¼ç¨æ¥éè¿RedisTemplateç´æ¥æ³¨å ¥å¯¹åºçOperationãæ们ææ¶ä¸è®²è¿ä¸ªã
对äºä¸é¢çtest1æ¹æ³ï¼æ们ææ¶ä¸ç¨èèï¼å äºè§£éè¿RedisTemplateæ¥ä½¿ç¨connectionæä½Redisã
Test代ç å¦ä¸ï¼
package cn.test.spjedis;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.cn.redis2.dao.IncrDao;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestRedis {
@Resource(name = "redisTemplate")
private RedisTemplate<String, String> template; // inject the template as ListOperations
//è³äºè¿ä¸ªä¸ºä»ä¹å¯ä»¥æ³¨å ¥ãéè¦åèAbstractBeanFactory doGetBean
//super.setValue(((RedisOperations) value).opsForValue());å°±è¿ä¸è¡ä»£ç ä¾é ä¸ä¸ªeditor
@Resource(name = "redisTemplate")
private ValueOperations<String, Object> vOps;
public void testSet(){
template.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
byte [] key = "tempkey".getBytes();
byte[] value = "tempvalue".getBytes();
connection.set(key, value);
return true;
}
});
}
public void testSet1(){
vOps.set("tempkey", "tempvalue");
}
@Autowired
private IncrDao incr;
@Test
public void addLink() {
System.out.println(incr.incr());
System.out.println(incr.get());
}
}
è¿ä¸ªæ¯å¯¹Stringç±»åæå ¥ç两个æµè¯ãtestæ¹æ³ä¸ï¼ä½¿ç¨äºæ¨¡çç±»æ交åè°(RedisCallBack)çæ¹æ³æ¥ä½¿ç¨jedis connectionæä½æ°æ®ãè¿ä¸é¨åï¼æ没æä¼¼æ¾ç¸è¯å¢ï¼
HibernateTemplateçHibernateCallbackï¼ä»¥åHibernate Sessionç±»ä¸çdoWork以ådoReturningWorkæ¹æ³ï¼é½æ¯ä½¿ç¨äºè¿æ ·çæºå¶ï¼æ¹ä¾¿å¯¹äºè¿æ¥æè sessionçç»ä¸ç®¡çã
public int excuteHqlUpdate(final String hql,final Object ...params){
return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Integer>() {
@Override
@SuppressWarnings("unchecked")
public Integer doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(hql);
if (params != null) {
for (int i = 0; i < params.length; i++) {
queryObject.setParameter(i, params[i]);
}
}
return queryObject.executeUpdate();
}
});
}