构建高性能高并发Java系统 .
1,使用异步通信
异步通信显然可以更快的返回响应。从实际经验看,对高吞吐服务器更大的好处是,系统中的某一服务出现问题后往往出现雪崩似的服务宕机。这很多都是由于采用同步通信,需要等待其他服务同步通信结束后,其占用资源才能得到释放。而这些资源往往是socket连接、线程、数据库连接等比较重的资源。因此请慎重使用同步通信。如果你真的需要他,可以用个mock同步。正如Tim Yang所说:很多远程服务调用是在关键路径中,它可以容忍失败,但是不能容忍堵塞。
2,使用NIO
NIO几乎是Java cluster的基石。大量分布式开源项目Thrift, ZooKeeper等都基于此项技术。其好处是用较低的系统开销处理大量消息。在Intel(R) Pentium(R) 4 CPU 3.00GHz/1G内存的普通PC上跑基于NIO/TCP的RTSP测试,每秒处理1K个RTSP消息是没有问题的。关于NIO的架构可以参考开源项目MINA,但要注意的是,不要直接用处理NIO消息的线程处理逻辑。
3,尽量不使用锁
如果你在高性能服务器逻辑中看到同步锁,就要小心了。我们希望服务器可以同时并发的尽量多的处理请求,而同步锁恰恰摁住了业务的咽喉。同时如果线程设计有问题而导致大量线程争夺同一把锁,最坏的情况(超过1K+线程)我曾见过JVM要用几个小时来调度一个线程占锁(为什么?请牛人解释)。解决的办法就是:1,尽量不用。可能么?在一定程度上是可能的,比如我曾使用一致性哈希算法解决资源sticky的问题。用算法替代同步,是一个思路;2,尽量减少锁的范围,事同步锁影响的逻辑越少越好。效果也很明显;3,使用数据库更新替代同步也是一个思路,虽然我自己不是很喜欢,但是从实际效果看使用数据库,特别是用存储过程。在压力不大的情况也是个简单有效的方法。
4,减少GC
Full GC对Java服务器性能的影响是致命的,特别是当JVM管理着较大内存时。即使是在小型应用,例如Old区只分配512M内存,一次Full GC都可能耗时2~3秒,这意味着你所有的服务都会中断。尽量减少Full GC的次数绝对是我们的目标。
首先,合理的配置GC参数,采用ParallelGC和 ConcMarkSweepGC,即并发和增量GC。CMS,全称Concurrent Low Pause Collector,CMS用两次短暂停来替代串行标记整理算法的长暂停。
第二,打出GC log,在性能测试阶段,检查你的GC是否OK。系统在线测试时也可以提供宝贵的track。
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
给出一个实际服务器GC参数为例,
|
1 |
JAVA_OPTS=" -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+DisableExplicitGC |
|
2 |
JAVA_OPTS=" -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=8 |
|
3 |
JAVA_OPTS="-Xms256m -Xmx640m -XX:NewSize=128m -XX:MaxNewSize=256m -Xss128k |
|
4 |
JAVA_OPTS=" -XX:PermSize=64m -XX:MaxPermSize=128m |
|
5 |
JAVA_OPTS=" -XX:SurvivorRatio=14 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=16 |
5,数据库前Cache
用queue缓存数据,一次写入多个数据。可以用多个线程同时写入数据库。在实际系统中,用多个线程同时读取cache并写入Mysql是效率很高的。
6,增加数据库索引
看起来很弱对吧?可是我真的遇到过靠加个简单的索引解决过一个很严重的性能问题。系统瓶颈的多数问题都存在于数据库和线程的使用不当上,所以还是要强调一下。
7,Master-Slave Mysql
Mysql有一篇很有名的文章来解释在Master-Slave结构下提高读效率的文章。大致就是说Mysql基准测试下max_read=1200次/s。在读写比例为9:1的情况下,通常写的时间比读的时间多一倍。假设有N个slave,如果只用slave来读,公式如下:
Max reads = 1200 – 2 * writes
Max Reads = 9 * writes / (N + 1) (读为9倍的写,平均到N+1个Mysql上)
9 * writes / (N + 1) + 2 *writes = 1200
Writes = 1200/ (2 + 9/(N+1))
结论是N=1,每秒增加到184次写
N = 8,增加到400次写
其中需要考虑的是复制多份binlog所占的网络带宽和对Master Mysql的影响。但我们在实际应用中认为mysql master-slave binlog增量同步是非常迅速且没有察觉到对性能的负面影响。但一般来说,既然memcached可以很好解决read问题,很少有team做这么大规模的mysql cluster。但小于等于4个还是可以考虑的。
总结,合理的使用异步通信,线程调度,优化GC和解决数据库瓶颈往往可以是构建高性能高并发Java消息处理服务器的利器。但这仅限于逻辑业务相对简单的即时通信系统,如果是设计大量cache调度,比如网页调度。或者是设计海量数据处理服务器,则需要考虑更多的问题。
构建高性能高并发Java系统 .的更多相关文章
- Java高并发秒杀系统API之SSM框架集成swagger与AdminLTE
初衷与整理描述 Java高并发秒杀系统API是来源于网上教程的一个Java项目,也是我接触Java的第一个项目.本来是一枚c#码农,公司计划部分业务转java,于是我利用业务时间自学Java才有了本文 ...
- 浅谈千万级PV/IP规模高性能高并发网站架构(转自老男孩)
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://oldboy.blog.51cto.com/2561410/736710 如果把来 ...
- 高吞吐高并发Java NIO服务的架构(NIO架构及应用之一)
高吞吐高并发Java NIO服务的架构(NIO架构及应用之一) http://maoyidao.iteye.com/blog/1149015 Java NIO成功的应用在了各种分布式.即时通信和中 ...
- PHP-学习大规模高并发Web系统架构及开发推荐书籍
以下书籍内容涵盖大型网站开发中几个关键点:高可用.高性能.分布式.易扩展.如果想对大规模高并发Web系统架构及开发有很系统的学习,可以阅读以下书籍,欢迎补充! 一.<Linux企业集群—用商用硬 ...
- 高性能高并发服务器架构设计探究——以flamigo服务器代码为例
这篇文章我们将介绍服务器的开发,并从多个方面探究如何开发一款高性能高并发的服务器程序. 所谓高性能就是服务器能流畅地处理各个客户端的连接并尽量低延迟地应答客户端的请求:所谓高并发,指的是服务器可以同时 ...
- 【高并发】Redis如何助力高并发秒杀系统,看完这篇我彻底懂了!!
写在前面 之前,我们在<[高并发]高并发秒杀系统架构解密,不是所有的秒杀都是秒杀!>一文中,详细讲解了高并发秒杀系统的架构设计,其中,我们介绍了可以使用Redis存储秒杀商品的库存数量.很 ...
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- 浅谈千万级PV/IP规模高性能高并发网站架构
高并发访问的核心原则其实就一句话“把所有的用户访问请求都尽量往前推”. 如果把来访用户比作来犯的"敌人",我们一定要把他们挡在800里地以外,即不能让他们的请求一下打到我们的指挥部 ...
- (转)浅谈千万级PV/IP规模高性能高并发网站架构
浅谈千万级PV/IP规模高性能高并发网站架构 原文:http://blog.51cto.com/oldboy/736710 文章架构简图: 高并发访问的核心原则其实就一句话“把所有的用户访问请求都 ...
随机推荐
- go构造函数
go构造函数 结构体没有构造函数,你可以创建一个函数返回一个相应类型的实例代替(类似一个工厂): func NewSaiyan(name string, power int) *Saiyan { re ...
- Android Studio androidx 包冲突解决方法
如果包冲突了会包如下这样的错: Android dependency 'androidx.core:core' has different version for the compile (1.0.0 ...
- python实现线程池(2.4)
线程池 什么是线程池? 诸如web服务器.数据库服务器.文件服务器和邮件服务器等许多服务器应用都面向处理来自某些远程来源的大量短小的任务. 构建服务器应用程序的一个过于简单的模型是:每当一个请求到达就 ...
- linux开机故障解决方法
无法进grub方法1光盘或者网络引导进入Rescue切换原机系统 chroot /mnt/sysimage/ 安装grub grub-install /dev/sda 方法2 直接命令 grub-in ...
- CPU指令集的虚拟化(x86)
IA-32 (x86)[edit] Main article: X86 virtualization The IA-32 instruction set of the Pentium processo ...
- 【Java多线程系列一】Java实现线程方法
Java实现线程的两种方法 继承Thread类 实现Runnable接口 它们之间的区别如下: Java的类为单继承,但可以实现多个接口,因此Runnable可能在某些场景比Thread更适用 Thr ...
- vue项目使用js-xlsx进行excel表格的导入和导出方法的简单原型封装
前提:已经安装好 file-saver xlsx和 script-loader,如未安装,请查看 https://www.cnblogs.com/luyuefeng/p/8031597.html 新建 ...
- 豆瓣图书Top250
从豆瓣图书Top250抓取数据,并通过词云图展示 导入库 from lxml import etree #解析库 import time #时间 import random #随机函数 import ...
- python-selenium -- 弹出框处理
弹出框有两种:页面弹出框(可定位元素能操作).Windows弹出框(不能直接定位) 一.页面弹出框 等待弹出框出现之后,定位弹出框,操作其中元素 如: driver = webdriver.Chrom ...
- 36-Ubuntu-用户管理-01-新建用户useradd
创建用户/设置密码/删除用户/确认用户信息 序号 命令 作用 说明 01 sudo useradd -m -g 组名 新建用户名 添加新用户 -m 自动建立用户家目录 -g 指定用户所在的组,否则会建 ...