ETCD 读写性能测试以及和Redis的简单对比

6,087 阅读3分钟

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

  • 📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!
  • 📢本文作者:由webmote 原创,首发于 【掘金】
  • 📢作者格言: 生活在于折腾,当你不折腾生活时,生活就开始折腾你,让我们一起加油!💪💪💪

🎏 序言

官方定义:etcd 是一个高度一致的分布式键值存储,它提供了一种可靠的方式来存储需要由分布式系统或机器集群访问的数据。它可以优雅地处理网络分区期间的领导者选举,即使在领导者节点中也可以容忍机器故障。

ETCD最常用的功能就是在配置中心中保存系统配置,而我们很清楚,配置中心属于读多写少的场景,并且需要配置具有强一致性,因此在这样的场景下,ETCD在合适不过了。

🎏 01.到底有多慢

官方网站放出的基准测试为: Benchmarked at 1000s of writes/s per instance,这是什么鬼啊?

有些业务场景,最需要的是高一致性,在保证高一致性的基础上,能提升高并发当然是更好的了。当然如果硬上ETCD,其实官方是不建议用在高性能的场景下的。

既然在某些特性上,已经天选为ETCD,那么我们就测试下ETCD的读写性能吧。

虚拟机搭建3节点ETCD 3.3.11,配置为 4cpu/2GB,编写测试程序,最简单方式,使用grpc底层通讯,单线程读、单线程写。

代码如下:

EtcdClient etcdClient = new EtcdClient("http://192.168.137.100:2379,...");  

var resp = etcdClient.Put("foo/bar", "barfoo");

WatchRequest request = new WatchRequest()
{
    CreateRequest = new WatchCreateRequest()
    {
        Key = ByteString.CopyFromUtf8("foo/a"),
        RangeEnd = ByteString.CopyFromUtf8("foo/z"),
    }
};
//print在不同的线程内执行
etcdClient.Watch(request, print);

Task.Run(() =>
{
    Thread.Sleep(1000);
    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < 10000; i++)
    {     
        etcdClient.Put($"foo/bar{i}", $"barfoo333-{i}");       
    }
    sw.Stop();
    Console.WriteLine($"100 Key write  : {sw.ElapsedMilliseconds} ms");
    Thread.Sleep(10000);
    Console.WriteLine($"100 Key Read  : {_ms} ms");
});
private static void print(WatchResponse response)
        {          
           ...    
        }

经过几次测试,ETCD 3节点的读写性能指标出炉啦:

image.png

一口老血喷出,咋这么慢~

经过和高手们沟通,确定这么慢的速度并不是ETCD的真实表现,应该是在虚拟机器人的硬盘速度太慢导致的,因此需要更改为SSD磁盘才能展示ETCD的真实实力。

🎏 02.更换硬盘为SSD

复制一个虚拟机,是分分钟的事情,把其更改为SSD上后,再次测试,结果达到了理想状态。

image.png

写的QPS达到了 1333 ,在这个配置下,已经很不错了。

额外测试了下通知事件,其执行是在不同的线程ID内,因此消费端如果有业务,则需要保持事务性不冲突。

另外,ETCD的优势是可以监控1组Key的变化,

  • 同时监听一个范围的key(比如:我可以监听key=foo/a ~ foo/z 。这是ETCD一个重要的功能)
  • 消费者消费速率不同,不会影响消息的消费。

🎏 03.对比Redis

既然写到这里了,也对比下Redis的性能指标,Redis采用Pub/sub方式构建。 毕竟是内存数据库,读写的性能是非常高的。 部分代码:

var _conn = ConnectionMultiplexer.Connect("192.168.137.101");

var db = _conn.GetDatabase();
var sub = _conn.GetSubscriber();
sub.Subscribe("channel1", (channel, val) =>
{
    _sw.Restart();               
     Console.WriteLine($"{channel}: {val }");

    _sw.Stop();
    _ms += _sw.ElapsedMilliseconds;
});

10000 Key write : 1312 ms;
10000 Key Read : 351 ms

🎏 04. 进击的Etcd

单线程Etcd写速度太慢了,因此加大对线程的投入,测试100个线程对Etcd的写,读取还是按照通知方式读取。

核心代码如下:

 Parallel.ForEach(Enumerable.Range(0, 100), n =>
{
    for (int i = 0; i < 100; i++)
    {
        conn.Put($"foo/a{i}", $"hhhhhhhhhhhhhhhhhhhxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx{i}");
    }
    //Thread.Sleep(1000);
});

整体的性能有了质的飞跃,这次应该比较接近理论值了:

image.png

写QPS达到了 24570;
读QPS也提升到: 19267;

对比下官方的BenchMarks,感觉还是不错的。

image.png

🎏 05. 小结

ETCD应该是可以应用到业务中了,毕竟我们的业务并发量并没有那么高,可是这个场景也适合Redis啊,性能不是瓶颈,只是业务上需要做出一致性的保障,既然有DB的托底,应该也不是问题!

所以架构永远是在折中,各种因素在里面,并没有说必须如何如何!

养成一个好习惯,需要不停的激励和鼓励,写作的能力也许就是不断的写中提升的,当然还有自身的额能力,在不断的输出过程中,发现自己的不足以及巩固自己的知识。

30天不停更,目标很远大,今天是第五天,加油吧,兄弟们!

例行小结,理性看待!

结的是啥啊,结的是我想你点赞而不可得的寂寞。😳😳😳

👓都看到这了,还在乎点个赞吗?

👓都点赞了,还在乎一个收藏吗?

👓都收藏了,还在乎一个评论吗?