前言

每一种该语言在某些极限情况下的表现一般都不太一样,那么我常用的Java语言,在达到100万个并发连接情况下,会怎么样呢,有些好奇,更有些期盼。
这次使用经常使用的顺手的netty NIO框架(netty-3.6.5.Final),封装的很好,接口很全面,就像它现在的域名 netty.io,专注于网络IO。
整个过程没有什么技术含量,浅显分析过就更显得有些枯燥无聊,准备好,硬着头皮吧。

测试服务器配置

运行在VMWare Workstation 9中,64位Centos 6.2系统,分配14.9G内存左右,4核。
已安装有Java7版本:

java version "1.7.0_21"
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)

在/etc/sysctl.conf中添加如下配置:

fs.file-max = 1048576
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_mem = 786432 2097152 3145728
net.ipv4.tcp_rmem = 4096 4096 16777216
net.ipv4.tcp_wmem = 4096 4096 16777216 net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

在/etc/security/limits.conf中添加如下配置:

     *	soft nofile 1048576
* hard nofile 1048576

测试端

测试端无论是配置还是程序和以前一样,翻看前几篇博客就可以看到client5.c的源码,以及相关的配置信息等。

服务器程序

这次也是很简单呐,没有业务功能,客户端HTTP请求,服务端输出chunked编码内容。

入口HttpChunkedServer.java:

唯一的自定义处理器HttpChunkedServerHandler.java:

启动脚本start.sh

达到100万并发连接时的一些信息

每次服务器端达到一百万个并发持久连接之后,然后关掉测试端程序,断开所有的连接,等到服务器端日志输出在线用户为0时,再次重复以上步骤。在这反反复复的情况下,观察内存等信息的一些情况。以某次断开所有测试端为例后,当前系统占用为(设置为list_free_1):

                  total       used       free     shared    buffers     cached
Mem: 15189 7736 7453 0 18 120
-/+ buffers/cache: 7597 7592
Swap: 4095 948 3147

通过top观察,其进程相关信息

    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
4925 root 20 0 8206m 4.3g 2776 S 0.3 28.8 50:18.66 java

在启动脚本start.sh中,我们设置堆内存为6G。

ps aux|grep java命令获得信息:

  root      4925 38.0 28.8 8403444 4484764 ?     Sl   15:26  50:18 java -server...HttpChunkedServer 8000

RSS占用内存为4484764K/1024K=4379M

然后再次启动测试端,在服务器接收到online user 1023749时,ps aux|grep java内容为:

  root      4925 43.6 28.4 8403444 4422824 ?     Sl   15:26  62:53 java -server...

查看当前网络信息统计

  ss -s
Total: 1024050 (kernel 1024084)
TCP: 1023769 (estab 1023754, closed 2, orphaned 0, synrecv 0, timewait 0/0), ports 12 Transport Total IP IPv6
  • 1024084 - -

    RAW 0 0 0

    UDP 7 6 1

    TCP 1023767 12 1023755

    INET 1023774 18 1023756

    FRAG 0 0 0

通过top查看一下

  top -p 4925
top - 17:51:30 up 3:02, 4 users, load average: 1.03, 1.80, 1.19
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
Cpu0 : 0.9%us, 2.6%sy, 0.0%ni, 52.9%id, 1.0%wa, 13.6%hi, 29.0%si, 0.0%st
Cpu1 : 1.4%us, 4.5%sy, 0.0%ni, 80.1%id, 1.9%wa, 0.0%hi, 12.0%si, 0.0%st
Cpu2 : 1.5%us, 4.4%sy, 0.0%ni, 80.5%id, 4.3%wa, 0.0%hi, 9.3%si, 0.0%st
Cpu3 : 1.9%us, 4.4%sy, 0.0%ni, 84.4%id, 3.2%wa, 0.0%hi, 6.2%si, 0.0%st
Mem: 15554336k total, 15268728k used, 285608k free, 3904k buffers
Swap: 4194296k total, 1082592k used, 3111704k free, 37968k cached
<span class="hljs-selector-tag">PID</span> <span class="hljs-selector-tag">USER</span>      <span class="hljs-selector-tag">PR</span>  <span class="hljs-selector-tag">NI</span>  <span class="hljs-selector-tag">VIRT</span>  <span class="hljs-selector-tag">RES</span>  <span class="hljs-selector-tag">SHR</span> <span class="hljs-selector-tag">S</span> %<span class="hljs-selector-tag">CPU</span> %<span class="hljs-selector-tag">MEM</span>    <span class="hljs-selector-tag">TIME</span>+  <span class="hljs-selector-tag">COMMAND</span>

4925 root 20 0 8206m 4.2g 2220 S 3.3 28.4 62:53.66 java

