10万Http(单机和集群Server)Subscribe的可行性实验和压测

本文通过实验验证了基于HTTP协议的订阅系统在单机与集群环境下的可行性。在单机环境下,2.5G内存可承受10万连接;通过LVS负载均衡技术,将连接分发到多台服务器,实现了集群的高效运作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0,前言
     前文《基于Http协议订阅发布系统设计 》提到物联网的发布订阅系统是需要能够承受千万级别长连接的。因此,本文从实践的角度,验证基于Http协议的订阅系统的可行性。实验使用当前流行的Java Web开源技术,通过使用Servlet3.0的特性,可以看到单机条件下2.5G左右内存可以承受10万连接。最后,结合LVS的负载均衡技术,将10万连接均衡的负载到两台机器上。通过以上实验,说明企业有可能通过LVS强大的负载均衡能力,搭建千万级别的基于Http协议的发布订阅系统。
1,准备工作
     环境: Linux, Jetty9.2, Jdk1.8-64bit
     因为Unix内核实现的每一个socket连接都对应要打开一个文件,所以实验前需修改Linux系统临时配置,使用ulimit -n 修改单个进程可打开最大文件数(超过10^5)。
      使用ConcurrentHashMap作为connection handler缓存(holder),参数使用默认参数(让map自动扩容): loadFactor= DEFAULT_LOAD_FACTOR = 0.75f; initialCapacity =  DEFAULT_INITIAL_CAPACITY = 1 << 4。
 
2,单机环境实验
  • 初始
     连接数
     由于实验机器有另一个Tomcat占用了8080端口,所以这里使用8088端口启动Jetty服务。
  Jetty默认配置下启动服务的堆快照
  • 建立2*10^4个http连接后
     JVM堆快照
  • 建立5*10^4个http连接后
  JVM堆快照
  • 建立10^5个连接后
     JVM堆快照 
  • 系统和进程运行状态

 
3,多机环境实验
     从上面单机服务下看,保持10万个Http连接,64位JVM大约需要消耗大约2.5G内存(32位JVM更省资源但内存寻址空间小,参见《深入理解Java虚拟机》第二版),这意味着需要超过25G的内存才能勉强承受百万连接,且不说CPU资源的要求。很显然,这种纵向拓展的方式不可行,因为在物联网环境下,硬件资源很快见顶。因此,横向拓展才应是物联网服务的首选。如果选用横向拓展的方式,就意味着集群机器可以运行更省资源的32位JVM,当然集群服务也有一系列问题需要解决。以下,将从集群角度来测试Http订阅请求的资源消耗以及可行性。市面上已有不少中间件支持Http协议的反向代理服务(开源如nginx、haproxy等)来搭建分布式集群,但是需要特别注意的是,订阅请求是一个Http长连接,Client向Server发送的请求将会保持很长时间,这意味着反向代理服务的端口会被一直占用,但用户可用最大端口范围是1024~2^16,这意味着TCP/IP的4层及以上协议的反向代理中间件都是不可行的,因此我们需要使用3层及以下协议的反向代理服务,本文使用开源的LVS(可以工作在3层和2层,不存在端口约束,资源消耗小)。考虑资源问题和实验性原则,本文使用4台机器(3太Linux VM实例,1台Windows),其中2台Request Client,2台Jetty Server,其中1台Server同时执行LVS服务。此外2台Server跑的是不同版本的Jdk(1.8和1.7),这样的目的是顺便检查一下不同JVM内存管理版本下的差异。
     note: LVS集群搭建,新手简易入门( http://www.cnblogs.com/liwei0526vip/p/6370103.html),官方说明( http://www.austintek.com/LVS/LVS-HOWTO)。
 
  • 同样使用ulimit -n 修改每台realserver的单个进程可打开最大文件数
 
  • LVS请求统计

  因为使用的权重是1:1负载,所以两台机器上分配了相等的连接数。

 
  • 机器1(Jdk1.8):连接数和JVM栈数据
 
  • 机器2(Jdk1.7):连接数和JVM栈数据
 
     从上面两台Server的JVM堆快照可以看到,对于10^5个Http请求,LVS均匀地将请求负载到各个机器上去了。因此,使用TCP/IP 3层及以下协议作为负载均衡的集群方案是有可行性的。

转载于:https://www.cnblogs.com/shenjixiaodao/p/7280948.html

在响应式编程中,`flatMap`、`flatMapCompletable` `subscribe` 是 RxJava 中用于处理异步数据流操作符链的重要工具。它们各自有不同的用途行为。 ### flatMap `flatMap` 操作符主要用于将一个发射的数据项转换为一个新的 `ObservableSource` 或者其他类型的可观察源,并且会合并这些新源发出的所有数据到最终的 `Observable` 中。这意味着原始 `Observable` 发出的每一项都可能被映射成多个事项,而这些事项会被打平后放进一个单独的 `Observable` 输出。这种方式非常适合于需要并行处理多个异步任务的情况[^1]。 使用方法示例: ```java observable.flatMap(item -> { // 对每个item进行处理,返回一个新的Observable return newObservableBasedOnItem(item); }) ``` ### flatMapCompletable `flatMapCompletable` 则是专门用来从现有的 `Observable` 转换到 `Completable` 类型的操作符。它接受一个函数作为参数,该函数将原 `Observable` 的每一个元素映射成一个 `CompletableSource`。最终的结果是一个 `Completable`,它可以表示没有具体数据输出但有完成或错误事件的通知。这通常用在只需要关注操作是否成功完成而不关心具体结果的情况下[^3]。 使用方法示例: ```java observable.flatMapCompletable(item -> { // 将item转换为CompletableSource return completableSourceBasedOnItem(item); }) ``` ### subscribe `subscribe` 方法则是订阅 `Observable` 的入口点。一旦调用了 `subscribe`,就会触发整个 `Observable` 链条的执行。你可以提供不同的回调来分别处理正常数据项、异常以及完成事件。这是消费 `Observable` 序列中最基本也是最关键的部分[^5]。 使用方法示例: ```java observable.subscribe( item -> { /* 处理每个数据项 */ }, error -> { /* 处理错误 */ }, () -> { /* 处理完成 */ } ); ``` ### 区别与作用总结 - **区别**:`flatMap` 用于创建新的 `Observable` 并将其内容合并进输出;`flatMapCompletable` 用于转换成不携带数据只报告完成状态的 `Completable`;`subscribe` 是用来启动序列并监听其结果。 - **作用**:三者共同构成了 RxJava 异步编程模型的核心部分,允许开发者以声明式的方式构建复杂的异步逻辑。 - **使用方法**:根据需求选择合适的方法来进行数据转换或者最终的数据消费。 通过合理运用这三个组件,可以非常灵活地构建出各种响应式的应用程序架构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值