dragonfly - Dragonfly 是一个现代内存数据存储,与 Redis 和 Memcached API 完全兼容,可作为Redis 和 Memcached 的替代品

Created at: 2021-12-11 18:00:42
Language: C++
License: NOASSERTION

蜻蜓

ci-test 推特网址

快速入门|不和谐聊天||讨论|贡献

可能是宇宙中最快的内存存储!

蜻蜓是一个现代内存数据存储,与 Redis 和 Memcached API 完全兼容。Dragonfly在多线程,无共享架构之上实现了新颖的算法和数据结构。因此,与 Redis 相比,蜻蜓的性能达到了 x25,并且在单个实例上支持数百万个 QPS。

蜻蜓的核心特性使其成为具有成本效益,高性能且易于使用的Redis替代品。

基准

与 Redis 相比,蜻蜓在 c6gn.16xlarge 上跨越 3.8M QPS,吞吐量增加了 x25。

蜻蜓在其峰值吞吐量时的第 99 个延迟百分位数:

操作 r6g c6克 c7克
设置 0.8毫秒 1毫秒 1毫秒
获取 0.9毫秒 0.9毫秒 0.8毫秒
塞泰克斯 0.9毫秒 1.1毫秒 1.3毫秒

所有基准测试都是使用memtier_benchmark(见下文)执行的,每个服务器类型和实例类型调整线程数。梅米蒂尔在一台单独的c6gn.16x大机器上运行。对于setex基准测试,我们使用500的到期范围,因此它将在测试结束时存活下来。

  memtier_benchmark --ratio ... -t <threads> -c 30 -n 200000 --distinct-client-seed -d 256 \
     --expiry-range=...

在管道模式下运行时,蜻蜓在SET操作中达到1000万个qps,在GET操作中达到1500万个qps

--pipeline=30

蜻蜓/蜻

我们在 AWS 上的实例上将蜻蜓与蜻蜓进行了比较。正如你在下面看到的,Dragonfly在写入和读取工作负载的写入和读取工作负载方面都占主导地位,并且具有相当的延迟。对于写入工作负载,蜻蜓也有更好的延迟,因为 memcached 中的写入路径存在争用。

c6gn.16xlarge

设置基准测试

服务器 质量(千次) 延迟 99% 99.9%
蜻蜓 🟩 3843 🟩 0.9毫秒 🟩 2.4毫秒
梅卡切德 806 1.6毫秒 3.2毫秒

获取基准测试

服务器 质量(千次) 延迟 99% 99.9%
蜻蜓 🟩 3716 1毫秒 2.4毫秒
梅卡切德 2100 🟩 0.34毫秒 🟩 0.6毫秒

Memcached 在读取基准测试中表现出较低的延迟,但吞吐量也较低。

内存效率

在下面的测试中,我们使用命令用~5GB的数据填充了蜻蜓和Redis。然后,我们开始发送更新流量,并使用“bgsave”命令启动快照。下图清楚地演示了两台服务器在内存效率方面的行为方式。

debug populate 5000000 key 1024
memtier

在空闲状态下,蜻蜓的内存效率比Redis高出30%。在快照阶段,它也没有显示任何可见的内存增加。与此同时,与蜻蜓相比,Redis在峰值时达到了几乎x3的内存增长。蜻蜓也更快地完成了快照,就在它开始后的几秒钟。有关蜻蜓中内存效率的更多信息,请参阅 dashboard 文档

运行服务器

蜻蜓在 Linux 上运行。我们建议在Linux版本5.11或更高版本上运行它,但你也可以在较旧的内核上运行蜻蜓。

使用泊坞窗:

docker run --network=host --ulimit memlock=-1 docker.dragonflydb.io/dragonflydb/dragonfly

redis-cli PING  # redis-cli can be installed with "apt install -y redis-tools"

你需要 --ulimit 内存锁 =-1,因为某些 Linux 发行版将容器的默认内存锁限制配置为 64m,而蜻蜓需要更多。

释放

我们维护 x86 和 arm64 架构的二进制版本。你需要安装 lib 才能运行二进制文件。

libunwind8

从源代码构建

你需要安装依赖项才能在 Ubuntu 20.04 或更高版本上进行构建:

git clone --recursive https://github.com/dragonflydb/dragonfly && cd dragonfly

# to install dependencies
sudo apt install ninja-build libunwind-dev libboost-fiber-dev libssl-dev libxml2-dev \
     autoconf-archive libtool cmake g++

# Configure the build
./helio/blaze.sh -release

# Build
cd build-opt && ninja dragonfly

# Run
./dragonfly --alsologtostderr

配置

蜻蜓在适用的情况下支持常见的Redis论点。例如,你可以运行:。

dragonfly --requirepass=foo --bind localhost

蜻蜓目前支持以下特定于 Redis 的论点:

  • port
    redis 连接端口,默认值:6379
  • bind
    本地主机仅允许本地主机连接,公共 IP 地址 ,以允许连接到该 IP 地址(也表示从外部)
  • requirepass
    用于身份验证的密码,默认值:“”
  • maxmemory
    对数据库使用的最大内存(以字节为单位)的限制 - 意味着程序将自动确定其最大内存使用率。默认值:0
  • dir
    - 默认情况下,蜻蜓泊坞窗使用文件夹进行快照。CLI 使用:“”你可以使用泊坞窗选项将其映射到主机文件夹。
    /data
    -v
  • dbfilename
    用于保存/加载 DB 的文件名。默认值:“转储”;

