Skip to content
This repository has been archived by the owner on Jul 16, 2024. It is now read-only.

EMQ可以达到百万单机长连接数,咱们这个RSocket Broker单机长连接数大概能达到多少? #38

Open
YuanHuCoding opened this issue Mar 5, 2020 · 14 comments
Labels
question Further information is requested

Comments

@YuanHuCoding
Copy link

EMQ可以达到百万单机长连接数,咱们这个RSocket Broker单机长连接数大概能达到多少?

@YuanHuCoding
Copy link
Author

YuanHuCoding commented Mar 5, 2020

http://rsocketbyexample.info/rsocket-broker/index.html 这篇文章有提到:关于长连接的数量,不同语言实现的Broker性能不太一样,如基于Java开发的Broker,单机连接总数在30-50万之间,而C++ Broker可以做到单机100万左右。如果有更多连接,目前RSocket Broker通过集群方案进行解决。
那意思是性能上还是比不上EMQ????物联网几百万设备连接下是不是还是得用EMQ?

@linux-china
Copy link
Collaborator

linux-china commented Mar 5, 2020

给我们一些时间测试一下,稍后给大家报告。 Netty在一定的硬件资源下能支持100万并发连接,但是还要快速响应,程度高的流量负载,这个需要一个可靠性测试,大家可以看一下这个文章: https://github.com/smallnest/C1000K-Servers https://colobu.com/2015/07/14/performance-comparison-of-7-websocket-frameworks/

Netty, Go, Node.js, Undertow, Vert.x都能正常建立百万连接。 Jetty, Grizzly 和 Spray未能完成百万连接
Netty表现最好。内存占用非常的少, CPU使用率也不高。 尤其内存占用,远远小于其它框架

我们给出的这个单机数据,是之前内部基于Netty测试的经验值,可能还需要更新。 RSocket Broker目前设计是支持多租户的,我们也是希望支持更多的连接,但是受限于语言和框架,当然还有稳定性和功能等考虑,在PK支持做大连接数这个方面,我们可能不会刻意和其他语言对比连接数上的优势。

我们在做一个RSocket纯C的SDK,到时应该和业内的单机最大连接数系统应该都会一致的,但是使用C来实现Broker,这个可能相对比较难一些。

目前RSocket C SDK主要是为IoT设备接入提供支持的,当然RSocket Broker也会提供MQTT的gateway,也是基于Netty的MQTT开发的。

@YuanHuCoding
Copy link
Author

YuanHuCoding commented Mar 7, 2020

Netty默认情况下的策略是每8个对象回收1个,能否设置为全部回收(相当于100%绿色无污染,不给GC添负担)来提高并发性能?对于这种高并发、长连接场景,咱们测试时都是怎么配置Netty相关参数的( Netty里的Recycler对象池漏洞netty/netty#9394 )

@linux-china
Copy link
Collaborator

@YuanHuCoding 遇到Nettty高手啦。测试没有任何配置,能给一个Netty调优的建议吗? 我添加到wiki中,也方便其他人了解具体的细节和Netty配置对线上产品的性能影响。 :)

@linux-china
Copy link
Collaborator

@YuanHuCoding 我看到PR已经merge啦,如果使用这个特性,要做这么调整吗?

@YuanHuCoding
Copy link
Author

YuanHuCoding commented Mar 9, 2020

Netty对象池源码注释版和bug测试代码发你邮箱了,仅供参考。
对象池的其他相关参数如下:
io.netty.recycler.ratio (8)
有概率的丢弃 缓存对象, 1/8的概率

io.netty.recycler.maxCapacityPerThread (io.netty.recycler.maxCapacity (4096))
使用 内部的 threadlocal 的 objectPool时, 每个线程的最大threadlocal 的容量。

io.netty.recycler.maxSharedCapacityFactor (2)
多线程之间共享 objectPool 数量因子 (TODO)

io.netty.recycler.maxDelayedQueuesPerThread (NettyRuntime.availableProcessors() * 2)
Recycler 跨线程的最多数量

io.netty.recycler.linkCapacity (16)
WeakOrderQueue 中线程可以缓存的对象数量

@linux-china
Copy link
Collaborator

