Go 原生net库的问题
Go
原生net库的问题
大连接内存占用
在上一篇文章Go 原生网络库
的源代码分析中我们可以看到,一般Go
的TCP
和HTTP
的程序都是每一个连接启动一个goroutine
去处理。在Go
的理念和设计中,goroutine
是廉价的,成千上万的goroutine
也是轻松的能够被创建,这点决不等同于进程或者线程。成千上万的goroutine
确实小case,但如果是上百万的连接呢,按照现在Go原生网络库
的goroutine-per-connection
模式意味着需要创建上百万的goroutine
去处理,实际上一个连接可能不止创建一个gorituine
,创建一个goroutine
要占用多少内存呢,答案是2kb~8kb
(和操作系统以及Go
相关版本有关)不等,所以如果是数百万连接的话光内存占用可能会有十几个G之多,这也是一个不小的开销了。
调度压力问题
大量的goroutine
创建不仅仅会带来内存占用的问题,还会给Go runtime
调度器的调度带来压力,从而导致调度效率的下降,最直接的表现就是吞吐率的下降、连接延时的增加。另外还记得在之前的Go原生网络库
的文章中源码剖析中的sync.once
epoller
嘛,也就是下面这一段:
serverInit.Do(runtime_pollServerInit)
这里serverInit
是一个sync.Once
类型,这么做可以保证只初始化一个epoll
实例。所以Go原生网络库
是一个单event loop
,也就是连接的处理(连接的建立和读写)和IO
的处理都是被加入到一个epoller
实例的,在同一个event loop
里面处理,这样在海量连接的同时可能会导致性能瓶颈。
以上就是Go
原生net
库的问题,虽然平常很难遇到百万甚至千万级别的goroutine
带来的调度压力和内存占用问题,即使遇到了最不济也是升级机器配置就可以解决,但真的遇到了这样的问题除了简单粗暴的升级机器配置之外还有什么别的办法呢?其实就是放弃Go
原生net
库的这种网络模式,采取更加高效的网络库模式,当然这也意味着放弃了Go
煞费苦心封装后暴露给开发者稳定简单的网络API,需要开发者做更多额外的工作,付出更多的心智。下面就来看看有哪些高性能的网络库模式。
一些高性能网络库模式
Reactor 模式
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
<p> <span style="font-size:14px;">本专刊是Go开源项目源码分析专栏,共 17 篇文章,挑选了Go 开源界知名的 4 个开源项目gnet(高效的网络库)、gin(知名的Go微型web框架)、fasthttp(高性能web框架)、nsq(Go消息队列)来对它们进行源码分析,分析它们的设计思想和代码实现。每个项目的讲解都是由浅入深,由设计思想的剖析到源码实现的分析,更易于读者理解。</span> </p> <p> <br /> </p> <h2> <b><span style="font-size:16px;line-height:1;">购买须知:</span></b> </h2> <span style="font-size:14px;">订阅成功后,用户即可通过牛客网 PC 端、App 端享有永久阅读的权限;</span><br /> <span style="font-size:14px;">牛客专刊为虚拟内容服务,订阅成功后概不退款;</span><br /> <span style="font-size:14px;line-height:1;">在专刊阅</span><span style="font-size:14px;line-height:1;">读过程中,如有任何问题,可在文章评论区底部留言,或添加牛客导师,加入读者交流群;</span><br /> <span style="font-size:14px;">想成为牛客作者,请邮件联系yinxiaoxiao@nowcoder.com,邮件主题【牛客作者+写作方向】,并附上个人简历一份及近期作品一份;</span><br /> <p> <span style="font-size:14px;">牛客专刊版权归本平台所有,任何机构、媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发布 / 发表,违者将依法追究责任</span><span style="font-size:14px;">。</span> </p> <p> <br /> </p>