此外,它还具有蜻蜓特定的参数选项:

  • memcache_port
    - 在此端口上启用内存兼容的 API。默认情况下禁用。
  • keys_output_limit
    - 命令中返回的密钥的最大数量。默认值为 8192。 是一个危险的命令。我们截断其结果,以避免在获取太多密钥时内存中爆炸。
    keys
    keys
  • dbnum
    - 支持的最大数据库数。
    select
  • cache_mode
    - 请参阅下面的缓存部分。
  • hz
    - 密钥到期评估频率。默认值为 100。较低的频率在空闲时使用较少的 CPU,但代价是逐出速率较慢。
  • save_schedule
    - 用于 UTC 时间的 glob 规范,用于保存与 HH:MM(24 小时时间)匹配的快照。默认值:“”
  • keys_output_limit
    - 按键命令输出的最大键数。默认值:8192

有关日志管理或 tls 支持等更多选项,请运行 。

dragonfly --help

路线图和状态

目前,蜻蜓支持~185个Redis命令和除.我们几乎与 Redis 5 API 不相上下。我们的下一个里程碑将是稳定基本功能并实现复制 API。如果你发现所需的命令尚未实现,请打开一个问题。

cas

对于蜻蜓原生复制,我们正在设计一种分布式日志格式,该格式将支持更高的速度。

在复制功能之后,我们将继续使用 API 3-6 中缺少的其他 Redis 命令。

请参阅 API 就绪文档,了解蜻蜓的当前状态。

设计决策

新颖的缓存设计

蜻蜓具有一种统一的自适应缓存算法,该算法非常简单且内存高效。你可以通过传递标志来启用缓存模式。一旦开启此模式,蜻蜓将驱逐未来最不可能被绊倒的物品,但只有在接近最大记忆极限时才会被驱逐。

--cache_mode=true

具有相对准确性的到期期限

过期范围限制为 ~4 年。此外,对于大于 134217727 毫秒(约 37 小时)的截止时间,具有毫秒精度的到期截止时间(PEXPIRE/PSETEX 等)将舍入为最接近秒。这种舍入的误差小于0.001%,我希望这在大范围内是可以接受的。如果它破坏了你的用例 - 与我交谈或打开问题并解释你的情况。

有关此实现与 Redis 实现之间的更多详细区别,请参阅此处

原生 Http 控制台和普罗米修斯兼容指标

默认情况下,蜻蜓允许通过其主 TCP 端口 (6379) 进行 http 访问。没错,你可以通过Redis协议和HTTP协议连接到蜻蜓 - 服务器在连接启动期间自动识别协议。继续使用浏览器进行尝试。现在它没有太多信息,但在将来,我们计划在那里添加有用的调试和管理信息。如果你去网址,你会看到一些普罗米修斯兼容的指标。

:6379/metrics

普罗米修斯导出的指标与格拉法纳 dashboard 兼容,请参阅此处

重要!http 控制台应在安全网络中访问。如果在外部公开蜻蜓的 TCP 端口,建议使用 或 禁用控制台。

--http_admin_console=false
--nohttp_admin_console

背景

Dragonfly最初是一项实验,旨在了解内存中数据存储在2022年设计时的外观。根据我们作为内存存储用户和为云公司工作的工程师的经验,我们知道我们需要为Dragonfly保留两个关键属性:a)为其所有操作提供原子性保证,以及b)保证在非常高的吞吐量下具有低亚毫秒级的延迟。

我们的第一个挑战是如何利用当今公共云中可用的服务器充分利用 CPU、内存和 I/O 资源。为了解决这个问题,我们使用了无共享架构,它允许我们在线程之间划分内存存储的键空间,以便每个线程管理自己的字典数据切片。我们称这些切片为分片。为无共享架构的线程和 I/O 管理提供支持的库在这里是开源的。

为了给多键操作提供原子性保证,我们利用了最近学术研究的进步。我们选择了论文“VLL:主内存数据库系统的锁管理器重新设计”来开发Dragonfly的事务框架。无共享架构和 VLL 的选择使我们能够在不使用互斥锁或自旋锁的情况下编写原子多键操作。这是我们 PoC 的一个重要里程碑,其性能从其他商业和开源解决方案中脱颖而出。

我们的第二个挑战是为新商店设计更有效的数据结构。为了实现这一目标,我们的核心哈希表结构基于论文“Dash:持久内存上的可扩展哈希”。本文本身以持久内存域为中心,与主内存存储没有直接关系。然而,它非常适用于我们的问题。它提出了一个哈希表设计,允许我们维护 Redis 字典中存在的两个特殊属性:a) 它在数据存储增长期间的增量哈希处理能力 b) 它在更改下遍历字典的能力 使用无状态扫描操作。除了这两个属性之外,达世币在CPU和内存方面的效率要高得多。通过利用达世币的设计,我们能够进一步创新,具有以下特点:

  • TTL 记录的高效记录到期。
  • 一种新颖的缓存逐出算法,可实现比其他缓存策略(如 LRU 和 LFU)更高的命中率,并且内存开销为零
  • 一种新颖的无分叉快照算法。

在我们为蜻蜓奠定了基础并且我们对它的性能感到满意之后,我们继续实现Redis和Memcached功能。到目前为止,我们已经实现了大约 185 个 Redis 命令(大致相当于 Redis 5.0 API)和 13 个 Memcached 命令。

最后,
我们的使命是为云工作负载构建一个精心设计、超快速、经济高效的内存中数据存储,以利用最新的硬件进步。我们打算解决当前解决方案的痛点,同时保留其产品API和主张。