四核都被占用了,每一个核心不太平均。这是在虚拟机中得到结果,可能真实服务器会更好一些。 因为不是CPU密集型应用,CPU不是问题,无须多加关注。

系统内存状况

  free -m
total used free shared buffers cached
Mem: 15189 14926 263 0 5 56
-/+ buffers/cache: 14864 324
Swap: 4095 1057 3038

物理内存已经无法满足要求了,占用了1057M虚拟内存。

查看一下堆内存情况

  jmap -heap 4925
Attaching to process ID 4925, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 23.21-b01 using parallel threads in the new generation.

using thread-local object allocation.

Concurrent Mark-Sweep GC Heap Configuration:

MinHeapFreeRatio = 40

MaxHeapFreeRatio = 70

MaxHeapSize = 6442450944 (6144.0MB)

NewSize = 629145600 (600.0MB)

MaxNewSize = 629145600 (600.0MB)

OldSize = 5439488 (5.1875MB)

NewRatio = 2

SurvivorRatio = 1

PermSize = 52428800 (50.0MB)

MaxPermSize = 52428800 (50.0MB)

G1HeapRegionSize = 0 (0.0MB) Heap Usage:

New Generation (Eden + 1 Survivor Space):

capacity = 419430400 (400.0MB)

used = 308798864 (294.49354553222656MB)

free = 110631536 (105.50645446777344MB)

73.62338638305664% used

Eden Space:

capacity = 209715200 (200.0MB)

used = 103375232 (98.5863037109375MB)

free = 106339968 (101.4136962890625MB)

49.29315185546875% used

From Space:

capacity = 209715200 (200.0MB)

used = 205423632 (195.90724182128906MB)

free = 4291568 (4.0927581787109375MB)

97.95362091064453% used

To Space:

capacity = 209715200 (200.0MB)

used = 0 (0.0MB)

free = 209715200 (200.0MB)

0.0% used

concurrent mark-sweep generation:

capacity = 5813305344 (5544.0MB)

used = 4213515472 (4018.321487426758MB)

free = 1599789872 (1525.6785125732422MB)

72.48054631000646% used

Perm Generation:

capacity = 52428800 (50.0MB)

used = 5505696 (5.250640869140625MB)

free = 46923104 (44.749359130859375MB)

10.50128173828125% used 1439 interned Strings occupying 110936 bytes.

老生代占用内存为72%,较为合理,毕竟系统已经处理100万个连接。

再次断开所有测试端,看看系统内存(free -m)

               total       used       free     shared    buffers     cached
Mem: 15189 7723 7466 0 13 120
-/+ buffers/cache: 7589 7599
Swap: 4095 950 3145

记为list_free_2

list_free_1list_free_2两次都释放后的内存比较结果,系统可用物理已经内存已经降到7589M,先前可是7597M物理内存。
总之,我们的JAVA测试程序在内存占用方面已经,最低需要7589 + 950 = 8.6G内存为最低需求内存吧。

GC日志

我们在启动脚本处设置的一大串参数,到底是否达到目标,还得从gc日志处获得具体效果,推荐使用GCViewer

GC事件概览:

其它:
 

总之:

  • 只进行了一次Full GC,代价太高,停顿了12秒。
  • PartNew成为了停顿大户,导致整个系统停顿了41秒之久,不可接受。
  • 当前JVM调优喜忧参半,还得继续努力等

小结

Java与与Erlang、C相比,比较麻烦的事情,需要在程序一开始就得准备好它的堆栈到底需要多大空间,换个说法就是JVM启动参数设置堆内存大小,设置合适的垃圾回收机制,若以后程序需要更多内存,需停止程序,编辑启动参数,然后再次启动。总之一句话,就是麻烦。单单JVM的调优,就得持续不断的根据检测、信息、日志等进行适当微调。

  • JVM需要提前指定堆大小,相比Erlang/C,这可能是个麻烦
  • GC(垃圾回收),相对比麻烦,需要持续不断的根据日志、JVM堆栈信息、运行时情况进行JVM参数微调
  • 设置一个最大连接目标,多次测试达到顶峰,然后释放所有连接,反复观察内存占用,获得一个较为合适的系统运行内存值
  • Eclipse Memory Analyzer结合jmap导出堆栈DUMP文件,分析内存泄漏,还是很方便的
  • 想修改运行时内容,或者称之为热加载,默认不可能
  • 真实机器上会有更好的反映

吐槽一下:
JAVA OSGI,相对比Erlang来说,需要人转换思路,不是那么原生的东西,总是有些别扭,社区或商业公司对此的修修补补,不过是实现一些面向对象所不具备的热加载的企业特性。

测试源代码,下载just_test

----------------------------------------------------------------------------

广而告之,让您自由畅游网络~
再超值提供一个近期2015年有效的9折优惠码:10off2015