@YuanHuCoding 问一个 问题, io.netty.recycler.ratio 默认为8,如果是长连接场景,是不是设置为1后就进行全部回收啦? 这种做法对RSocket更于好一些?

@YuanHuCoding
Copy link
Author

YuanHuCoding commented Mar 19, 2020

将 io.netty.recycler.ratio设置为1的意思,就是用完的对象不再丢弃给GC处理,回收再利用。
不一定全部回收,还要满足下面几个条件:
io.netty.recycler.maxCapacityPerThread (io.netty.recycler.maxCapacity (4096))
使用 内部的 threadlocal 的 objectPool时, 每个线程的最大threadlocal 的容量。
io.netty.recycler.maxSharedCapacityFactor (2)
多线程之间共享 objectPool 数量因子 (TODO)
io.netty.recycler.maxDelayedQueuesPerThread (NettyRuntime.availableProcessors() * 2)
Recycler 跨线程的最多数量
io.netty.recycler.linkCapacity (16)
WeakOrderQueue 中线程可以缓存的对象数量

如果并发高峰期是1000并发,那么会有1000个可回收对象;
如果再到低谷200并发,那么就有800个高峰期回收的对象一直占着内存,浪费了空间;

我觉得对于那种并发数很稳定的情况,将 io.netty.recycler.ratio设置为1,性能最好。
但是也要考虑并发降下来后,有没有必要去移除那些多余的回收对象。

其他相关资料:
在Netty中,所有的IO操作基本上都要涉及缓冲区的使用,无论是上文说的HeapBuffer还是DirectBuffer,如果对于这些缓冲区不能够重复利用,后果是可想而知的。对于堆内存则会引发相对频繁的GC,而对于直接内存则会引发频繁的缓冲区创建与回收,这些操作对于两种缓冲区分别带来严重的性能损耗,Netty基于ThreadLocal实现的轻量级对象池实现在一定程度上减少了由于GC和分配回收带来的性能损耗,使得Netty线程运行的更快,总体性能更优。
总体上基于内存池技术的缓冲区实现,优点可以总结如下:
 对于PooledHeapBuffer的使用,Netty可以重复使用堆内存区域,降低的内存申请的频率同时也降低了JVM GC的频率。
 对于PooledDirectBuffer而言,Netty可以重复使用直接内存区域分配的缓冲区,这使得对于直接内存的使用在原有相比HeapBuffer的优点之外又弥补了自身分配与回收代价相对比较大的缺点。

@linux-china
Copy link
Collaborator

linux-china commented Mar 19, 2020

@YuanHuCoding 对于RSocket的使用情况来说,如机房内部,即便流量降低,这个长连接也不会断的,除非我们将这些服务器或者容器关闭啦。如果是IoT的场景,如手机长连接到云端,即便我们睡觉啦,但是这个连接还是不断的,这个可能和HTTP流量有些区别,如果是这个情况,我们评估一个最大连接数,如50万,那么io.netty.recycler.ratio为2是不是比较合理? 高峰和低峰对RSocket的连接数影响并不大。 如果是这样的情况,我还需要主要什么吗?
内存的情况,目前和你说的一样,目前使用的是PooledByteBufAllocator的direct Buffer,这个也是默认方式。 应用中我们做了一些元信息的bytebuf缓存,都是direct buffer。

@YuanHuCoding
Copy link
Author

YuanHuCoding commented Mar 20, 2020

我们关心的应该是 可回收对象(PooledDirectByteBuf、ThreadLocalDirectByteBuf、WriteAndFlushTask、WriteTask等)的利用率。
和你用的是不是长连接,好像没有多大关系。

Netty框架里使用Recycler的地方有:
Recycler<PooledDirectByteBuf>、Recycler<ThreadLocalDirectByteBuf>、Recycler<Entry>、Recycler<WriteAndFlushTask>、Recycler<WriteTask>、Recycler<PendingWrite>、Recycler<RecyclableArrayDeque>、Recycler<RecyclableArrayList>

在IoT的场景下,设置io.netty.recycler.ratio为1,再分如下两种情况讨论:
a)50w长连接+白天业务高峰期:在长连接中流动的是新闻推送、聊天等高频业务。Netty需要创建的可回收对象很多,比如200w,且这200w一直被回收利用,利用率接近100%;
b)50w长连接+半夜业务低峰期:在长连接中流动的是心跳等低频业务。Netty需要的可回收对象很少,只需要50w,利用率25%。多出的150w对象无用武之地(貌似除了多占点内存,也没什么坏处,是不是更费电,我就不清楚了);

