levy5307 / blog

https://levy5307.github.io/blog/
MIT License
0 stars 0 forks source link

pegasus remove slog #74

Open levy5307 opened 2 years ago

levy5307 commented 2 years ago

https://levy5307.github.io/blog/pegasus-remove-slog/

读WiscKey论文的时候,了解到SSD的写入具有一定的并行性。遂对SSD做了一些调研,发现果真如此。另外考虑到Pegasus的双WAL架构,以slog写入为准,而slog是单线程写入的。这导致完全利用不上SSD的并行性。因此考虑对slog做移除。

可行性调研

经过深入研究pegasus代码,发现涉及到slog的功能主要有learn、duplication、partition split以及2pc

2pc

需要将plog提交改成同步提交。

learn

learnee

learnee只会使用plog,不会从slog同步数据跟leaner,因为plog没有的数据可以从prepare_list中获取,不会有数据遗漏。

learner

learner(on_learn_reply函数)会将获取的mutation apply到plog和slog,这里需要做修改。

热备(duplication)

使用的完全是plog,与slog无关。

partition split

copy parent时使用private log,只是在child写入时需要同时写入plog和slog。

版本升级&回退

升级

true data应该是在slog里的,在升级时的启动过程,log回放还是需要从slog中获取。因此slog相关代码还需要保留,只是不再写入。

回退

回退时会导致plog中数据比slog中更新,需要能正确回放log数据。

在replica_init.cpp的replay_mutation主要用于执行log mutation回放:

对每个replica回放其对应plog

当所有replica回放完plog之后,读取slog,对其中保存的mutation进行回放。如果某个mutation的decree小于plog中max decree,则直接忽略该mutation。

因此该机制可以保证,在回退到老版本时,依然可以通过回放plog获取最新数据。

需要注意的点:在回放时,不会将slog缺失的数据补足,即slog中间会有空洞。因此在回放完成后,slog+plog才代表true data

升级中途

此时,部分replica server的true data在slog,另外一部分在plog。

只要确保log数据能够正确写入和读取就没有问题。

升级中途回退

如果升级过程遇到问题,需要回退到老版本。此时会导致如下情况:

部分replica的true data在slog(这部分replica没有被正常打开)

部分replica的true data在plog(这部分replica被正常open且对写请求进行了响应)

同版本回退,replay_mutation机制可以保证回放到最新的数据。

slog gc

gc逻辑主要是匹配所有slog文件的max_decree与min{plog_durable_decree,app_durable_decree}。如果小于则该文件可以删除;否则需要保留。

所以即使有回退等情况导致的slog空洞,理论上也不影响数据的正确性,只要slog文件中的mutation的decree是有序的即可。

Note: 升级之后,系统会逐渐gc掉slog文件,直到还剩最后一个。

其他

可以维持原有逻辑不变。

结论

目前可以做到不向slog写入,并将plog写入改成同步写,无法全部将slog相关代码删除。

性能测试

在移除slog后,plog的保存依然有两种方案:

因此测试性能时,对这两种方案分别进行了测试。

master分支(保留slog)

+————————–+———-+————+——–+————+————–+————————————————–+————————————————+ | operation_case | run_time | throughput | length | read_write | thread_count | read(qps|ave|min|max|95|99|999|9999) | write(qps|ave|min|max|95|99|999|9999) | +————————–+———-+————+——–+————+————–+————————————————–+————————————————+ | write=single,read=single | 12982 | 23108 | 1000 | 0 : 1 | 15 | {0 0 0 0 0 0 0 0} | {23108 1944 412 515241 5265 10553 24484 38153} | | write=single,read=single | 3695 | 244278 | 1000 | 1 : 0 | 50 | {244316 612 119 353535 969 2084 20393 35273} | {0 0 0 0 0 0 0 0} | | write=single,read=single | 5627 | 42651 | 1000 | 1 : 1 | 30 | {21328 1424 129 1111380 5469 20425 95060 155604} | {21326 2784 418 550228 7383 12399 37279 68009} | | write=single,read=single | 5013 | 29915 | 1000 | 1 : 3 | 15 | {7479 1084 128 1347924 3065 15969 84169 141567} | {22439 1639 407 255615 3979 7665 21596 37012} | | write=single,read=single | 3488 | 25793 | 1000 | 1 : 30 | 15 | {830 987 153 811689 2795 12929 75935 143828} | {24966 1765 412 271700 4196 8500 19433 28137} | | write=single,read=single | 4093 | 73317 | 1000 | 3 : 1 | 30 | {54992 845 118 457727 2798 9303 36057 56009} | {18328 2360 415 456191 5900 10385 30020 50996} | | write=single,read=single | 4560 | 197394 | 1000 | 30 : 1 | 50 | {191035 732 119 172628 1461 4051 17439 27193} | {6369 1470 440 130943 2480 5995 19623 30948} | +————————–+———-+————+——–+————+————–+————————————————–+————————————————+

plog in data

+————————–+———-+————+——–+————+————–+———————————————–+————————————————+ | operation_case | run_time | throughput | length | read_write | thread_count | read(qps|ave|min|max|95|99|999|9999) | write(qps|ave|min|max|95|99|999|9999) | +————————–+———-+————+——–+————+————–+———————————————–+————————————————+ | write=single,read=single | 10538 | 28464 | 1000 | 0 : 1 | 15 | {0 0 0 0 0 0 0 0} | {28466 1577 339 447572 4808 9529 21057 31903} | | write=single,read=single | 3420 | 265243 | 1000 | 1 : 0 | 50 | {265272 567 118 166548 884 1799 16427 23087} | {0 0 0 0 0 0 0 0} | | write=single,read=single | 4398 | 54556 | 1000 | 1 : 1 | 30 | {27282 724 123 179284 2433 7693 23727 33321} | {27280 2567 351 474623 7309 12553 34591 60809} | | write=single,read=single | 4071 | 36835 | 1000 | 1 : 3 | 15 | {9209 617 131 253225 1626 6852 21545 30025} | {27629 1418 344 564393 4054 7904 19201 30495} | | write=single,read=single | 2831 | 31775 | 1000 | 1 : 30 | 15 | {1025 702 155 248788 1721 8023 29839 43103} | {30757 1436 341 308393 4029 8521 19097 27551} | | write=single,read=single | 3410 | 87997 | 1000 | 3 : 1 | 30 | {66002 680 120 168404 1912 6281 21188 32169} | {21999 2038 344 432895 5556 10164 30020 54239} | | write=single,read=single | 4143 | 217312 | 1000 | 30 : 1 | 50 | {210345 668 116 179284 1374 3876 16865 23241} | {7010 1233 376 133353 2054 5217 18625 24799} | +————————–+———-+————+——–+————+————–+———————————————–+————————————————+

plog in home

+————————–+———-+————+——–+————+————–+———————————————–+————————————————+ | operation_case | run_time | throughput | length | read_write | thread_count | read(qps|ave|min|max|95|99|999|9999) | write(qps|ave|min|max|95|99|999|9999) | +————————–+———-+————+——–+————+————–+———————————————–+————————————————+ | write=single,read=single | 12674 | 23668 | 1000 | 0 : 1 | 15 | {0 0 0 0 0 0 0 0} | {23669 1898 387 575828 5411 10455 23983 36287} | | write=single,read=single | 3347 | 269283 | 1000 | 1 : 0 | 50 | {269348 555 121 151508 867 1438 16021 19000} | {0 0 0 0 0 0 0 0} | | write=single,read=single | 5126 | 46811 | 1000 | 1 : 1 | 30 | {23407 600 128 146943 1426 5945 20548 30708} | {23408 3236 399 587775 9396 15871 42324 74004} | | write=single,read=single | 4859 | 30863 | 1000 | 1 : 3 | 15 | {7712 527 130 320297 919 5117 19105 27636} | {23152 1763 394 464639 4712 9924 23199 34889} | | write=single,read=single | 3371 | 26690 | 1000 | 1 : 30 | 15 | {859 566 155 190377 960 4981 21252 31743} | {25831 1719 391 152831 4335 9175 20751 29716} | | write=single,read=single | 3750 | 80008 | 1000 | 3 : 1 | 30 | {60016 569 122 310868 1179 4841 17724 27908} | {20003 2777 415 577364 7352 13444 33855 54121} | | write=single,read=single | 4118 | 218765 | 1000 | 30 : 1 | 5 | {211735 656 116 176937 1313 3533 16956 23524} | {7053 1471 456 150100 2435 5804 20839 30159} | +————————–+———-+————+——–+————+————–+———————————————–+————————————————+

总结对比

plog in data(remove slog) v.s. master分支(保留slog)

以mater分支为基准:

利用了ssd的并行性,符合理论预期

写延迟降低,是因为以前单线程写时,每个写向磁盘flush时,都需要排队很长时间。remove slog之后,可以多队列并行写,排队时间减少。

读延迟降低这么多确实是始料未及的,猜测原因是由于写延迟降低、写对集群的负载减少,从而间接提高了读的性能

plog in home v.s. plog in data

以plog in data为基准:

plog in home(remove slog) v.s. master(保留slog)

以master分支为基准:

结论

以master分支(保留slog)为基准,得出如下表格

+————–+————–+————+———–+ | Scenario | throughput | 读延迟 | 写延迟 | +————–+————–+————+———–+ | plog in data | +20% | -36% | -8% | | plog in home | +7% | -45% | +10% | +————–+————–+————+———–+



从而可得:

    plog in data(remove slog)性能最好

    master分支(保留slog)和plog in home(remove slog)各有优劣,master分支写性能高,plog in home读性能高。