ãã¼ã¨å¤ã®é£æ³é åã§ããDBMã®ã¤ã³ã¿ã¼ãã§ã¤ã¹ã§LRUã¬ã³ã¼ãåé¤æ©è½ä»ãã®ãã£ãã·ã¥æ©æ§ãå®è£ ãã¦ã¿ã話ã
æ å ±æè¡ã®æèã«ããã¦ããã£ãã·ã¥ï¼cacheï¼ã¨ã¯ãçæãããã¯åå¾ããããã®ã³ã¹ããé«ããã¼ã¿ãä¸æçã«ä¿åãã¦ããã¦ããããåå©ç¨ãããã¨ã«ãã£ã¦æ§è½ã®åä¸ãå³ãæ©æ§ã§ããããã£ãã·ã¥ã®ã¬ã³ã¼ãã¯ãªã³ã¡ã¢ãªã§ä¿æããã®ãä¸è¬çã§ããããã®å®¹éã«éããããããã£ãã·ã¥ä¸ã«ææã®ã¬ã³ã¼ãããªãå ´åã«ã¯ãã³ã¹ãã®ããããæ¬çªãã®å¦çãå試è¡ãããã¨ã§åããã¼ã¿ãçæã§ããã®ã§ããã¾ã使ãããªãã¬ã³ã¼ãã¯æ¶ãã¦ãåé¡ãªããéããã容éã®ãã£ãã·ã¥ä¸ã«ããã使ãããï¼ãããçã®é«ãï¼ã¬ã³ã¼ããæ®ããããã§ãªãã¬ã³ã¼ããç ´æ£ããã¨ããã®ãæ§è½ä¸éè¦ã«ãªãã
ããããTkrzwããã¼ã¹ã«ãããã¼ã¿ãã¼ã¹ãµã¼ãã¹ãå®è£ ãããããããªãããã®éã«ã¯ãè¦æ±ãããæ©è½è¦ä»¶ã¨éæ©è½è¦ä»¶ã«å¿ãã¦ãã¹ãã¬ã¼ã¸ï¼ãã¡ã¤ã«ããªã³ã¡ã¢ãªãï¼ã¨ãã¼ã¿æ§é ï¼ããã·ã¥ãã¼ãã«ã¨B+æ¨ã¨ã¹ããããªã¹ãï¼ãé¸ã¹ãã®ã¯å¤§ããªå¼·ã¿ã§ããããããã¨ã¯å¥ã«ããã£ãã·ã¥ãµã¼ãã¹ã¨ãã¦ã®éè¦ãèãããããã¢ããªã±ã¼ã·ã§ã³å´ããä¸è¦ãªã¬ã³ã¼ããåé¤ããå½ä»¤ãåºãç¶ããä»çµã¿ã«ããã¨ç ©éã«ãªããããä¸è¦ãªãã¼ã¿ã¯ãµã¼ãå´ã§å¤æãã¦æé»çã«åé¤ãã¦ãããæ¹ãæã¾ããããã£ãã·ã¥ãµã¼ãã¹ã¨ããå ´åã«ã¯æä½éãã¡ã¢ãªä½¿ç¨éãä¸å®ã«ä¿ã¤ããã®ä»çµã¿ãåããªããã°ãªããªãã
ä¸è¦ãªã¬ã³ã¼ããæ©æ¢°çã«å¤æããããã«ãåã¬ã³ã¼ãã«çåæéï¼TTL = Time To Liveï¼ã®ã¡ã¿ãã¼ã¿ãè¨å®ãããããéãããã®ãåé¤ããã¨ããæ¹æ³ããããå ·ä½çãªTTLå¤ã®è¨å®ã¯ã¬ã³ã¼ãã追å ããéã«ã¢ããªã±ã¼ã·ã§ã³å´ã§è¡ãããã®æ¹æ³ã®å©ç¹ã¯ãå¤ããã¦å©ç¨ä¾¡å¤ã®ãªããªã£ãã¬ã³ã¼ãããã£ãã·ã¥ä¸ã«èç©ããããåå©ç¨ããããããã®ãé²ãããã¨ã«ãªããæ¬ ç¹ã¯ãã¡ã¢ãªä½¿ç¨éãä¸å®ã«ããä¿è¨¼ããªããã¨ã§ãããå¥ã®ã¢ããã¼ãã¨ãã¦ããã£ãã·ã¥ä¸ã®ã¬ã³ã¼ãæ°ããã®ãµã¤ãºã®åè¨ã«ä¸éãè¨ãããããéããããå¤ãã¬ã³ã¼ãããæ¶ãã¨ããæ¹æ³ãããããã®æ¹å¼ã®å©ç¹ã¯ã¡ã¢ãªä½¿ç¨éãä¸å®ã«ãããã¨ãä¿è¨¼ããããã¨ã§ãããæ¬ ç¹ã¯ãå¤ãæ å ±ããã¤ã¾ã§ãæ®ãå¯è½æ§ããããã¨ã§ãããã¿ããªå¤§å¥½ãmemcachedã¯ãã®äºã¤ã¨ãããµãã¼ããã¦ããã®ã§ã使ãåæãã¨ã¦ãããã
ä»åå®è£ ãããã£ãã·ã¥DBMã§ã¯ãTTLæ¹å¼ã¯æ¡ç¨ãããã¬ã³ã¼ãæ°ã«ä¸éãè¨ããã ãã«ãããã¡ã¢ãªä½¿ç¨éãä¿è¨¼ããæ©è½ã ãã¯ãµã¼ãå´ãæ ã£ã¦ããªãã¨ãå®å¿ãã¦éç¨ãããã¨ãã§ããªããå¿ è¦ã§ããã°ãã¢ããªã±ã¼ã·ã§ã³å´ã®è²¬ä»»ã§åã¬ã³ã¼ãã«TTLãä»ä¸ããå¤ãã¬ã³ã¼ãã¯ç¡è¦ããããã«ãã¦ãããããããç ©éã«æããå ´åãTTLãæé»çã«ä»ä¸ããã©ããã¼ãæ¸ãã°ãããTTLæ¹å¼ã使ããããªãããä¸ã¤ã®çç±ã¯ãæ§è½ã®åé¡ã§ãããåã¬ã³ã¼ãã«TTLãä»ä¸ãããã¨ã«ãã空éå¹çã®æªåã¯æè©®4ãã¤ãã5ãã¤ãã§æ¸ãã®ã§å¤§ããåé¡ã§ã¯ãªããTTLãéããã¬ã³ã¼ããåé¤ããããã«ãã¼ã¿ãã¼ã¹å ¨ä½ã«ã¤ãã¬ã¼ã¿ãåãããåé¤äºå®æå»ãè¿ãé ã«ã¬ã³ã¼ãã並ã¹ããã¨ãå¿ è¦ã«ãªãã®ãåé¡ã§ãããã©ã¡ãã®æ¹æ³ãå®è£ ã¯ç°¡åã ããCPUè² è·ãã¡ã¢ãªä½¿ç¨éãå¢ããã¦ãã¾ãæ¬ ç¹ãããã
ãã¦ãã¿ã¤ã ã¹ã¿ã³ãã使ããã«ã¬ã³ã¼ãã®è¦ä¸è¦ãå¤æããããã®å ¸åçãªæ¹æ³ã¨ãã¦ãLRUåé¤ã¨ããæ¹å¼ãæãããããB+木のキャッシュの記事ã§ã説æããããæè¿ä½¿ãããã¬ã³ã¼ãã¯ã¾ã使ãããå¯è½æ§ãé«ãã¨ããä»®å®ã«åºã¥ãæ¹æ³ã§ãããå ¨ã¦ã®ã¬ã³ã¼ããé£çµãªã¹ãã§ç¹ãã§ãåã ã®ã¬ã³ã¼ããã¢ã¯ã»ã¹ããã度ã«ããã®ä½ç½®ãé£çµãªã¹ãã®æ«å°¾ã«ç§»åããããããããã¨ãé£çµãªã¹ãã®åæ¹ã«ã¯æãå¤ãå©ç¨ãããï¼Least Recent Usedãªï¼ã¬ã³ã¼ããéã¾ãããã£ãã·ã¥ã®å®¹éãä¸éãè¶ ããéã«ã¯ãLRUãªã¬ã³ã¼ãããæ¶ãã¦ããã°ããã
ã¨ããã§ãã¬ã³ã¼ãæ°ã¨ã¡ã¢ãªä½¿ç¨éãæ¯ä¾ããã®ã¯ç¢ºãã ããã¡ã¢ãªä½¿ç¨éãã¬ã³ã¼ãæ°ã®ä¸éã ãã§å¶å¾¡ããã®ã¯é¢åã ãã¬ã³ã¼ãã®å¹³åçãªãµã¤ãºãäºåã«ææ¡ããä¸ã§ãå©ç¨å¯è½ã¡ã¢ãªéãå¹³åã¬ã³ã¼ããµã¤ãºã§å²ãã¨ãã£ãä½æ¥ãå¿ è¦ã«ãªããããããæ¨å®ãå®éã¨ç°ãªããã¨ã¯å¤ãããéç¨ãã¦ã¿ãªãã¨ã¾ã¨ããªæ¨å®ãã§ããªããã¨ãå¤ãã ãããããããã¯ããã£ãã·ã¥å ã§ã¡ã¢ãªä½¿ç¨éãææ¡ãã¦ããã¦ããããéãããä¸è¦ã¬ã³ã¼ããæ¶ãã¨ããæ¹å¼ã®æ¹ã管çããããããããã£ã¦ãæ大ã¡ã¢ãªä½¿ç¨éã¨ãããã©ã¡ã¼ã¿ãè¨å®ã§ããããã«ããããã³ã³ã¹ãã©ã¯ã¿ã§æ大ã¬ã³ã¼ãæ°ã¨æ大ã¡ã¢ãªä½¿ç¨éãè¨å®ã§ããããã«ããã1000ä¸ã¬ã³ã¼ã以ä¸ãã¤ã¡ã¢ãªä½¿ç¨é4GB以ä¸ã¨ããè¨å®ã«ããã«ã¯ã以ä¸ã®ããã«DBMãæ§ç¯ããã
constexpr int64_t max_num_records = 10000000; // 10 million constexpr int64_t max_memory_usage = 4LL << 30; // 4GiB CacheDBM dbm(max_num_records, max_memory_usage); dbm.Set("1234", "I love you."); dbm.Set("5678", "You love me."); ...
æ大ã¡ã¢ãªä½¿ç¨éã ãè¨å®ããã°æ大ã¬ã³ã¼ãæ°ã®æå®ã¯ãããªãã¨æããããããªããããããã¬ã³ã¼ããå¹ççã«æ¤ç´¢ããããã«ããã·ã¥ãã¼ãã«ã使ã£ã¦ãã¦ãããã·ã¥ãã¼ãã«ã®ãã±ããæ°ãæ大ã¬ã³ã¼ãæ°ããç®åºãããã®ã§ãæ大ã¬ã³ã¼ãæ°ã®æå®ã¯å¿ é ã¨ããããã ãããã®å¤ã¯æ£ç¢ºã§ãªãã¦ãæ§ããªããæ大ã¡ã¢ãªä½¿ç¨éã®æ¹ã¯ãªãã·ã§ã³ã§ãããã©ã«ãå¤ã¯ç¡éã¨ãããã¨ã«ãããæ大ã¡ã¢ãªä½¿ç¨éãè¨å®ããã«æ大ã¬ã³ã¼ãæ°ã«å¤§ããããè¨å®ãããå ´åãä»®æ³ã¡ã¢ãªã®ã¹ã¯ãããçºçãã¦ãæ§è½ãã¬ã¿è½ã¡ã«ãªã£ã¦ãã¾ããéã«æ大ã¬ã³ã¼ãæ°ãå°ããããã¨ããã£ããæè¼ããã¦ããã¡ã¢ãªãéãã§ãã¾ããã¨ã«ãªããã³ã¹ããæªããªããæ大ã¡ã¢ãªä½¿ç¨éãè¨å®ããå ´åã¯ããããä¿éºã¨ãªãã®ã§ãæ大ã¬ã³ã¼ãæ°ã大ããã«è¨å®ãããã¨ãã§ãããçé¢ç®ãªã¦ã¼ã¹ã±ã¼ã¹ã§ã¯æ大ã¡ã¢ãªä½¿ç¨éã¯å®è³ªå¿ é ã¨è¨ã£ã¦ããã ããã
DBMå ã§ã¡ã¢ãªä½¿ç¨éãææ¡ããã«ã¯ã©ãããã°ããããåã¬ã³ã¼ãã«å¯¾ãã¦ããã®ãã¼ã®ãµã¤ãºã¨å¤ã®ãµã¤ãºã¨ãããããªã³ãã®ãµã¤ãºãåè¨ããå¤ãç®åºãããããç·è¨ãããã®ãã¬ã³ã¼ãã®ã¡ã¢ãªä½¿ç¨éã¨ãªãããããããªã³ãã¯å ¸åçã«ã¯26ãã¤ãã§ã以ä¸ã®å 訳ã«ãªãã
- ããã·ã¥ãã±ããããå ¨ã¬ã³ã¼ããç¹ãé£çµãªã¹ãã®ãã¤ã³ã¿8ãã¤ã
- æåã®ã¬ã³ã¼ãããæå¾ã®ã¬ã³ã¼ãã¾ã§ãç¹ãé£çµãªã¹ãã®ãã¤ã³ã¿8ãã¤ã
- æå¾ã®ã¬ã³ã¼ãããæåã®ã¬ã³ã¼ãã¾ã§ãç¹ãé£çµãªã¹ãã®ãã¤ã³ã¿8ãã¤ã
- ãã¼ã®ãµã¤ãºã®ã¡ã¿ãã¼ã¿1ï¼ãã6ï¼ãã¤ã
- å¤ã®ãµã¤ãºã®ã¡ã¿ãã¼ã¿1ï¼ãã6ï¼ãã¤ã
ã¬ã³ã¼ãã®ã¡ã¢ãªä½¿ç¨éã«å ãã¦ããã¼ã¿ãã¼ã¹å ¨ä½ã§ä½¿ãã¡ã¢ãªã®ä½¿ç¨éãèããå¿ è¦ãããã主ãªãã®ã¯ããã·ã¥ãã¼ãã«ã§ããããã±ããæ°ã«8ãã¤ããè³ããã¡ã¢ãªä½¿ç¨éã«ãªãããã±ããæ°ã¯æ大ã¬ã³ã¼ããµã¤ãºã®1.5åãåãã¨ãããã¨ã«ããããããããã¨ããã¼ãå¹³å8ãã¤ãã§å¤ãå¹³å100ãã¤ãã®ã¬ã³ã¼ãã1000ä¸åå ¥ããã¨ããã¨ã(8 + 100 + 26) * 10000000 + 8 * 10000000 * 1.5 ã§ãããã1.4GBã®ä½¿ç¨ã¡ã¢ãªã¨ãããã¨ã«ãªãããããã®è¨ç®ãã§ãã¦ããã°æ大ã¡ã¢ãªä½¿ç¨éãè¨å®ããå¿ è¦ã¯ãªãã®ã ãã念ã®ããã4GBã¨ããã£ãä¸éå¤ãè¨å®ãã¦ãããã¨ã¯æç¨ã§ãããããªããå®éã®ã¡ã¢ãªä½¿ç¨éï¼RSS = Resident Set Sizeï¼ã«ã¯ããã°ã©ã ã®ã³ã¼ããã¢ãã±ã¼ã¿ï¼mallocï¼ã使ãã¡ã¢ãªãå«ã¾ããã®ã ããããã«é¢ãã¦ã¯ã©ã¤ãã©ãªå´ããã¯å¶å¾¡ã§ããªãããã£ã¦ããã£ãã·ã¥ãµã¼ãã¹ã«ãã·ã³ã®å ¨ãªã½ã¼ã¹ãæ§ããã«ãã¦ããå®å¿ã®ããã«ã¯ãæè¼ããç©çã¡ã¢ãªéã®7å²ããããä¸éå¤ã«è¨å®ãããã¨ã«ãªãã ããã
LRUåé¤æ©è½ã®ããã«ã¯å ¨ã¬ã³ã¼ããåæ¹åé£çµãªã¹ãã§ç¹ãå¿ è¦ãããã®ã ããé£çµãªã¹ãã®æ´æ°å¦çã¯ä¸¦åã«è¡ããªãã¨ããæ¬ ç¹ããããé åºé¢ä¿ããããã®ã¯ä¸¦åã«æ´æ°ã§ããªãã®ã ããããããã£ãã·ã¥ãµã¼ãã¹ã¯æ§è½ãå½ãªã®ã§ã並ååã¯å¿ é ã ããã£ã¦ãå é¨ã§ã·ã£ã¼ãã£ã³ã°ãæ½ãã¦ä¸¦ååãå®ç¾ãããåã ã®ã·ã£ã¼ãã管çããå é¨çãªé£æ³é åãã¹ãããã¨å¼ã¼ããããªãã¡ãå é¨çã«32åã®ã¹ãããã«åãã¦ç®¡çãã¦ããã®åã ã§ããã·ã¥ãã¼ãã«ã¨é£çµãªã¹ããæããããæä»å¶å¾¡ã¯ã¹ãããæ¯ã«æã¤mutexã§è¡ããæè¿ã®ãã·ã³ã 6ã³ã¢12ã¹ã¬ããã¨ããæ®éã«å®è£ ãããããã«ãªã£ã¦ããããã¹ãããæ°ã¨ãã¦ã¯32åãããã°ååã ãããåã ã®ã¬ã³ã¼ãã«å¯¾ãã¦ã¯ããã¼ã®ããã·ã¥å¤ã«ãã£ã¦ãã©ã®ã¹ãããã«æå±ãããã決ãããããã·ã¥å¤ã®ä¸ä½8ãããã¯ã¹ãããã®ã¤ã³ããã¯ã¹ã®ç®å®ã«ç¨ãã¦ãæ®ããããã·ã¥ãã±ããã®ã¤ã³ããã¯ã¹ç®å®ã«ä½¿ãã°ããã ãããã¬ã³ã¼ãã®è¿½å æä½ã¯ä»¥ä¸ã®ãããªã³ã¼ãã§å®è£ ãããã
uint64_t hash = PrimaryHash(key); int32_t slot_index = hash & 0xFF; int64_t bucket_index = (hash >> 8) % num_buckets_; slots_[slot_index].Set(bucket_index, key, value);
ã¹ãããåã«ãã£ã¦ãå®å ¨ãªLRUåé¤ã¯å®ç¾ãããªããªããã¬ã³ã¼ãæ°ã®ä¸éã1000ä¸ã¨è¨å®ãããªããåã ã®ã¹ãããã®ã¬ã³ã¼ãæ°ã®ä¸éã¨ãã¦31ä¸ããããè¨å®ãããããã£ã¦ãçè«çãªææªã®ã±ã¼ã¹ã§ã¯å ¨ã¬ã³ã¼ããç¹å®ã®ã¹ãããã«éä¸ãã¦ã31ä¸åããå¤ãã¬ã³ã¼ããæ¶ãããå¯è½æ§ããããã¨ã¯ããããã®ãããªãã¨ãå®éã«èµ·ãã確çã¯ã»ã¼ã¼ãã§ããããã¨ãèµ·ããã¨ãã¦ããã£ãã·ã¥ãã¼ã¿ãªã®ã§åé¡ãªããçè«çãªä¿è¨¼ããã¯å®éã®æ§è½ã®æ¹ãéè¦ã§ãããã
æ§è½ãã¹ãããã¦ã¿ãããã¼ã¨å¤ããããã8ãã¤ãã§ã©ã³ãã ãªãã¿ã¼ã³ãæã¤ã¬ã³ã¼ãã1å件ç»é²ãããLRUåé¤ãªãã§ã¹ãããåããªãå®è£ ã§ããTinyDBMã¨ãLRUåé¤ããã§ã¹ãããåããå®è£ ã§ããCacheDBMãæ¯è¼ããã
class | Set | Get | Remove | RAM usage |
TinyDBM (1 thread) | 2,267,644 QPS | 2,576,552 QPS | 2,690,487 QPS | 3573.0 MB |
CacheDBM (1 thread) | 2,263,022 QPS | 2,257,323 QPS | 2,745,666 QPS | 4999.2 MB |
TinyDBM (10 threads) | 7,376,532 QPS | 8,314,453 QPS | 7,596,498 QPS | 3573.0 MB |
CacheDBM (10 threads) | 6,871,719 QPS | 7,358,504 QPS | 8,325,958 QPS | 4999.5 MB |
ä¸è¨ã§ç¢ºèªã§ããããã«ããã«ãã¹ã¬ããã«ãã並åå¦çã¯ååã«æ©è½ãã¦ãã¦ã10ã¹ã¬ããã使ãã¨700ä¸QPSç¨åº¦ã§æ¤ç´¢ãæ´æ°ãã§ããããã¼ã¿ãã¼ã¹ãµã¼ãã®å é¨ã§ä½¿ãã¨ä»®å®ããå ´åããã®æ§è½ã§ããã°ããã«ããã¯ã«ãªããã¨ã¯ãªãã ãããã¹ã«ã¼ãããã大ãããã°ãå®ä¾¡ãªCPUãæ¡ç¨ãã¦ããã®åã®éãRAMã®å¢è¨ããã·ã³èªä½ã®å¢è¨ã«åããã®ã§ãçµæçã«ã¹ã±ã¼ã«ã¢ãããã¹ã±ã¼ã«ã¢ã¦ãã«ç¹ãããã¹ã«ã¼ãããã¯TinyDBMã¨CacheDBMã§ã»ã¼åçã ããã¡ã¢ãªä½¿ç¨éã¯TinyDBMã®æ¹ãå°ãªããããã¯CacheDBMã¯é£çµãªã¹ãã®ããã®ãããããªã³ãã大ããããã§ããããã ããå®éã®ã¦ã¼ã¹ã±ã¼ã¹ã§ã¯ã¬ã³ã¼ãã®å¤ã®ãµã¤ãºããã£ã¨å¤§ããã®ãå ¸åçã§ãããããããããããªã³ããå ããå²åã¯ãã£ã¨ä½ããªããã¨ã ããã
ããããªã³ã¡ã¢ãªDBMã¯ããã¼ã¿ãã¼ã¹ãµã¼ãã«çµã¿è¾¼ã以å¤ã§ããJavaãPythonãRubyã®ããã»ã¹ã«çµã¿è¾¼ãã§ä½¿ã£ã¦ãæç¨ã§ããããDBMã«ã¯æååããæ ¼ç´ã§ããªãã®ã§ãªãã¸ã§ã¯ããã·ãªã¢ã©ã¤ãºãã¦æ±ããã¨ã«ãªãã®ã ããåè¨èªã®ãã¤ãã£ããªãªãã¸ã§ã¯ãã大éã«ä¿æãç¶ããããã¯ãå¤§å¹ ãªã¡ã¢ãªç¯ç´ã«ãªãã1åã¬ã³ã¼ãããã·ã³1å°ã§ããããåããã®ã ã