编写数据库:第2部分-预写日志

编写数据库:第2部分-预写日志

与往常一样,请访问https://github.com/danchia/ddb上的代码

所以,您的数据不是很耐用...

第1部分中,我使用gRPC和Go编写了一个非常简单的服务器,该服务器用于服务GetPut请求内存中的映射。如果服务器退出,它将丢失所有数据,对于数据库,我必须承认这是非常糟糕的。
我实现了预写日志记录,允许在服务器重新启动时恢复内存中状态。尽管这个想法真的很简单,但实现起来却是很困难的!最后,我看了 LevelDBCassandraetcd 如何解决此问题。

预写日志

预写日志(WAL)是数据库系统中一种常用的技术,用于保证写操作的原子性持久性。WAL背后的关键思想是,在我们对数据库状态进行任何实际修改之前,我们必须首先记录我们希望是原子性的和持久存储(例如磁盘)的完整操作集。

通过在将更改应用于例如内存中表示之前,先将预期的改变写入WAL来提供持久性。通过首先写入WAL,如果数据库之后崩溃,我们将能够恢复改变并在必要时重新应用。

原子性更加微妙。假设一个改变需要改变ABC发生,但是我们的应用没有办法一下应用所有的改变。我们可以先记日志

intending to apply A
intending to apply B
intending to apply C

然后才开始制作实际的应用程序。如果服务器中途崩溃,我们可以查看日志并查看可能需要重做的操作。

在DDB中,WAL是记录 append-only 的文件:

record:
  length: uint32      // length of data section
  checksum: uint32    // CRC32 checksum of data
  data: byte[length]  // serialized ddb.internal.LogRecord proto 

由于序列化原型不是自我描述的,因此我们需要一个 length 字段来知道data有效载荷的大小。此外,为了防止各种形式的损坏(和错误!),我们提供了数据的 CRC32 校验和。

性能至关重要,但是磁盘速度很慢

通常,WAL结束了所有变更操作的关键路径,因为我们必须在进行变更之前执行预写日志的记录。

您可能会认为我们会在File.Write调用返回后继续前进,但是由于操作系统缓存,通常情况并非如此。

我将在这里以Linux为例。 buffer cache. 这些缓存有助于提高性能,因为应用程序经常读取它们最近写的内容,而且应用程序并不总是按顺序读取或写入。

Linux通常以写回模式(write-back)运行,在该模式下,缓冲区缓存仅定期(约30秒)刷新到磁盘。 File.Write``fsync()

写了一个快速的基准来判断我的WAL的性能。该测试重复记录100字节或1KB的记录,每n次调用一次fsync()。这些测试在装有本地SSD的Windows 10计算机上运行。

基准测试

DDB WAL Benchmarks
BenchmarkAppend100NoSync             529 ns/op         200.23 MB/s
BenchmarkAppend100NoBatch         879939 ns/op           0.12 MB/s
BenchmarkAppend100Batch10          88587 ns/op           1.20 MB/s
BenchmarkAppend100Batch100          9727 ns/op          10.90 MB/s
BenchmarkAppend1000NoSync           2213 ns/op         455.45 MB/s
BenchmarkAppend1000NoBatch        906057 ns/op           1.11 MB/s
BenchmarkAppend1000Batch10         94318 ns/op          10.69 MB/s
BenchmarkAppend1000Batch100        14384 ns/op          70.08 MB/s

毫不奇怪,fsync()它很慢!100字节的日志条目没有同步需要529ns,同步需要880us。880us会将我们限制在〜1.1k QPS。对于普通的HDD,可能会更糟,因为磁盘寻道可能要花费我们10毫秒左右的时间。对于HDD来说,仅将专用驱动器用于WAL以减少寻道时间并不少见。

为了理智地检查我的结果,我运行了etcd的WAL基准测试。

etcd WAL Benchmarks
BenchmarkWrite100EntryWithoutBatch    868817 ns/op           0.12 MB/s 
BenchmarkWrite100EntryBatch10         79937 ns/op           1.35 MB/s
BenchmarkWrite100EntryBatch100        9512 ns/op          11.35 MB/s
BenchmarkWrite1000EntryWithoutBatch   875304 ns/op           1.15 MB/s 
BenchmarkWrite1000EntryBatch10        84618 ns/op          11.92 MB/s
BenchmarkWrite1000EntryBatch100       12380 ns/op          81.50 MB/sk

etcd的单个100字节写操作为869ns,所以我非常接近!他们的大批产品的性能要好一些,但这并不奇怪,因为他们的实现得到了更优化。我怀疑如果我要测量等待时间直方图,它们的性能可能会缩短尾部等待时间。

同步还是不同步?

鉴于同步是如此昂贵,其他数据库又是怎么做的呢?

  • LevelDB 实际上默认为不同步。他们声称非同步写入通常可以安全地使用,并且用户应该在希望进行同步时进行选择。
  • Cassandra 默认为每10秒进行一次定期同步。写入将被放置到OS文件缓冲区中后被确认。
  • etcd 对于是否同步有一些逻辑,但最好的办法是告诉用户写操作最终会导致同步。

我现在决定改正正确性并始终保持同步。我要寻找的一种潜在优化是尝试批量更新WAL,从而分摊同步成本。

其他的问题/我没有做的事情

大多数WAL实现将其日志记录在段中。段达到一定大小后,WAL将开始一个新段。一旦不再需要日志的较早部分,这将很容易截断它们。
处理多个文件,或者实际上是一般的文件系统,可能会很棘手。特别是,就像使用编译器和内存一样,操作系统通常可以自由地将操作重新排序到磁盘,并且许多文件操作不是原子的。诸如写入临时文件然后将其重命名为最终位置以进行原子文件写入之类的技术很常见。对此,你可以检查出GitHub上另一个项目 issue 来了解 ACID 文件系统写入的难度。

下一次:共识

我希望接下来通过共识算法(例如Raft)进行复制。

如果您喜欢阅读本文,请重新分享并通过任何推文(@DanielChiaJH)发给我!

译自:https://medium.com/@daniel.chia/writing-a-database-part-2-write-ahead-log-2463f5cec67a

本文由博客一文多发平台 OpenWrite 发布!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容