dragonfly数据库这段时间风头正盛,和redis的对飙也颇有看点。可能是刚出现的缘故,网上成型的资料还不多。今天接着这篇博客的机会,了解一下dragonfly。主要内容围绕以下几个主题:
  1.dragonfly基本信息
  2.dragonfly本身的特点
  3.dragonfly和redis对比

一、dragonfly基本信息

  一句话描述就是:dragonfly是一个的开源内存存储数据库,类型属于nosql,兼容redis和memcached API。
  开源代码(GitHub):GitHub - dragonflydb/dragonfly: A modern replacement for Redis and Memcached
  开源代码(Gitee):DragonflyDB: Dragonfly 是一个现代化的开源内存数据库,兼容 Redis 和 Memcached API (gitee.com)
  官网:Dragonfly (dragonflydb.io)
  代码整体是C和C++组成,具体的语言结构如下:
在这里插入图片描述
  目前最新的版本是v0.6.0
  dragonfly的使用环境是Linux5.1以上,经本人测试ubuntu的话需要是20.04才能成功运行。不知道为啥,进行源码编译时缺少opt-build这个文件夹中的信息,无奈只能选择二进制文件的运行方式。
  使用步骤如下:

// 1.首先配置下基础环境:
sudo apt install ninja-build libunwind-dev libboost-fiber-dev libssl-dev \
     autoconf-archive libtool cmake g++
// 2.开启服务器端(在dragonfly)
./dragonfly-x86_64 --alsologtostderr
// 3.开启客户端(新起窗口,初次使用需要sudo apt install redis-tools)
redis-cli

  然后终端会有输出,服务器端会输出一些相关的配置参数:
在这里插入图片描述
  关于dragonfly的输入参数,因为文档尚且不完整,所以很难查阅。但dragonfly提供了-help命令,可以看到其参数,下面罗列一下目前所有的可输入参数:

user@ubuntu:~$ ./dragonfly-x86_64 -help
dragonfly-x86_64: a modern in-memory store.

Usage: dragonfly [FLAGS]


  Flags from facade/dragonfly_connection.cc:
    --http_admin_console (If true allows accessing http console on main TCP
      port); default: true;
    注释:是否允许访问主TCP端口的http控制台
    --tcp_nodelay (Configures dragonfly connections with socket option
      TCP_NODELAY); default: false;
    注释:是否使用套接字选项TCP_NODELAY配置dragonglu连接
  Flags from facade/dragonfly_listener.cc:
    --conn_threads (Number of threads used for handing server connections);
      default: 0;
    注释:用于处理服务器连接的线程数
    --conn_use_incoming_cpu (If true uses incoming cpu of a socket in order to
      distribute incoming connections); default: false;
    注释:为true时使用套接字传入CPU来分配传入连接
--tls (); default: false;
    注释:是否开启tls连接
--tls_client_cert_file (cert file for tls connections); default: "";
    注释:tls连接的证书文件
    --tls_client_key_file (key file for tls connections); default: "";
    注释:tls连接的关键文件

  Flags from server/dfly_main.cc:
    --bind (Bind address. If empty - binds on all interfaces. It's not advised
      due to security implications.); default: "";
    注释:绑定地址,为空时绑定所有接口()
--pidfile (If not empty - server writes its pid into the file); default: "";
    注释:非空时服务器将其pid写入指定文件
    --use_large_pages (If true - uses large memory pages for allocations);
      default: false;
    注释:为真时使用大内存页分配

  Flags from server/engine_shard_set.cc:
--backing_prefix (); default: "";
    注释:未知
    --cache_mode (If true, the backend behaves like a cache, by evicting entries
      when getting close to maxmemory limit); default: false;
    注释:为true时后端行为类似缓存,在接近最大内存限制时逐出条目
    --hz (Base frequency at which the server updates its expiry clock and
      performs other background tasks. Warning: not advised to decrease in
      production, because it can affect expiry precision for PSETEX etc.);
      default: 1000;
    注释:服务器更新其到期时钟并执行其他后台任务的基本频率(不建议减少,会影响PSETEX到期精度)
  Flags from server/generic_family.cc:
