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)
因作者水平有限,如有错误之处,请在下方评论区指正,谢谢!