作为码农,严重推荐!

100万并发连接服务器笔记之Java Netty处理1M连接会怎么样的更多相关文章

  1. 并发编程学习笔记之Java存储模型(十三)

    概述 Java存储模型(JMM),安全发布.规约,同步策略等等的安全性得益于JMM,在你理解了为什么这些机制会如此工作后,可以更容易有效地使用它们. 1. 什么是存储模型,要它何用. 如果缺少同步,就 ...

  2. Java Netty简介

    Netty和Mina是Java世界非常知名的通讯框架.它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户netty.io(http:// ...

  3. [转帖]Java Netty简介

    Java Netty简介 https://www.cnblogs.com/ghj1976/p/3779820.html Posted on 2014-06-10 13:41 蝈蝈俊 阅读(2992) ...

  4. Netty 100万级高并发服务器配置

    前言 每一种该语言在某些极限情况下的表现一般都不太一样,那么我常用的Java语言,在达到100万个并发连接情况下,会怎么样呢,有些好奇,更有些期盼. 这次使用经常使用的顺手的netty NIO框架(n ...

  5. Java 多线程与并发【知识点笔记】

    Java 多线程与并发[知识点笔记] Java多线程与并发 先说一下线程与进程的由来: 在初期的计算机,计算机只能串行执行任务,并且需要长时间的等待用户的输入才行 到了后来,出现了批处理,可以预先将用 ...

  6. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(二) 之 ChatServer搭建,连接服务器,以及注意事项。

    上篇:ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取) 上一篇我们已经完成了初步界面的搭建工作,本篇将介绍IM的核心内容 ...

  7. 通过MSSQL连接服务器连接至Oracle数据库

    前言 有很多时候,我们需要MSSQL与Oracle进行跨库查询或数据交互.本篇随笔将阐述如何通过MSSQL的连接服务器连接至Oracle数据库,并且读取数据的示例. 具体步骤 首先需要到Oracle的 ...

  8. 无法远程连接服务器上的mysql

    使用mysql管理工具连接服务器删过得mysql,显示连接被拒绝,但是在服务器上是可以登录mysql的. 无法远程连接通常以下几种情况: 首先,关闭mysql.        service mysq ...

  9. PUTTY无法远程连接服务器故障解决[转]

    对于一个刚刚了解putty工具的新手来说,在putty工具使用中有时出现了问题而无法解决.今天就来介绍怎么解决putty无法远程连接服务器的故障. 用putty远程连接服务器时,提示错误 server ...

随机推荐

  1. 洛谷P3383 【模板】线性筛素数(Miller_Rabin)

    题目描述 如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内) 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示查询的范围和查询的个数. 接下来M行每行 ...

  2. 基于Linux平台Softimage XSI 演示

     2009年底上映的<阿凡达>是电影特效的巅峰之作,就在本月初上映的变形金刚3每次观看之后看得眼花缭乱总能让我热血沸腾,要是自己能做出那样的特效该多好,Linux下研究Maya已经有一段日 ...

  3. Android Studio 解决unspecified on project app resolves to an APK archive which is not supported

    出现该问题unspecified on project app resolves to an APK archive which is not supported as a compilation d ...

  4. javafx tabPane

    public class EffectTest extends Application { @Override public void start(Stage primaryStage) { prim ...

  5. C++集合运算函数总结 & 需要有序集合的操作

    前提:两个集合已经有序.merge() //归并两个序列,元素总个数不变,只是将两个有序序列归并为一个有序序列.set_union() //实现求集合A,B的并.set_difference()//实 ...

  6. 利用JAVA反射机制实现调用私有方法

    1.fragment是AccessibilityFragment的對象.须要被調用的方法的類. setAccessible(true)并非将方法的訪问权限改成了public.而是取消java的权限控制 ...

  7. 开源 java CMS - FreeCMS2.3会员积分记录

    原文地址:http://javaz.cn/site/javaz/site_study/info/2015/28995.html​ 项目地址:http://www.freeteam.cn/ 积分记录 从 ...

  8. 跟着鬼哥学so改动,三,作业篇

    作业: 通过前面两篇文章的学习.请自行分析此应用,将当前用户类型改动为Gold Vip 用户. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3VpZ3V ...

  9. cluster discovery概述及FaultDetection分析

    elasticsearch cluster实现了自己发现机制zen.Discovery功能主要包括以下几部分内容:master选举,master错误探测,集群中其它节点探测,单播多播ping.本篇会首 ...

  10. Objc执行时读取和写入plist文件遇到的问题

    以下是本猫保持游戏NPC和物件交互的plist文件: 随着游戏和玩家逐步发生互动,玩家会改动人物和物件的交互的状态.这也是RPG游戏最主要的功能. 在切换每一个地图时须要将上一个地图发生的改变存储到p ...