--dbnum (Number of databases); default: 16;
    注释:数据库上限
    --keys_output_limit (Maximum number of keys output by keys command);
      default: 8192;
    注释:keys命令输出的最大键数
  Flags from server/io_mgr.cc:
    --backing_file_direct (If true uses O_DIRECT to open backing files);
      default: false;
    注释:为true时使用O_DIRECT打开备份文件
  Flags from server/list_family.cc:
    --list_compress_depth (Compress depth of the list. Default is no
      compression); default: 0;
    注释:list的压缩深度,默认不压缩
    --list_max_listpack_size (Maximum listpack size, default is 8kb);
      default: -2;
    注释:最大listpack大小,默认8kb
  Flags from server/main_service.cc:
    --maxmemory (Limit on maximum-memory that is used by the database.0 - means
      the program will automatically determine its maximum memory usage);
      default: 0;
    注释:数据库使用的最大内存限制。0-表示程序将自动确定其最大内存使用量
--memcache_port (Memcached port); default: 0;
    注释:Memcached端口号
    --port (Redis port); default: 6379;
    注释:Redis端口号
  Flags from server/server_family.cc:
--dbfilename (the filename to save/load the DB); default: "dump";
    注释:保存/加载数据库文件名
--dir (working directory); default: "";
    注释:工作目录
    --requirepass (password for AUTH authentication); default: "";
    注释:身份验证密码
  Flags from server/tiered_storage.cc:
    --tiered_storage_max_pending_writes (Maximal number of pending writes per
      thread); default: 32;
    注释:每个线程最大挂起写入数

  Flags from helio/util/proactor_pool.cc:
    --proactor_threads (Number of io threads in the pool); default: 0;
    注释:线程池中io线程数目

  Flags from helio/util/uring/proactor.cc:
    --proactor_register_fd (If true tries to register file descriptors);
      default: false;
    注释:是否注册文件描述符
    --proactor_spin_limit (How many times to spin proactor loop before blocking
      on kernel); default: 10;
    注释:内核阻塞前旋转proactor循环次数
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.

  开启客户端后就能正常输入命令,对于dragonfly的命令兼容了memcache和redis的API,基本保持一致了,目前已经实现了大部分的命令(),详细的命令参数可见:dragonfly API
在这里插入图片描述
  dragonfly在本地端口制作了一个网页(redis是没有的),能够显示当前的一些信息,主要就是对于一些时延的统计什么的,每次需要刷新一下才能看到实时情况:
在这里插入图片描述

二、dragonfly本身的特点

  dragonfly一出来就号称比redis快25倍,同属于内存数据库,能做到这点肯定是有一些特殊的设计,下面就来介绍一下dragonfly的特点:

  1)特点1:多线程

  与redis的单线程设计不同,dragonfly使用多线程进行响应服务。多线程的设计更加符合现代计算机的多核设计,能够更大化的利用系统资源。

  2)特点2:无共享架构

  redis使用单线程结构,不涉及共享。而dragonfly作为多线程,对于多线程的数据传输也没有使用共享架构。对此原因有以下三点:
  (1)可以在公有云中可用服务器充分利用CPU,内存和IO资源,允许线程之间对内存存储键空间分区,每个线程管理自己的数据切
  (2)共享架构可为所有的操作提供原子性的保证,在非常高的吞吐量上保证低时延
  (3)在多CPU的情况下,没有共享架构就不需要停等,CPU的利用率会上升

  3)特点3:新型的锁管理器

  dragonfly为了提供更好的原子性保证,用了一种VLL的新型锁管理器来开发事务框架。借此可以允许在不使用互斥锁或者自旋锁的情况下编写原子操作。

  4)特点4:更多的数据结构

  dragonfly保持了原有的redis的基础数据结构(string set list zset hashset),同时基于hash表开发了一个Dashtable结构保证更好的性能
  关于dash的详细描述在这里(其实是我也没看懂,不知道咋解释~):dragonfly/dashtable