另外,官方对io.netty.recycler.ratio的注释里提到了一点,避免爆发式的请求:
// By default we allow one push to a Recycler for each 8th try on handles that were never recycled before.
// This should help to slowly increase the capacity of the recycler while not be too sensitive to allocation
// bursts.
// 回收因子,默认为8。
// 即默认每8个对象,允许回收一次,直接扔掉7个,可以让recycler的容量缓慢的增大,避免爆发式的请求
RATIO = safeFindNextPositivePowerOfTwo(SystemPropertyUtil.getInt("io.netty.recycler.ratio", 8));

我们是不是可以考虑改造源码,改成:
a)高峰期:动态的从8缓慢的过渡到1。回收对象利用率从12.5%逐渐上升到100%;
b)低峰期:动态的从1过渡到8再过渡到1。实际只需要50w可回收对象,多出的无用武之地的150w对象慢慢的被去库存了,回收对象利用率也逐渐从25%上升到100%,内存占用也降下来了;

其他考虑:目前Recycler的数据结构是否可以优化改造?是否可以将回收操作丢给专门的线程池来处理?

另外,除了Netty里使用Recycler,我们自己的业务也应该用。
我们可以对中间件编制一个GC回收指标,来衡量中间件的“能耗比”。

还有一点要注意:并不是io.netty.recycler.ratio为1,就100%被回收,还有其他几个参数会影响回收,Recycler源码中共有7处代码会根据这些参数来评估是否回收(可以搜索我发你的注释版里的drop(Object value)方法)。

终极目标:保持可回收对象的利用率为100%,不给GC添负担。

PS:我没用过Netty,以上内容纯属YY,如有误导,概不负责。

@linux-china linux-china added the question Further information is requested label Apr 12, 2020
@pc859107393
Copy link

首先说一下,在服务器上面跑的,我们要应对业务增量以及解决微服务调用延时问题(我这边业务场景需要实时交互要求延时很低),需要将连接一直保活同时加入断线监测机制实现快速重连自动重连。iot场景中,我们的设备存活状态也需要感知,同时需要加入一定的策略,比如说设备长时间不使用是否需要断开链接,链接不稳定短时间内持续重连断开的动作又怎么办?这个时候设置百分百回收是否可行?所以说这个回收指标,应该适当考虑。

@linux-china
Copy link
Collaborator

备注一下: netty/netty#10348

The title doesn't look good to me. We built our Load Balancer on top of Netty and doing 10M connections is a piece of cake for us now. So I'm pretty sure Netty is not stopping you from 1k request in 1 connection, must be something else.

@pc859107393
Copy link

netty适当的调优内网环境下达成百万链接这个是没问题的,问题是不是每个团队都有这样的开发能力,所以我们需要合理的技术选型,再考察每个技术选择是否符合期望值。当然对你们阿里系的产品,还是期望值蛮高的。

@hadix-lin
Copy link

首先说一下,在服务器上面跑的,我们要应对业务增量以及解决微服务调用延时问题(我这边业务场景需要实时交互要求延时很低),需要将连接一直保活同时加入断线监测机制实现快速重连自动重连。iot场景中,我们的设备存活状态也需要感知,同时需要加入一定的策略,比如说设备长时间不使用是否需要断开链接,链接不稳定短时间内持续重连断开的动作又怎么办?这个时候设置百分百回收是否可行?所以说这个回收指标,应该适当考虑。

@pc859107393 回收对象重用的知识我是第一次在 @YuanHuCoding 的回复中学习到,我认为这个意思是在很高压的业务场景中,适当调整这些参数可以降低GC频率和DirectBuffer的重复创建成本,提升内存效率(应该跟我们常说的CPU能效比类似)。跟重连,保活,连接健康监测这些不是一个话题。而这些内容作为一个维护长连接的基础Broker而已应该都是基础能力,我想RSocket Broker没理由不提供完善支持的,这方面可以研究一下RSocket Broker和Netty的连接管理方法即可。

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants