29

百万 Go TCP 连接的思考: 正常连接下的吞吐率和延迟

 5 years ago
source link: https://colobu.com/2019/02/28/1m-go-tcp-connection-3/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

这一篇文章介绍了I/O密集型服务器和计算密集型的服务器的两种场景,对多epoller服务器和goroutine-per-connection服务器两种服务器进行测试,连接数分别是5000、2000、1000、500、200和100。

第一篇 百万 Go TCP 连接的思考: epoll方式减少资源占用

第二篇 百万 Go TCP 连接的思考2: 百万连接的吞吐率和延迟

第三篇 百万 Go TCP 连接的思考: 正常连接下的吞吐率和延迟

相关代码已发布到github上: 1m-go-tcp-server

前两篇的是有巨量连接的情况下服务器的性能,这类服务器可能应用于消息推送、IOT、页游等场景,追求的是大量连接,并发量相对不大的场景。还有一类场景是服务器的连接数不多,几十几百,最多几千的TCP连接,比如公司内的服务之间的调用等,这类服务器在不同的实现下的性能是怎样的?

测试区分两个场景: I/O密集型和计算密集型。I/O密集型的服务比如文件的读取、数据库的访问,远程服务的调用等等,计算密集型的访问比如区块链的挖矿、算法的计算、类似redis这样的基于内存的数据处理服务等等(当然redis还是memory bound类型的服务)。

我们通过 time.Sleep 让goroutine休眠来模拟I/O密集型的服务,实际goroutine休眠和真正的I/O密集型的服务还是有区别的,虽然它们都有一定的耗时,goroutine在等待的过程中会休眠,但是I/O密集型还有大量的I/O访问,比如磁盘、网络等等。出于方便测试的目的,我们还是使用 time.Sleep 来模拟,主要测试goroutine在休眠一段时间后对性能的影响。

计算密集型的访问我们采用挖矿算法,通过计算hash值,满足一定的挖矿难度让CPU进行大量的计算动作。

测试分别采用并发连接数为 5000、2000、1000、500、200、100,测试对应的吞吐率和延迟。

测试使用多epoller的方式实现的服务器和goroutine-per-connection实现的服务器。因为连接数少,我们可以采用goroutine-per-connection的方式。

九、 I/O 密集型的服务器(无sleep)

首先测试I/O密集型的服务器,在没有sleep的情况下,两个服务器的数据对比如下:

多epoller服务器

代码: 10_io_intensive_epoll_server

5000 2000 1000 500 200 100 tps 210064 203027 207097 208460 200798 212587 latency(s) 23.2 9.1 4.5 2.3 0.9 0.5

吞吐率变化不大,基本都在误差以内,延迟随着连接数的降低而降低,基本成线性关系。

服务器可以达到20万的吞吐率。

goroutine-per-connection 服务器

代码: 11_io_intensive_goroutine

5000 2000 1000 500 200 100 tps 203038 208002 209128 207990 209192 212376 latency(s) 24 9.2 4.6 2.3 0.9 0.5

可以看到,当服务器的业务简单,基本没有耗时的情况下,这两种实现的差别不大,基本一样。

十、 I/O 密集型的服务器 (sleep 10 ms)

我们模拟I/O耗时10毫秒的情况,两个服务器的数据对比如下:

多epoller服务器

5000 2000 1000 500 200 100 tps 6218 6256 6251 6108 6027 4736 latency(s) 0.8 0.3 0.2 0.08 0.04 0.03

吞吐率急剧下降。

goroutine-per-connection 服务器

5000 2000 1000 500 200 100 tps 203088 194783 98895 49326 19747 9886 latency(s) 0.02 0.01 0.01 0.01 0.01 0.01

可以看懂吞吐率会和连接数相关,但是也不是线性关系,随着连接数的增加,所带来的吞吐率收益也慢慢的变弱,也就是有一个拐点,连接数的增加带来的吞吐率的增加将变得很小。

看它的延迟时间,连接数2000以下延迟就是都是业务所耗费的时间(10毫米)。

这给了我们一个启示,在连接数比较小的情况下,正统的goroutine-per-connection可以取得很好的延迟,并且为了提高吞吐率,我们可以适当增加连接数。

十一、 计算密集型服务器

采用挖矿算法,计算哈希值,如果哈希值的前12bit都是0的话算挖矿成功。

多epoller服务器

代码: 12_cpu_intensive_epoll_server

5000 2000 1000 500 200 100 tps 212554 227291 224509 229796 226687 226147 latency(s) 0.02 0.01 0.004 0.002 0.001 0.0005

吞吐率基本不变,但是延迟随着连接数的降低而成线性降低。

goroutine-per-connection 服务器

代码: 13_cpu_intensive_goroutine

5000 2000 1000 500 200 100 tps 211048 212343 228978 228756 228768 229425 latency(s) 0.02 0.01 0.005 0.002 0.001 0.0005

吞吐率和多epoller方式基本一致,延迟也一样。 可以看出对于计算密集型的服务,这两种方式的性能差别不大。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK