多版本并发控制 (MVCC)
您可能听过开发人员谈论 MVCC 这个术语,也可能认识到像 PostgreSQL 这样的数据库中的一些术语。使用像 MVCC 这样强大的方法,为 KeyDB 带来了在 NoSQL 数据库中不常见的工具。它还与 KeyDB 的多线程架构协同工作,提供高级查询和事务处理,而不会出现像 Redis 那样的性能损失。我们相信,一个数据库应该允许尽可能多的请求被同时处理。
#
什么是 MVCC?多版本并发控制,顾名思义,使我们能够允许对数据库进行并发访问。例如,当 KeyDB 需要更新某些数据或执行事务时,它不会覆盖原始数据,而是为其创建一个新版本/快照。这样,被修改的数据仅对创建它的事务可见,直到该事务被提交。在此之前,其他的读取操作看到的是未提交更改之前的快照。当旧的快照不再被访问时,它会被自动移除。
通过维护对象的多个版本,MVCC 确保事务永远不必等待读取数据库对象,从而使其成为非阻塞的。这对于涉及事务、脚本、繁重查询等通常在 Redis 中会是阻塞操作的工作负载来说至关重要。借助 MVCC,通过多个快照实现隔离的能力带来了巨大的功能改进。
MVCC 的并发性远优于两阶段锁定,这使得它在数据库系统中更具优势。
#
为什么要在 KeyDB 中构建 MVCC?KeyDB 有着利用 MVCC 实现未来功能和用途的整体计划,这些功能和用途需要这样的基础设施。
KeyDB 相信用户应该只需要一个开箱即优化的数据库。您不应该需要运行外部工具或其他数据库来弥补现有数据库的局限性。KeyDB 旨在通过其高性能实现简单性。
事务、Lua 脚本、数据管理对许多用户来说非常重要,使他们能够用数据库完成所需的操作。大量使用这些功能会带来许多问题,包括可能减慢整个数据库速度、造成积压甚至可能导致服务器崩溃的阻塞操作。对我们来说,MVCC 与多线程化应用的初衷完全一致。我们现在可以运行更多的并发操作而不会减慢速度。这意味着用户可以做更多的事情,执行事务、脚本、高级查询,而不用担心在 Redis 上执行此类操作所带来的恐惧。
MVCC 将允许我们执行事务回滚。这为用户提供了一种新的自由度,不再需要在客户端进行预筛选和追求完美。它还提供了当用户改变主意时进行回滚的选项(具体取决于设置)。
Redis 无法做出这些保证,并依赖客户端筛选来防止问题。如果事务的一部分已经进行了修改,但事务最终失败,那么这些修改是无法撤销的。“要么全部成功,要么全部失败……除非中间发生了什么”。
#
无等待和无锁算法KeyDB 使用一种无等待和无锁的算法。这意味着我们可以通过并发操作来保证延迟和系统级的吞吐量。无锁意味着无论某个线程是否被挂起,进程都将继续推进,这可以防止在不同写入场景下的性能下降。无等待与 MVCC 结合意味着读取操作不会被挂起,每个线程都将继续取得进展。许多在 Redis 生产环境中运行时常令人担忧和严重关切的阻塞操作,在 KeyDB 中已不再是问题。这种基础架构正在为 KeyDB 奠定基础,以构建强大的工具,从而实现更复杂的操作,提供更好的数据管理和分析。
这一采用使得可以使用更多的线程,确保 KeyDB 的多线程能力在处理复杂/重型操作和高 IOPS 方面能够持续扩展。
#
无 fork 后台保存MVCC 使无 fork 后台保存成为可能。这极大地减少了在执行后台保存时所需的空闲内存量。
无 fork 后台保存首先是关于 Linux 性能的。使用 fork() 进行快照的问题在于写放大:如果您修改了页面上的哪怕一个字节,整个 4K 页面都需要被复制。在 fork 发生期间,您必须确保有足够的可用内存来接受所有写操作(新的和更新的数据)。内存不足可能导致进程失败。写入 rdb 备份所需的时间取决于数据库的大小,随着大小增长到数 GB,可能需要很长时间。fork() 的时间与整个数据集的大小有关。相比之下,无 fork 后台保存的成本是相同的,无论您的键是 1 字节还是 500MB。随着值大小的增加,这一点将变得非常重要。无 fork 后台保存将既更快又更节省内存。