三、redis和dragonfly的对比

  dragonfly一出来就直接对飙redis,说自己可能是宇宙中最快的数据库,比redis快了25倍。对此dragonfly和redis的官方都做出了回应,下面来看看具体的内容吧。

  1)dragonfly官方

  dragonfly官方做了两部分的测试,一个是通过基础测试程序反应的每秒访问次数,另外一个是对内存效率进行测试。
  先来看看环境:dragonfly肯定是单服务器多线程了,对于redis选择的是单服务器单实例进程。
  最后每秒访问次数的结果如下图(图可以在github上找到),dragonfly达到redis25倍性能,在单例(多线程)情况下支持每秒百万次的查询率
在这里插入图片描述
  至于内存效率,分成了两个阶段:空闲阶段(单纯进行查询)、快照阶段(指为了持久性从内存向磁盘的备份阶段),从下面图的结果上看,在空闲阶段下,dragonfly的性能要优于redis30%左右,快照阶段优于一倍多,而且能够保持稳定。
在这里插入图片描述
  从表面的数据上看,dragonfly确实优于redis。但我个人认为对于比较细节描述的不是很详细,有点儿云里雾里的感觉。

  2)Redis官方:

  对于dragonfly的表示,redis官方也给出了回应。回应的详细内容在这里:13 Years Later - Does Redis Need a New Architecture? | Redis
  redis官方认为这样比较是不公平的,他认为单个进程实例不是redis在真实世界的运行模式,redis有集群体制,使用集群才能发挥redis的性能,才能更公平公正的比较出效果。于是redis官方又使用相同的示例数据做了对比实验
  说说环境:redis官方使用redis7.0,用40个节点分片(等同于40个服务器)构成集群和单台机器上dragonfly的64核做比较。得到的实验结果如下:
在这里插入图片描述
  从结果上看,无论是单通道还是多通道,redis的吞吐量都比dragonfly高18%-40%
  其次redis只使用到了vCPU64个其中的40个,而dragongfly用满了64个,暗含redis性能还能提高的意思
在这里插入图片描述
  从实验结果上看,两家各有说法。不过dragonfly的出现也引发了redis对于存储结构的思考。是单线程集群式(横向扩展)还是单机式多线程更好(纵向扩展)。对此redis官方在回应中认为是横向更好,并给出了多点原因的介绍:

  更佳弹性——我们在集群中使用的节点越多,整个集群的健壮性就越强。例如,如果您在三节点集群上运行数据集,且其中一个节点发生降级,则代表有三分之一的集群无法运行;但如果是在九节点集群上运行数据集,同样是其中一个节点发生降级,则只有九分之一的集群无法运行。
  易于扩展——在横向扩展系统当中,向集群添加一个额外节点、并将数据集的一部分迁移到其中要容易得多。与之对应,在纵向扩展系统中,我们只能直接引入一个更大的节点并复制整个数据集……这是个漫长的过程,而且期间随时有可能闹出麻烦。
  逐步扩展更具成本效益——纵向扩展,尤其是云环境下的纵向扩展,往往对应高昂的成本。在多数情况下,即使只需要向数据集内添加几 GB 内容,也需要将实例大小翻倍。
  高吞吐——在 Redis,我们看到很多客户会在小型数据集上运行高吞吐量工作负载,即具有极高的网络带宽及 / 或每秒数据包(PPS)需求。我们以每秒操作数 100 万 + 的 1 GB 大小数据集为例,相较于使用单节点 c6gn.16xlarge 集群(128 GB 内存、64 个 CPU 加 100 Gbps 传输带宽,每小时使用成本 2.7684 美元),三个 c6gb.xlarge 节点(8 GB 内存、4 个 CPU 外加最高 25 Gbps 传输带宽,每小时 0.1786 美元)构成的集群能够将运行成本拉低 20%,而且健壮性反而更高。既然成本效益出色、弹性更强且吞吐量反超,那横向扩展无疑就是比纵向扩展更好的选择。
  贴近 NUMA 架构——纵向扩展还要求使用能容纳更多核心和大容量 DRAM 的双插槽服务器;相比之下,Redis 这样的多处理架构其实更适应 NUMA 架构,因为其行为特征就接近一种由多个较小节点组成的网络。但必须承认,NUMA 跟多线程架构之间也有天然冲突。根据我们在其他多线程项目中的经验,NUMA 可能令内存数据存储的性能降低达 80%。
  存储吞吐量限制——AWS EBS 等外部磁盘的扩展速度,显然不及内存和 CPU。事实上,云服务商会根据所使用设备的类型添加存储吞吐量限制。因此,避免吞吐量限制、满足数据高持久性要求的唯一办法,就是使用横向扩展——即添加更多节点和更多的配套网络附加磁盘。
  临时磁盘——临时磁盘是一种将 Redis 运行在 SSD 上的绝佳方式(其中 SSD 用于替代 DRAM,而非充当持久存储介质),能够在保持 Redis 极高速度的同时将数据库成本保持在磁盘级水平。但临时磁盘也有其上限,一旦逼近这一上限,我们还需要进一步扩展容量——这时候,更好的办法仍然是添加更多节点、引入更多临时磁盘。所以,横向扩展继续胜出。
  商品硬件——最后,我们的很多客户会在本地数据中心、私有云甚至是小型边缘数据中心内运行 Redis。在这类环境中,绝大多数设备内存不超过 64 GB、CPU 不超过 8 个,所以唯一可行的扩展方式就只有横向扩展

