ãããã¤ã³ã¿ã¼ããã Advent Calendar 2020ã®23æ¥ç®ã§ãã
ç¾æç¹ã§ã¯ææ°çã®Redis 6.0ã®Redis Clusterã«å¯¾ãã¦ãGoè¨èªã®ä»£è¡¨çãªRedisã¯ã©ã¤ã¢ã³ãã©ã¤ãã©ãªã§ããgo-redisããã¢ã¯ã»ã¹ããã¨ãã«ãæ§è½ãæ·±å»ãªã¬ãã«ã§å£åãã¾ããã ãã®è¨äºã§ã¯ãããã«ã¦ã§ã¢ãå©ç¨ããGoè¨èªã¢ããªã±ã¼ã·ã§ã³ã®æ§è½å£åã«é¢ããåé¡èª¿æ»ã®äºä¾ã¨ãã¦ããã®æ§è½å£åãä¿®æ£ããã¾ã§ã®è©±ãã¾ã¨ãã¾ããã
go-redisã¸ã®Pull Requestã¯https://github.com/go-redis/redis/pull/1355ã§ãã
ã¯ããã«
åå¹´ã»ã©åã®è«æã®ç· ãåãã«è¿½ããã¦ããããæ¥ãè©ä¾¡å®é¨ã®ããã«Redisã使ã£ãæç³»åãã¼ã¿ãã¼ã¹ã®ãããã¿ã¤ããéçºãã¦ãã¾ããã ãã³ããã¼ã¯ãã¼ã«ã§ãããã¿ã¤ãã®æ§è½ã測å®ããã¨ãããåä¸ã¤ã³ã¹ã¿ã³ã¹ã®Redisã«å¯¾ãã¦æ³å®ããçµæãå¾ããã¾ããã
ããã§ãææ°æã ã¨ãã¹ã±ã¼ã«ã¢ã¦ãæ§è½ãè©ä¾¡ããããã«ãè¤æ°ã®Redisã¤ã³ã¹ã¿ã³ã¹ã«ãã¼ã¿ãæ°´å¹³åå²å¯è½ãªRedis Clusterãå©ç¨ãã¦ãã¹ã«ã¼ããããè¨æ¸¬ãã¾ããã ã¨ããããä¿¡ãããããã¨ã«ãåä¸ã¤ã³ã¹ã¿ã³ã¹ã«å¯¾ããã¹ã«ã¼ãããããããã¯ã©ã¹ã¿åãããã¨ã§ããã£ã¦ã1/10åã»ã©ã¹ã«ã¼ããããä½ä¸ããçµæã¨ãªãã¾ããã
æåã¯ãåä¸ã¤ã³ã¹ã¿ã³ã¹ã¨Redisã¯ã©ã¹ã¿ã¨ã®å¦çã®å·®åã«çç®ãã¾ããã å®é¨ã§ã¯ãGoã¢ããªã±ã¼ã·ã§ã³ã¨Redisããã»ã¹ã®CPUãªã½ã¼ã¹ãå ¨ã使ãåãã¦ããªãã£ãããããããã¯ã¼ã¯I/Oã«é¢ããããã«ããã¯ã«ããããã¤ãã¾ããã
Redisã¯ã©ã¹ã¿ã¯ãæ°´å¹³åå²ã®ããã«ãã³ãã³ãã対象ã¨ãããã¼ã¨ãã¼ãã対å¿ãããå¿ è¦ãããã¾ãã ãã¼ã¨ãã¼ãã®å¯¾å¿ãç´æ¥ç®¡çããããã§ã¯ãªãããã¼ãã®å¢æ¸ã«å¯¾å¿ããããããã«ãããã·ã¥ã¹ãããã¨ããåºå®æ°ã®ã¹ããããå©ç¨ããã¾ã*1ã ãã¼ããèªèº«ã«å²ãå½ã¦ãããããã·ã¥ã¹ãããã«å¯¾å¿ããªããã¼ãå«ãã³ãã³ããåä¿¡ããã¨ãã«ãã¯ã©ã¤ã¢ã³ãã¸ãªãã¤ã¬ã¯ãããããã«æç¤ºãã¾ãã ãªãã¹ããªãã¤ã¬ã¯ããããªãã»ããæã¾ãããããgo-redisã¯ãã¼ãã©ã®ããã·ã¥ã¹ãããã«å±ããããè¨ç®ããä¸ã§ãé©åãªãã¼ãã«æåããã³ãã³ããéä¿¡ãã¾ãã
Redis Clusteråããã䏿°ã«ã¹ã«ã¼ãããè½ã¡ãã⦠redisãã¤ãã©ã¤ã³å ã§ã¯ã©ã¤ã¢ã³ãå´ããã¼ã¨ããã·ã¥ã¹ãããã®ãããã³ã°ã«å¿ãã¦æ¯ãåãã¦ãå¦çã§è©°ã¾ã£ã¦ãã®ããª...
— ãããã (@yuuk1t) 2020å¹´6æ2æ¥
ã¯ã©ã¤ã¢ã³ãã«ãããã¼ã鏿ããã¾ãåããã«ãã³ãã³ãçºè¡ã®ãã³ã«ãªãã¤ã¬ã¯ããã¦ããã®ã§ã¯ãªããã¨ããããã¤ãã¾ããã ããããªãããgo-rediså ã§printãããã°ãã¦ãããªãã¤ã¬ã¯ãã観測ã§ãã¾ããã§ããã
ãã®ããã«ããã®æç¹ã§æã£ã¦ãç¥èããç´æã§ããããã¤ãã¦åé¡èª¿æ»ããã¦ãã試è¡é¯èª¤ã®åæ°ãå¢ãã¦ãçµå±é åããªãã¾ããã
ããã§ãæ¨æ¸¬ããã«ãè¨æ¸¬ãããã¨ã«ãã¾ããã
è¨æ¸¬ã®ããã«ãGoè¨èªæ¨æºã®ãã¬ã¼ã·ã³ã°ãã¼ã«ã§ããExecution tracerãå©ç¨ãã¾ããã
pprofã§åå¾ããçµæãgo tool trace
ã«é£ãããã¨ãgoroutineã®å®è¡ç¶æ³ãç¹ã«ã¡ã½ããã®å¼ã³åºãé¢ä¿ã¨ã¡ã½ããåä½ã®å®è¡æéãå¯è¦åã§ãã¾ãã
go tool traceã®åæçµæ
go tool trace
ã¯View TraceãGoroutine AnalysisãNetwork blocking profileãSynchronization blocking profileãSyscall blocking profileãScheduler latency profileãªã©ã®ãã¬ã¼ã¹ã®ãã¥ã¼ãããã¾ãã
次ã®ç»åã¯ãå®éã®ãããã¿ã¤ãã®åä½ãå¯è¦åããããã¥ã¼ã®ç¨®é¡ãã¨ã®çµæã§ãã
ãã¥ã¼ã«ãã£ã¦ã¯ãã¿ãããã®ããã«ããã¥ã¼ã®ä¸é¨ãæ¡å¤§ãã¦è¡¨ç¤ºãã¦ãã¾ãã
View Traceã¯ãGoroutineæ°ããã¼ãã¡ã¢ãªéãã¹ã¬ããæ°ãããã»ã¹ãã¨ã®GCåæ°ãã©ã®ã³ã¼ããå®è¡ããã¦ããããªã©ã®æéå¤åã表示ãã¾ãã
Goroutine Analysisã¯ããããã¡ã¤ã«æéã«å®è¡ãããgoroutineã®æ°ããgoroutineãèµ·åããã颿°ãã¨ããã¤ãå ¨ä½ã®å®è¡æéã®å²åã®éé ã«è¡¨ç¤ºãã¾ãã
Network blocking profoleã¯ããããã¯ã¼ã¯I/Oå¾ ã¡æéãã¡ã½ããã®å¼ã³åºãé¢ä¿ã¨ã¨ãã«è¡¨ç¤ºãã¾ãã
Synchornization blocking profileã¯ãæä»ããã¯ãªã©ã®åæããªããã£ãã«ããå¾ ã¡ã«å ¥ã£ãæéãã¡ã½ããã®å¼ã³åºãé¢ä¿ã¨ã¨ãã«è¡¨ç¤ºãã¾ãã
(Synchornization blocking profile)
Syscall blocking profileã¯ãOSã«ã¼ãã«ã«å¯¾ããã·ã¹ãã ã³ã¼ã«ã®ãããã¯æéãã¡ã½ããã®å¼ã³åºãé¢ä¿ã¨ã¨ãã«è¡¨ç¤ºãã¾ãã
Scheduler latency profileã¯ãGoã®å¦çç³»ã®ã¹ã±ã¸ã¥ã¼ã©ã®ã¹ã±ã¸ã¥ã¼ãªã³ã°é å»¶æéã表示ãã¾ãã
åãã¥ã¼ãã¿ãã¨ãgo-rediså ã®ãã¥ã¼ããã¯ã¹ããã¯ã¨ç»åã§ã¯è¦ãã¥ããã§ããRedisã®ãã¤ãã©ã¤ã³å¦çå ã®ãããã¯ã¼ã¯I/Oå¾ ã¡ãããã«ããã¯ã¨ãªã£ã¦ãããã¨ããããã¾ãã profileç³»ã®ãã¥ã¼ã§ã¯ãä¸ã®ç»åã§ã¯ç¯å²å¤ã«ãªã£ã¦ãã¾ãããèªåãæ¸ãã¦ããã¢ããªã±ã¼ã·ã§ã³ã®ã³ã¼ãã®ã¡ã½ããã表示ãããã®ã§ãã©ã¤ãã©ãªã®å é¨çãªå¦çã¨ç´ä»ãããã¨ãã§ãã¾ãã
ãã¥ã¼ããã¯ã¹ããã¯ã®èª¿æ»
ãã®ããã¯ã¯ä½ã®ããã«ã©ãã§å©ç¨ããã¦ããã®ã§ããããã
sync.Mutexã®å¼ã³åºãå
ã¯ãClusterClient.mapCmdsByNode -> ClusterClient.cmdSlot -> ClusterClient.cmdInfo -> cmdsInfoCache.Get -> internal.Once.Do ã®é ã¨ãªã£ã¦ãã¾ãã
mapCmdsByNodeã¯ããã¤ãã©ã¤ãã³ã°ã®ãã¼ã«é¢ããå¶ç´ã«ããããªãããã«ãé©åãªãã¼ãã«ã³ãã³ããæ¯ãåããããã«ããã¼ãã¨ã³ãã³ãã®å¯¾å¿ãçæãã¾ãã
ãã®ä¸é£ã®å¦çã®ä¸ã§ãã³ãã³ã弿°ã®ä¸ã®ãã¼ã®ä½ç½®ãç¥ãå¿
è¦ãããã¾ãã
go-redisã§ã¯COMMAND
ã³ãã³ããå©ç¨ãããã¨ã«ãããåçã«ã³ãã³ãã¨ãã¼ã®ä½ç½®ã®å¯¾å¿é¢ä¿ãåå¾ã§ãã¾ãã
ã³ãã³ãã¨ãã¼ã®ä½ç½®ã®å¯¾å¿é¢ä¿ã¯ãRedisã®ã³ã¼ãå
ã§éçã«æ±ºå®ããããããRedisãµã¼ãã«ã¢ã¯ã»ã¹ãããã³ã«ãåå¾ããå¿
è¦ã¯ããã¾ããã
ããã§ãCOMMAND
ã³ãã³ãã®çµæããã£ãã·ã¥ããã®ããcmdsInfoCacheã§ãã
ããããã¯ãè¤æ°ã®goroutineããCOMMAND
ã³ãã³ããRedisãµã¼ãã«æ®ºå°ããªãããã«ããã¥ã¼ããã¯ã¹ããã¯ãç²å¾ããã®ã¡ã«ãCOMMAND
ã³ãã³ããéä¿¡ãã¦ãã¾ãã
ãã®ãã¥ã¼ããã¯ã¹ããã¯ã®ç®æãããã«ããã¯ã¨ãããã¨ã¯ãCOMMAND
ã³ãã³ãããã£ãã·ã¥ã§ããã«ãæ¯åCOMMAND
ã³ãã³ããéä¿¡ãã¦ããã®ã§ã¯ãªããï¼ã¨çãã¾ããã
å®éã«ãprintãããã°ããã¨ããã¤ãã©ã¤ã³ãå®è¡ãããã³ã«ããããã«COMMAND
ã³ãã³ããéä¿¡ãã¦ãã¾ããã
ãªããã®ãããªãã¨ãèµ·ãã¦ããã®ããæ¢ã£ã¦ããã¨ãCOMMAND
ã³ãã³ãã®çµæãåå¾ããã¡ã½ãããã¨ã©ã¼ã¨ãã¦redis: got 7 elements in COMMAND reply, wanted 6
ãè¿ãã¦ãã¾ããhttps://github.com/go-redis/redis/blob/v7.2.0/cluster.go/#L1534-L1540ã
ãã®ã¨ã©ã¼ãä¸ä½ã®å¼ã³åºãå
ã«ä¼æ¬ããéç¨ã§ãã¨ã©ã¼ãç¡è¦ãããCOMMAND
ã³ãã³ãã®çµæãnilã¨ãã¦è¿å´ãã¦ãã¾ãããhttps://github.com/go-redis/redis/blob/v7.2.0/cluster.go/#L1546-L1549
ãã®èª¿æ»ã«ããããã£ãã·ã¥ã§ããã«ãæ¯åCOMMAND
ã³ãã³ããéä¿¡ãã¦ãããã¨ã確å®ãã¾ããã
ã¨ã©ã¼ã®åæã¨ä¿®æ£
åè¿°ã®ã¨ã©ã¼ã®çæå
ã¯ãCOMMAND
ã³ãã³ãã®çµæã®ãã¼ã¹å¦çã§ãããããã§ã¨ã©ã¼ã«ãªãã¨ãããã¨ã¯nãæå¾
ãã6ã§ã¯ãªãã£ããã¨ãæãã¾ãã
func commandInfoParser(rd *proto.Reader, n int64) (interface{}, error) { if n != 6 { return nil, fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 6", n) } # https://github.com/go-redis/redis/blob/v7.2.0/command.go/#L1936-L1939
ãã®nã®å¤ã¯ãCOMMAND
ã³ãã³ããåºåãããåã³ãã³ããã¨ã®ã¡ã¿æ
å ±ã®è¦ç´ æ°ãæãã¦ãã¾ãã
ããã¦ãRedis 6.0ããã¯ãã®è¦ç´ æ°ã6ãã7ã«å¢ãã¦ãã¾ãããhttps://github.com/redis/redis/commit/c5e717c637cbb1c80e1259560ebf995fb7920628
ãã®Redisæ¬ä½ã®å¤æ´ã«ãããå
ç¨ã®ã¨ã©ã¼ãçæãããããã«ãªã£ã¦ãã¾ããã
ãã®å¤æ´ã§COMMANDã³ãã³ãã®è¿å´ããè¦ç´ æ°ã6 -> 7ã«ãªã£ã¦ãã https://t.co/4n1I4Xk1et
— ãããã (@yuuk1t) 2020å¹´6æ4æ¥
ãã®ããã§ãgo-redisã® https://t.co/MTY2YIvxHS ã®ifæã§ã¨ã©ã¼ãè¿ãããã«ãªã£ã¦ããã¨ã©ã¼ã«ãªãã¨ãã£ãã·ã¥ãããªãããæ¯å204ã¨ã³ããªããredisã®ã³ãã³ããªã¹ããåå¾ãã¦ãã...
å®éã«ãã³ãã³ããå©ãã¦ç¢ºèªãã¦ã¿ã¾ãã Redis 5.0.8ã¯ã次ã®ããã«è¦ç´ æ°6ã¨ãªãã¾ããã
127.0.0.1:6379> COMMAND INFO xadd 1) 1) "xadd" 2) (integer) -5 3) 1) write 2) denyoom 3) random 4) fast 4) (integer) 1 5) (integer) 1 6) (integer) 1
䏿¹ã§ãRedis 6.0.1ã§ã¯ã次ã®ããã«è¦ç´ æ°ã7ã¨ãªãã¾ããã
127.0.0.1:6379> COMMAND INFO xadd 1) 1) "xadd" 2) (integer) -5 3) 1) write 2) denyoom 3) random 4) fast 4) (integer) 1 5) (integer) 1 6) (integer) 1 7) 1) @write 2) @stream 3) @fast
以ä¸ã«ãããã¨ã©ã¼ã®ä¿®æ£å 容ã¯ãè¦ç´ æ°7ã®ã±ã¼ã¹ã®å¯¾å¿ã追å ããã ãã ã¨ãããã¾ããã ä¿®æ£ã®çµæããããã¿ã¤ãã«ããã¦ãæ³å®ããã¹ã«ã¼ããããå¾ããã¨ãã§ãã¾ããã
æçµçã«ããã®ä¿®æ£å 容ãgo-redisã¸Pull Requestã¨ãã¦ææ¡ãã¦ãææ¡ãåãè¾¼ã¾ãã¾ããã
go-redisã®âã®åé¡ã解決ããPRãæããã https://t.co/mnsESAO66P
— ãããã (@yuuk1t) 2020å¹´6æ5æ¥
åè
- An Introduction to go tool trace
- golang でのデバッグに非常に便利な go tool trace - 理系学生日記
- go tool traceでgoroutineの実行状況を可視化する - ( ꒪⌓꒪) ゆるよろ日記
- RedisサーバのCPU負荷対策パターン - ゆううきブログ
ã¾ã¨ã
Redis 6.0ã®ã¯ã©ã¹ã¿ã«ããã¦ãgo-redisã§æ¥ç¶ããã¨ãã®æ·±å»ãªæ§è½å£åã«å¯¾ãã¦ãpprofãå©ç¨ãã¦ãããã«ããã¯ãçºè¦ããã½ã¼ã¹ã³ã¼ãã調æ»ããä¸ã§ãä¿®æ£ãã¾ããã ä»åã®åé¡ã¯ãRedis 6.0以éã®ã¯ã©ã¹ã¿ã«å¯¾ãã¦ãgo-redisããæ¥ç¶ããã¨å¿ ãçºçãããã®ã§ããã®ã§ãå°ããªä¿®æ£ã®ããã«ã¯ãæ½å¨çãªå½±é¿ç¯å²ã¯ãããªãã«å¤§ããã£ãããã«æãã¾ãã ãããä¿®æ£ã§ããã®ã§ãèªåã¨ãã¦ã¯æºè¶³æãå¾ã¾ããã
åã¯ãèªåãéçºããããã§ã¯ãªãæ¢åã®OSSã®ããã°ãæ¹åç¹ãçºè¦ãããã¨ãã©ããè¦æãªãããæ¢åã®OSSã«ããããæãããã¨ã«å¯¾ãã¦è¦ææèããã£ã¦ãã¾ãã å®éãPull Requestãæããé »åº¦ã¯ãé«ã å¹´ã«1,2åç¨åº¦ã§ãã OSSã®åé¡ãçºè¦ãã¦ä¿®æ£ããããæ¯ãå¸ãããã«æãããã人ã¯ãããããã½ããã¦ã§ã¢ã®åé¡ãçºè¦ããç®ãéãããã¦ããã®ã§ãããã
ç ç©¶ãé²ããä¸ã§ã¯ãå®é¨çµæãããããããã«ãã©ããã¦ãæå®ã®æ§è½ãã»ããã£ãããç ç©¶ææã®ä¸é¨ãä¸ã®ä¸ã§ä½¿ã£ã¦ãããããã«ã¯ãæ¢åã®OSSãæ¹åãããã¨ãå¿ è¦ã«ãªãã¾ãã ãã®ãããªç®çæèããé§åãããããã種ã®å¼·å¶åããã¾ãå©ç¨ãã¦ãè¦æãªãããOSSã³ãã¥ããã£ã¸å°ããã¤è²¢ç®ãã¦ããããã§ããã
æ¯ãè¿ã£ã¦ã¿ãã¨ããµã¼ãå´ã®APIã®ä»æ§å¤æ´ã«ã¯ã©ã¤ã¢ã³ãã©ã¤ãã©ãªã追å¾ã§ãã¦ããªãã£ãæ ã«çºçããåé¡ã¨ãããã¨ã«ãªãã¾ãã 仿§å¤æ´ãç°ãªãçµç¹ãå人ã管çããã¯ã©ã¤ã¢ã³ãã©ã¤ãã©ãªã¾ã§ã«åæ ãããã®ã¯ãã³ãã¥ãã±ã¼ã·ã§ã³ã®ã¬ãã«ã§ãä¸è¬çã«é£ããåé¡ã§ãã æ§è½ã®åé¡ã¨æããã¨ãCI/CDã®ããã»ã¹ã«æ§è½æ¸¬å®ããã¦ãç°å¸¸ãããã°éç¥ãããã¨ãä¸ã¤ã®æã§ãã ããããã©ã®ç¨åº¦é ããªãã°ãç°å¸¸ã¨ã¿ãªãã®ããæ§è½å¤ãè©ä¾¡ããã«ã¯ãCI/CDç°å¢ã§ä¸è²«ãããã¼ãã¦ã§ã¢ãªã½ã¼ã¹ãå©ç¨ãã¤ã¥ããªããã°ãªããªããæ§ã ãªã¢ã¯ã»ã¹ãã¿ã¼ã³ãèããããä¸ã§ãã©ã®ç¨åº¦ãã¹ãã±ã¼ã¹ãç¶²ç¾ ãã¹ãããªã©èãããã¨ã¯ããããããã¾ãã
ãã®ããã«ãã¡ãã£ã¨ãã工夫ã§ã¯è§£æ±ºãã¥ããåé¡ããç ç©¶éçºã§è§£æ±ºããåé¡ã¨æããã¨ããããããããããã¾ããã
*1:æ°´å¹³åå²ï¼ãã¼ãã£ã·ã§ãã³ã°ï¼ã«ããããã¼ãã®ãã¼ãã£ã·ã§ã³å²ãå½ã¦æ¦ç¥ã«ã¤ãã¦è©³ããã¯ããMartin Kleppmannè,æè¤å¤ªé ç£è¨³,çå·ç«å¸ 訳, ãã¼ã¿æåã¢ããªã±ã¼ã·ã§ã³ãã¶ã¤ã³ââä¿¡é ¼æ§ãæ¡å¼µæ§ãä¿å®æ§ã®é«ã忣ã·ã¹ãã è¨è¨ã®åç, 6.4.1.2 ãã¼ãã£ã·ã§ã³æ°ã®åºå®, ãªã©ã¤ãªã¼ã»ã¸ã£ãã³, 2019ããåç §ãã¦ãã ããã