alibaba / alibaba-rsocket-broker

Alibaba RSocket Broker: Mesh, Streaming & IoT
https://alibroker.info
Apache License 2.0
762 stars 165 forks source link

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

Open YuanHuCoding opened 4 years ago

YuanHuCoding commented 4 years ago

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

YuanHuCoding commented 4 years ago

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

linux-china commented 4 years ago

给我们一些时间测试一下,稍后给大家报告。 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 commented 4 years ago

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

linux-china commented 4 years ago

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

linux-china commented 4 years ago

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

YuanHuCoding commented 4 years ago

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 commented 4 years ago

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

YuanHuCoding commented 4 years ago

将 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 commented 4 years ago

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

YuanHuCoding commented 4 years ago

我们关心的应该是 可回收对象(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,如有误导,概不负责。

pc859107393 commented 4 years ago

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

linux-china commented 4 years ago

备注一下: https://github.com/netty/netty/issues/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 commented 4 years ago

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

hadix-lin commented 4 years ago

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

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