参考:https://mp.weixin.qq.com/s/rwK6e2ZuXNUsABES7TpqRg

  除了两官方给出的测试比较外,其实dragonfly在实现细节上也和redis产生了一些不同:
  1)string长度256MB
  2)过期时间限制在4年
  3)支持lua intergers

四、实操测试

  光听官方说,也不知道谁说的对,还是自己使用测试工具测试一下。在此使用的开源测试工具是ycsb。这个工具专门用来测试nosql的性能,其中包含了redis,刚好dragonfly兼容了redis的接口,所以也没问题。
  先介绍一下ycsb吧!
  源码见:GitHub - brianfrankcooper/YCSB: Yahoo! Cloud Serving Benchmark
  这个源码是基于java的,所以使用前先安装java环境(sudo apt-get -y install openjdk-11-jdk)

  代码执行的时候可能报错:/usr/bin/env: ‘python’: No such file or directory
  解决办法见:解决:/usr/bin/env: ‘python’: No such file or directory

  对于ycsb的使用可以参考:YCSB性能测试工具使用

  下面开始对比测试,步骤如下:
  1)开服务器端
  2)执行测试命令

  第一组测试使用redis的单线程进行测试,命令如下:

bin/ycsb.sh load redis -s -P workloads/workloada -p "redis.host=127.0.0.1" -p "redis.port=6379"

bin/ycsb.sh run redis -s -P workloads/workloada -p "redis.host=127.0.0.1" -p "redis.port=6379" \
 -p "operationcount=10000" -p "measurementtype=timeseries" \
 -p "timeseries.granularity=5000"

  对命令进行下解读,在这个命令中设置了1000条命令(后台文件配置),measurementtype会配置Measurements输出时间序列而不是直方图,operationcount表示总共操作次数,使用的YCSB实例操作数,measurementtype是显示延迟测量的方式为timeseries同时设置

  为了让数据更有说服力,选择其中的关键信息保存,然后将实验进行5次

  读写比1:1
  redis统计结果如下(小数位省略):
在这里插入图片描述
  dragonfly统计结果如下(小数位省略):
在这里插入图片描述

  读写比9:1
  redis统计结果(小数位省略):
在这里插入图片描述
  dragonfly统计结果(小数位省略):
在这里插入图片描述
  读写比1:9
  redis统计结果(小数位省略):
在这里插入图片描述

  dragonfly统计结果(小数位省略)
在这里插入图片描述
留一下redis使用:
ubuntu20.04安装redis参考:
https://blog.csdn.net/m0_57394815/article/details/124051159
redis使用:

cd /usr/local/redis
./src/redis-server
./src/redis-cli

学习过程中,看到一些参考资料,在此标注:
Dragonfly安装&配置 Redis和Memcached的现代替代品
redis VS dragonfly(更支持redis):Redis老了吗?Redis与Dragonfly性能比较 (jdon.com)

因作者水平有限,如有错误之处,请在下方评论区指正,谢谢!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