V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
abcbuzhiming
V2EX  ›  程序员

遇到真正的高并发问题了,特来求助

  abcbuzhiming · 2018-09-16 20:25:02 +08:00 · 35118 次点击
这是一个创建于 2295 天前的主题,其中的信息可能已经有所发展或是发生改变。
以前做的项目,要么服务器够多,要么访问量比较分散,一天虽然人多,但是都是不同时段。所以没遭遇到访问瓶颈。这次真刀真枪的需要进行一次单服优化,然后就发现单服性能不可思议的低。大致情况如下:
应用服务器是 Tomcat,在阿里云上的 4 核心的 xero,8GB 内存,10MB 带宽,技术实现是 spring mvc,并不是特别复杂的计算业务,说难听点仅仅是 crud,而且输出的是纯粹的 json,没有其它的静态文件之类的东西。然后 MySQL 数据库在和应用服务器同一区域的另外一台阿里云服务器上,类似的配置,4 核心,8GB 内存,用的是高效 SSD。
这样的两台(一组)服务器,能抗住多少并发呢,500 不到。。。

然后开始初步分析,发现一个问题,就是哪怕是单纯的数据库读业务,从浏览器请求到服务器,服务器从数据库读取完毕到返回给前端,最快也要 20-30ms 左右,稍微复杂点的数据结构就上 100ms 了,如果按这个计算,每秒每个线程的处理能力理论最快也就 50 个并发请求,4 核心的机器上,JVM 的线程池一般也就核心的 1.5-2 倍,顶多不到 10 个线程,这样一算,单服理论并发处理能力确实只有 500 不到。。。

我不死心于是回头去找以前的类似服务器做测试,结果发现性能是类似的,只不过当年是靠着服务器够多顶住了罢了。

我知道肯定会有人说,上缓存啊,我当然知道上缓存,我的困惑是,难道只有上缓存一条路,那些并发上 w 的都是靠缓存顶住的吗?不上缓存的话,我现在服务器的性能指标到底是否正常?
183 条回复    2018-09-17 19:59:04 +08:00
1  2  
night98
    1
night98  
   2018-09-16 20:33:44 +08:00 via Android
4c8g 应该性能不会这么差,排查下那几个点耗时长再优化
abcbuzhiming
    2
abcbuzhiming  
OP
   2018-09-16 20:36:25 +08:00
@night98 没有长耗时,我检查过数据库,就是最简单的 select 单条记录,从浏览器前端到应用服务器,应用服务器从数据库读取再返回给前端,就要 20-30ms。所以我现在很想找个参照物,这个过程又没有能压到个位数毫秒级的让我见识一下
sujin190
    3
sujin190  
   2018-09-16 20:42:17 +08:00 via Android
没怎么用过 java,但是 python 的 tornado 做的 curd 延时平均差不多 3ms,内网延时普遍应该 1ms 吧,简单 sql 2 到 3ms 可以返回了吧,框架不可能慢吧,spring 应该有性能分析工具吧,可以看看是数据库慢还是框架慢

不过认真说,实际项目 500 感觉不低了吧,还是加机器缓存靠谱
sylxjtu
    4
sylxjtu  
   2018-09-16 20:44:24 +08:00 via Android
@abcbuzhiming 用 show profile 应该能知道在服务端的延时吧,可以知道到底网络问题还是 sql 的问题
ittianyu
    5
ittianyu  
   2018-09-16 20:45:59 +08:00   ❤️ 1
500 就高并发?
你们公司规模得多小,手动滑稽。
让我这个曾经做安卓应届生来给你点小建议

数据复杂的可以考虑 join 拆分成多个单表查询,然后在 java 里面关联起来。
数据长时间不变的上缓存。
几万并发的集群+缓存基本就可以解决。

整个项目几万到十几万的并发,就拆分项目,也就是 SOA 或 微服务。主要是分摊压力,解决数据库和入口大流量瓶颈问题。

what ?在往上怎么办?这么大的用户群,会让我这种应届生来做架构?这种问题,有请下面的大佬来回答。
hopingtop
    6
hopingtop  
   2018-09-16 20:48:10 +08:00 via Android
根据你描述的点可以测试两个点
1. 数据库机器到应用机器的网络,单纯的数据读取
2. 只测试序列化的时间

如果上述都 ok,在考虑线程是否优化,sql 等
ashes1122
    7
ashes1122  
   2018-09-16 20:48:56 +08:00   ❤️ 24
@ittianyu 你连题主的描述和需求都没看完吧?
luban
    8
luban  
   2018-09-16 20:49:26 +08:00 via iPhone   ❤️ 2
500 并发我觉得不低了,工作七八年还没接触过超过 500 并发的系统
lxrmido
    9
lxrmido  
   2018-09-16 20:56:35 +08:00 via iPhone
@ittianyu 你没看题,你这只是解决了你设想的高并发,然而楼主遇上的显然不是

建议楼主换高性能的 RDS
qiuqiuer
    10
qiuqiuer  
   2018-09-16 20:59:18 +08:00 via Android
有个过时的东西叫,内存变硬盘
liprais
    11
liprais  
   2018-09-16 21:00:35 +08:00 via iPhone
现在应届生阅读能力这么差了 ?
老实讲不上缓存 500 并发不低了,不过还是先做 profile 看看时间都花哪了
单表查询 mysql 应该可以做到 5ms 以内没问题
ooTwToo
    12
ooTwToo  
   2018-09-16 21:05:21 +08:00 via iPhone
想要马儿跑得快,又不给马儿吃草?
dengtongcai
    13
dengtongcai  
   2018-09-16 21:08:27 +08:00
20-30ms 整个请求响应过程,确实就算一个普通 select 最低也要这个时间
Ico945
    14
Ico945  
   2018-09-16 21:13:35 +08:00
首先赞同楼上的,用工具看看是哪部分慢。数据库的话 查看你的 crud 语句是不是可以继续优化,表的结构是不是合理
ittianyu
    15
ittianyu  
   2018-09-16 21:19:09 +08:00
@ashes1122 不好意思,确实没往下看了,单机一个 tomcat 200-500 并发是正常的,多加机器,别折腾了。
metrxqin
    16
metrxqin  
   2018-09-16 21:20:20 +08:00
> 这样的两台(一组)服务器,能抗住多少并发呢,500 不到

请把测试相关信息也发出来,比较关键的信息 CPU 负载情况、Tomcat 线程池使用情况、应用数据库连接使用情况,另外在高并发时使用 jstack 打印出最繁忙的线程堆栈。

另外还有主机的带宽使用情况和 ss -s 输出内容。
metrxqin
    17
metrxqin  
   2018-09-16 21:23:44 +08:00
另外还有测试请求内容大小和响应大小。
xiaoshenke
    18
xiaoshenke  
   2018-09-16 21:24:12 +08:00 via Android
性能问题一般就是带宽,数据库,线程数。你这个数据库有点慢了。
lhx2008
    19
lhx2008  
   2018-09-16 21:28:36 +08:00   ❤️ 1
不上缓存的话,用 Netty 上面的异步框架进一步压缩一下多余的开销,然后暴力线程池来等 Mysql,至少能抗两三千吧,具体看业务了。
lhx2008
    20
lhx2008  
   2018-09-16 21:32:01 +08:00
https://github.com/xenv/gushici#%E5%8D%95%E6%9C%BA%E5%8E%8B%E6%B5%8B

vert.x + netty + redis 可以做到超高并发的 10ms 内稳定返回,如果旧项目不好转的话 Spring Webflux + netty 也是不错的选择。
me15000
    21
me15000  
   2018-09-16 21:32:15 +08:00
看看哪个进程占用 cpu 多啊?
是数据库,还是站点啊?

数据库有 sql 性能监控工具分析下 sql 占用
站点问题就看看是哪些页面语句引起的

性能优化的关键是如何找出性能瓶颈
teli
    22
teli  
   2018-09-16 21:32:24 +08:00
吓死我了
这也就真正的高并发

云数据库+分布式+缓存
abcbuzhiming
    23
abcbuzhiming  
OP
   2018-09-16 21:36:09 +08:00
@sujin190 查了一下,发现应用服务器访问数据库服务器的速度并不慢,确实如你说,个位数的 ms 就结束了查询,但是,如果加上前端网络请求,到 json 数据返回,就慢了,无论如何也压不进 10ms,基本都在 20ms 以上
SlipStupig
    24
SlipStupig  
   2018-09-16 21:37:53 +08:00   ❤️ 13
我做过 PVP 游戏服务器,8CORE 8GB 用 mysql 做数据库上线峰值 1500 人,还能扛得住,你目前性能上面感觉是完全够的,如果条件允许可以做这么几件事:

1. 带宽问题 :检查阿里云带宽使用情况
1.1 入口带宽被爬虫或者业务占满了,看一下阿里云带宽情况是不是把带宽撑死了导致业务无法正常工作,解决方案:加大带宽,上 CDN 的话能缓解一下
1.2 线路问题,使用一些云测速工具看一下全国情况,看情况如何,如果正常则可以排除

2. 检查服务器基本状态问题
看一下连接表:如果出现大量“ TIME_WAIT ”,说明被占用了大量链接没正常释放,这个得具体分析没有太好的解决方案

3. 应用配置不当
3.1 本身程序逻辑写的有问题,导致有性能异常缓慢,这个只能做 Profileing,特别是要保证数据库有没正常开关连接,并且没有用数据库做一些计算和 offset 和排序操作。
3.2 tomcat 配置不当,主要表现少量请求下性能正常,并发量大完全打不开,解决方案:优化 Tomcat 配置

4. 数据库问题
4.1 数据数据结构有问题并写了很多垃圾 sql 语句把数据库活活拖死,这个需要开启 slow log 进行分析,并看一下当前查询语句情况,如果从面板上看 qps 很小却速度很慢,基本上可以断定是数据库的问题
4.2 数据库配置不当,mysql 默认配置主要是为了让业务起来而不是高并发,这个主要表现是数据库占用很低但是性能很差,需要做 benchmark

希望能帮上你
abcbuzhiming
    25
abcbuzhiming  
OP
   2018-09-16 21:38:21 +08:00
@lxrmido 你的意思是 MySQL 在这种情况下不行? 4 核 8G 就这点性能?
sagaxu
    26
sagaxu  
   2018-09-16 21:40:29 +08:00 via Android   ❤️ 1
JVM 的线程池一般也就核心的 1.5-2 倍?

对此表示怀疑,只要 cpu 占用率低,内存足够的时候,线程池是核心的 10 倍甚至 100 倍也行。
abcbuzhiming
    27
abcbuzhiming  
OP
   2018-09-16 21:40:31 +08:00
@metrxqin CPU 负载,无论是应用服务器还是数据库服务器,到应用服务器影响明显变慢变卡顿时,CPU 资源的一半都还没吃掉,数据库 CPU 停留在 38-45%之间,应用服务器最高也就 60%的 CPU,内存,带宽,远远没吃满
sujin190
    28
sujin190  
   2018-09-16 21:42:31 +08:00 via Android   ❤️ 1
@ittianyu 是不是对并发有什么误解,500 并发每日已经数百万 pv 了吧。不小了,动辄数万数十万的国内也没几个吧,而且你确定不是整个公司做了大量基础服务支撑而是你自己搞的
abcbuzhiming
    29
abcbuzhiming  
OP
   2018-09-16 21:43:24 +08:00
@SlipStupig 谢了,我现在遇到的情况就是并发量大了就打不开,但是此时服务器的硬件资源 CPU,内存,带宽都没有到吃满的程度
abcbuzhiming
    30
abcbuzhiming  
OP
   2018-09-16 21:45:39 +08:00
@sagaxu 我建议你读一些关于 Java 多线程方面的书,java 的线程都是内核级的线程,没有实现自己的用户线程,这就导致 java 的线程切换是 1 个代价很高的事情。因此才有推荐 java 的线程数大约是逻辑内核的 1.5-2 倍的这个值,因为更多没有,至于你说的 10 倍,100 倍,我保证,你搞这么多线程,不是根本用不上,就是消耗在线程切换上的时间比计算时间还多,毫无意义
sorra
    31
sorra  
   2018-09-16 21:47:13 +08:00
性能测试、性能监控、性能分析,拿到总时间和瓶颈时间的平均值、中位数、方差
你就什么都知道了

附赠一些细节:
- 数据库简单查询可以<1ms,这个 20-30ms 值得分析一下(未必是花在数据库上)。但缓存也早晚要上的
- 你的 Tomcat 线程池大小、数据库连接池大小,弄清楚
- 注意一下日志量,可能影响性能哦
sujin190
    32
sujin190  
   2018-09-16 21:47:37 +08:00 via Android
@abcbuzhiming 那就是框架慢了,是不是加了太多插件,单纯 http 编码解码不可能这么慢的,现在框架大多是插件式的,tornado 延时这么低很大因素就是纯框架,啥多余的都没有,比如另外 php 的 laravel 比较复杂,普通 curd 就已经 100 延时了
ittianyu
    33
ittianyu  
   2018-09-16 21:49:33 +08:00
@sujin190 照你这么说,tomcat*2 就完全够支撑大部分公司的需求了?
照你这并发的理解,随便搞个抢购活动分分钟就宕机。
wdlth
    34
wdlth  
   2018-09-16 21:52:04 +08:00
@abcbuzhiming 你是怎么把对象转换成 JSON 的,直接用 Spring 的 Message Converter 么?
huhu3312
    35
huhu3312  
   2018-09-16 21:53:01 +08:00
我感觉楼主的机器是正常的,你说 json 到页面响应只有 20-30ms,那接口速度很快了啊。建议看看带宽之类的数值,在阿里云 rds 控制台上看看,看看你业务高峰的时候带宽到多少了
cpdyj0
    36
cpdyj0  
   2018-09-16 21:53:23 +08:00
研究下慢在哪里,如果是 io 可以考虑切换到 vert.x 这种异步框架,,,如果是慢在计算就只能加机器了呗。
janxin
    37
janxin  
   2018-09-16 21:53:35 +08:00
单机 500 就是高并发了?我们对 Java 的理解不太一样吧?最起码的系统优化应该做了吧?
sagaxu
    38
sagaxu  
   2018-09-16 21:57:50 +08:00 via Android   ❤️ 2
@abcbuzhiming 你知道四核 cpu 上,10000 个线程的时候,linux 内核做一次线程调度,上下文切换开销多大吗?微秒级别,比较古老的 cpu 上,也不过 10 微秒级别。

而 10000 个线程,通常需要配备 10G 内存。所以我们一般不会开 10000 个这么多,但是几百个上千个是很轻松的,1000 个线程的时候,上下文切换占用 cpu 的开销还不到 10%,完全可以承受。

tomcat 默认线程池大小就是 200,这个数值一般是偏保守的,难道说大部分人都是 100 核以上的机器?



我们之前一个 IO 密集型项目里,几台 backend 都是开 1000 线程或 2000 线程,日 pv 几亿。
abcbuzhiming
    39
abcbuzhiming  
OP
   2018-09-16 21:58:25 +08:00
@wdlth 用的 jackson 来进行 json 序列化
ittianyu
    40
ittianyu  
   2018-09-16 21:58:50 +08:00
@sujin190 忘了说了,抢购只是打个比方(一般 nosql mq 来解决),但每天访问量又不是平均的,高峰期过 1000 并发很常见。你跟我说 500 并发每日不小了,只能说规模不一样。
showecho
    41
showecho  
   2018-09-16 21:59:11 +08:00
技术我不懂,但是 500 并发说很低的人,你们真的实操过吗?
并发 500,一天流量得多少,有多少企业能到?
wuhhhh
    42
wuhhhh  
   2018-09-16 22:00:39 +08:00 via iPhone
tomcat 本身并发访问就 600 是最佳,越往后越容易丢失,大概 1000 左右就会崩溃,所以如果想要做高并发,就必须考虑动态静态资源的分离,用 nginx 做反代或者静态资源存储,动态就靠缓存或者升级服务器来实现,再往上的解决就不是程序员的问题,是架构师本身能力了
SlipStupig
    43
SlipStupig  
   2018-09-16 22:00:45 +08:00
@abcbuzhiming 硬件没问题,多分析代码问题吧
seancheer
    44
seancheer  
   2018-09-16 22:00:52 +08:00 via Android
首先排查网络,磁盘,cpu 问题
然后观察 java gc
最后代码涉及到 io 的地方进行打点,观察方法执行的时延
一步步缩小怀疑段
micean
    45
micean  
   2018-09-16 22:00:59 +08:00
不到 10 个线程,做的 mysql 的 crud 的场景,那能不慢吗?
把线程池加到 200 就正常了
如果你想要异步化的 crud,抛弃 jdbc,转 scala,有人重写了 mysql 的客户端
gsggwbz
    46
gsggwbz  
   2018-09-16 22:02:40 +08:00 via Android
用消息队列进行流量削峰,java 后台服务层用线程池实现并行异步执行,数据层上缓存,并发量集中的页面考虑做成静态页面,减轻服务端压力,负载均衡集群做下。
micean
    47
micean  
   2018-09-16 22:04:15 +08:00
再说一下,一般说的按核心数计算线程数是用来给非阻塞线程的,阻塞线程要按实际情况调试
metrxqin
    48
metrxqin  
   2018-09-16 22:07:26 +08:00
很奇怪,你先试试导出堆栈。
ccnccy
    49
ccnccy  
   2018-09-16 22:11:04 +08:00 via iPhone
前几天有 2 台服务器负载超高,30 左右,看了下很多 time wait, 两台都是 centos 7.1, 看了下其他的 6.9 的都没问题,后面把这两天装回 centos6.9,问题解决。
opengps
    50
opengps  
   2018-09-16 22:20:56 +08:00
首先问下,你的 mysql 在什么硬盘上,云服务器的硬盘性能都很低。
你有必要换 ssd 或者直接使用阿里云提供的 RDS for mysql.

看到很多人觉得 500 不是高并发,我笑了,实际上很多人的项目,使用单台云服务器,根本支撑不到 500 并发,做一次公网环境的压测,会深深地意识到自己技术水平的不足,然后才会理解为什么云架构这么受欢迎(简单说:流量来了加机器即可解决)。
weizhen199
    51
weizhen199  
   2018-09-16 22:28:32 +08:00
500 的并发事务的话,已经非常大了
CoderGeek
    52
CoderGeek  
   2018-09-16 22:28:50 +08:00
1.如果有 slow api 分析看一下是否涉及到 cud 持久化操作调用有问题
2.看一下 sql 的 slow。 优化一下你的 sql
3.阿里云 ecs 的实例类型 是否购买成共享型 cpu 了 被别的人强了资源也会这样 cpu 直接爆了 (仔细观察一下服务器资源)
后面才是代码 gc 和 数据库配置
还有不是核心数据做 log 异步处理一下
D3EP
    53
D3EP  
   2018-09-16 22:29:57 +08:00   ❤️ 1
楼上说的对。你说的线程数是 CPU 核心数的 1.5 或 2 倍 指的是计算密集型的任务。Tomcat 默认 200 个线程。不要看书看得太教条了。多开点线程没啥问题。
CoderGeek
    54
CoderGeek  
   2018-09-16 22:30:31 +08:00
我之前买的几台服务器实例 全部是共享型的 有一次数据库的那台服务器 cpu 直接爆了 前几周 ali 才告诉我 我都要坑死了 挪了二十几台服务器 没气死我了...
SoCrazyStone
    55
SoCrazyStone  
   2018-09-16 22:31:48 +08:00
收藏了,看大佬 battle
CoderGeek
    56
CoderGeek  
   2018-09-16 22:32:56 +08:00
我现在用的是 rds mysql 和自建的核心数据库 仔细看下服务器吧。。。
zorui
    57
zorui  
   2018-09-16 22:34:40 +08:00 via Android   ❤️ 2
@ittianyu 应届生无疑。。。
lxrmido
    58
lxrmido  
   2018-09-16 22:38:16 +08:00
@abcbuzhiming
4 核 8G 不是问题,瓶颈压根就不在 CPU 和内存上,对于 500 个写数据库的并发操作而言,瓶颈在磁盘 IO 上,只是不知道是底层存储云的网络 IO 还是 SSD 的磁盘 IO,假如你们没有对数据库配置比较了解的人的话,换 RDS、加机器的性价比可能会比较高。
Infernalzero
    59
Infernalzero  
   2018-09-16 22:39:06 +08:00
你怕是没改配置还用的是 BIO 吧?
hand515
    60
hand515  
   2018-09-16 22:39:13 +08:00
日志打太多了吗
CoderGeek
    61
CoderGeek  
   2018-09-16 22:42:32 +08:00
你这描述 并发 500 不应该不用缓存的 ... 我这高峰 API qps500+ 都是 3 台你这配置的服务器+slb
一台也顶得住但是你作为线上业务 不应该单台的 单点故障。
ittianyu
    62
ittianyu  
   2018-09-16 22:43:28 +08:00   ❤️ 1
@zorui 那还真是抱歉了, 不是做 java 的我不该来这看了个标题瞄到一个 500 就开始评论。一堆人讽刺,告辞!!

最后说 认为 500 并发很低的人没实操过的,我不想说话(随便开十几台机器做压测会达不到 500 ?),500 那么高的并发,那是不是可以这么理解,99.99%的公司有两三台服务器就够用了。
我又没说单机 500 并发很低,单机能到 300 就不错了,我说的是整个项目 500 并发很低。
算了, 告辞!!
Actrace
    63
Actrace  
   2018-09-16 22:45:58 +08:00   ❤️ 1
阿里云的 vps 你还是要考虑一下超售的问题的。
vnex
    64
vnex  
   2018-09-16 22:47:44 +08:00
@sagaxu #38
请教下

你知道四核 cpu 上,10000 个线程的时候,linux 内核做一次线程调度,上下文切换开销多大吗?微秒级别,比较古老的 cpu 上,也不过 10 微秒级别。

而 10000 个线程,通常需要配备 10G 内存。所以我们一般不会开 10000 个这么多,但是几百个上千个是很轻松的,1000 个线程的时候,上下文切换占用 cpu 的开销还不到 10%,完全可以承受。

这个的计算是:

1000 个线程: 10us * 1000 == 10ms == 1% cpu

10000 个线程: 10us * 10000 == 100ms == 10% CPU

这样吗?
ebony0319
    65
ebony0319  
   2018-09-16 22:49:29 +08:00
上个星期遇到了一个项目,感觉跟楼主差不多,最后临时把阿里云带宽加到 100M 就好了,就是这么神奇。你可以试下是不是带宽的瓶颈。
neoblackcap
    66
neoblackcap  
   2018-09-16 23:01:30 +08:00
@ittianyu 之前就有人做过测试,inner join 跟子查询的性能基本没有区别,在单机 mysql 的情况下更是如此。
jokerlee
    67
jokerlee  
   2018-09-16 23:01:38 +08:00 via Android
加内存缓存 提高 tomcat 线程数到 500
tomcat 一般都是 io 密集操作 线程要开大,不然线程都是 block cpu 跑不满
rogerchen
    68
rogerchen  
   2018-09-16 23:02:37 +08:00
这么简单的问题,群魔乱舞。
profile 一下搞清楚为什么 mysql 毫秒级返回,前端请求加 json 解析需要 20ms+。
如果是网络延迟,多开十倍的线程。
如果是 json encode decode 卡计算,换 rapidjson 这种高效 json 库。
如果 mysql SSD 吞吐打满了,换 RDS。
jdgui
    69
jdgui  
   2018-09-16 23:02:49 +08:00
楼上说 500 并发很小的。。
多半是纸上程序员吧。真的实际坐过这些的应该不会觉得这个小。
ittianyu
    70
ittianyu  
   2018-09-16 23:05:09 +08:00
@neoblackcap 我说的是集群的情况下,减少对数据库的压力,耗时的事放在 java 上做,容易扩展。
我答的时候没细看楼主的问题。
neoblackcap
    71
neoblackcap  
   2018-09-16 23:09:16 +08:00
@sagaxu 为什么要开那么多线程呢?按照 nginx 的思路,要解决大并发以及 IO 密集型业务也不需要那么多的线程吧。过多线程之后徒增上下文切换的成本。毕竟 IO 又不占 CPU 时间片,用 IO 复用机制加非堵塞 IO 解决不好么?
jokerlee
    72
jokerlee  
   2018-09-16 23:14:10 +08:00 via Android
@neoblackcap 你要理解同步模型和异步模型的区别
rogerchen
    73
rogerchen  
   2018-09-16 23:16:09 +08:00
@neoblackcap 无脑加线程本来就是解决 IO 的合理方法之一,特别是规模小的时候
tcsky
    74
tcsky  
   2018-09-16 23:16:48 +08:00
你试试调大线程池,

你说的线程数微多与核心数 一般针对的是 cpu 密集型的应用, 如用来一些异步框架
io 阻塞的情况下 需要调大线程数, 看你 API 相应时间在小几十 ms, 你调整线程数到 100 试试. cpu 跑满后 qps 会趋于稳定

500 并发其实不小了,普通应用一天 10 小时算, 都快 2000 万 pv 了, 另外只要不是连续的突发流量, 应用都撑得住的, 一般应用用的 tcpserver 自带队列,或者会抛弃超出负载的连接. 对应现象是响应时间变长, 或部分请求会失败
palmers
    75
palmers  
   2018-09-16 23:19:41 +08:00
我也觉得应该把各个业务节点的耗时整理出来然后再讨论优化 这样才会有着力点 才会知道是网络需要优化还是业务需要优化 不要小看每一个点的优化 累计是很客观的
wjqxhy
    76
wjqxhy  
   2018-09-16 23:20:17 +08:00
个人觉得可能测试的模型是建连接,发请求,断连接这个完整的过程
建连接是比较耗时的,如果用 ab 测试工具的话,应该是能看到这部分的耗时,看是不是较高

如果是的话,看看服务器端是否支持了 keep-alive,如果支持,使用 ab 测试的话可以加-k 进行,或者用 wrk 工具
另外也可以调整内核参数优化性能
neoblackcap
    77
neoblackcap  
   2018-09-16 23:26:48 +08:00
@jokerlee 那两个模型理解啊,就是理解了我才觉得多线程没法很好地解决 IO 密集业务。linux 下线程上下文切换虽然成本低,但是多了也不少啊。
而且基本上所有 linux 的 IO 都能设置成非堵塞 IO,加上 IO 复用机制,这个不是将 CPU 更好地利用么?我是没法想象出一个不能用 IO 复用机制+非堵塞 I+线程池替代单纯多线程处理的场景。因此我才觉得这个场景比较奇怪,想问问当成为什么这样考量。
neoblackcap
    78
neoblackcap  
   2018-09-16 23:28:03 +08:00
@rogerchen 你这样一说我倒是可以理解,不过这个始终不是长久之计,毕竟线程多了,上下文切换成本高,得不偿失。
tcsky
    79
tcsky  
   2018-09-16 23:29:32 +08:00
@neoblackcap 两种模型各有优缺点,
异步模型开发成本会更高一点, 如果业务很轻, 需要支撑大量的 tcp 连接, 走异步模型比较合适.
其他情况下开线程就行,简单快速, 性能损耗也不明显.
jokerlee
    80
jokerlee  
   2018-09-16 23:31:03 +08:00 via Android
@neoblackcap 一般应用根本用不着去抠线程上下文切换的性能消耗 而且业务层不是都能写成无阻塞模型的
misaka19000
    81
misaka19000  
   2018-09-16 23:31:14 +08:00
@ittianyu #5。。。不知道你做过多大的并发数? 500 已经不低了
tachikomachann
    82
tachikomachann  
   2018-09-16 23:33:11 +08:00 via Android
mark
4c8g 两台机器,500 并发的话,算挺高了。
best1a
    83
best1a  
   2018-09-16 23:41:31 +08:00   ❤️ 2
并发和 QPS 是两个不同的概念...
lolizeppelin
    84
lolizeppelin  
   2018-09-16 23:41:57 +08:00 via Android
不写 java 但是楼上提到的 100m 带宽的解决方向是没错的

你们用虚拟机还是要了解下云服务器的网络和存储架构的

老在代码和自己的服务器上找问题很可能是找不到结果的
neoblackcap
    85
neoblackcap  
   2018-09-16 23:43:24 +08:00
@jokerlee @tcsky 这样我觉得其实架构师需要背锅了。出来久了,面试多,项目做多了,我觉得一个合格的架构师的确是需要预估业务量的。然后选择合适的架构。以前还好觉得很多项目都很容易做烂,不过我现在觉得,刚开始选一个性能高一些的架构的确是好事。开发效率其实可以从外部库来提升的。比如现在基于 openresty 的东西他们的性能都不差,业务写起来其实跟其他的框架也不会差到哪里去。
因为以前自己也干过无脑加线程的事情,但是业务高上去的话,的确解决不了。自己后来也反省,并发这事情啊其实跟 IO 密不可分,比较好解决的一个就是用户态线程(erlang, golang),二就是 IO 复用+非堵塞 IO+线程池即 one thread one loop + 线程池的架构。
无脑加线程的确可以解决一部分问题,但是假如业务是往上走的话,很快就会出问题的。因为单纯地加线程跟规模不是线性的关系。
hcymk2
    86
hcymk2  
   2018-09-16 23:47:53 +08:00
xiaoshenke
    87
xiaoshenke  
   2018-09-16 23:49:16 +08:00 via Android
@ittianyu 别人嘲讽你是因为,真实的线上环境不是只有单次 crud 的简单业务场景,而是比如有多层调用,甚至调用那种有时候几秒才能响应的第三方服务的真实复杂场景,在这种情况下,500 并发已经是非常高了。
sampeng
    88
sampeng  
   2018-09-16 23:49:33 +08:00 via iPhone
都扯了一些有的没得。都很有道理。500 并发不低。但单机真的也谈不上特别高。但这个看和什么比。所有性能对比是要有参照物的

有几个问题 lz 没有交代
这个性能瓶颈你是怎么得到的,是 500tps 左右接口开始打不开?
请先做基准测试。同样项目框架,连数据库,随便查一条,输出 json。每一步算一个测试用例。这就是你的基准测试了。哪一步有问题,问题就出在哪。正常情况是基准测试效率都在可接受范围内。

其次,用测试工具测试,所谓评价一定是响应时间是个慢慢变大的过程。如果延迟一直没变化,但是接口打不开了。那问题在你的容器开始拒绝新的连接。和其他都无关。


查性能问题,我的经验就是控制变量,一个一个查。很好查的。lz 的用例还算简单。应该不难。

曾经更多次查一些无法控制变量的性能问题才叫噩梦
luozic
    89
luozic  
   2018-09-16 23:51:21 +08:00 via iPhone
基准 benckmark 撸上几把,研究一下瓶颈。 实际不上缓存 nginx+lua 可以搞到 5000qps 单机
xiaoshenke
    90
xiaoshenke  
   2018-09-16 23:55:06 +08:00 via Android
楼主对于线程的理解…我只能说你大概是运维吧。对于 io 密集型的业务场景,你等一个 io 可能是 ms 级别的时间,相比之下切换线程带来的损耗微乎其微。如果是 cpu 密集型的,确实加线程反而因为增加切换上下文而不会有效果
sampeng
    91
sampeng  
   2018-09-16 23:56:12 +08:00 via iPhone   ❤️ 2
看了楼下回复,资源还没用就不响应了。这可能就是我说的,逻辑处理很快,但是拒绝新的连接进来。

经验里,几个可能。
1,linux 内核问题,tcp 用完,文件句柄用完了。看看最高的时候 socke 数是多少? ss -s ?
2,和 linux 类似,是 mysql 拒绝新连接。也就是 mysql 连接池。java 一般 redis 和 mysql 都是连接池。可以试试放大一倍。
3,java 容器拒绝,线程池就那么大。新的连接进来被等待。
jokerlee
    92
jokerlee  
   2018-09-16 23:56:58 +08:00 via Android
@neoblackcap 我就这么说吧 国内大厂 java 的业务层就没有大规模应用非阻塞模型的,原因是完全的非阻塞模型带来的性能提升一般也就是 20%,而开发难度的提升一倍都不止

应用层和中间件的技术选型考量是不一样的,应用层要兼顾开发效率,你当然可以说去用 openresty nidejs go 之类原生支持非阻塞模型或者协程的语言框架,但是这就是另一个技术选型的复杂问题了
tcsky
    93
tcsky  
   2018-09-16 23:57:19 +08:00
@neoblackcap 一般需要考虑点比较多, 例如团队技术栈, 业务场景, 历史系统; 其实一个项目拆解后, 各层侧重点不太一样. 一般像前端网关或 API 部分期望能支持更多并发, 业务处理部分则倾向于第三方组件完善, 开发调试简单, 其他人易于理解等. 另外一般真出现加机器都解决不了时, 基本公司已经比较成规模 l, 内部各系统方案就更多种多样了.
sampeng
    94
sampeng  
   2018-09-16 23:57:37 +08:00 via iPhone
测一下基准,不要在原油项目上测。一般问题都很好解决
xiaoshenke
    95
xiaoshenke  
   2018-09-16 23:59:57 +08:00 via Android
@jokerlee 服了,你哪里看到的? dubbo 就是用 nio 写的…现在谁写框架不用非阻塞 io ……
jokerlee
    96
jokerlee  
   2018-09-17 00:05:45 +08:00 via Android
楼主这个问题从经验上看就是 tomcat 线程池跑满了,请求排队了。

这个问题可以这么确定,在系统高延时看一下系统的 cpu 磁盘 网络 内存有没有任意一项被打满了,没有的话就不要去优化代码了,调调各种配置先让某个资源打满再说
sagaxu
    97
sagaxu  
   2018-09-17 00:10:43 +08:00 via Android
@neoblackcap 因为异步代码比同步的难写的多,写框架和底层还行,业务逻辑错综复杂,比如同步循环里阻塞调用其它服务,根据其它服务的返回值做 break 或者 continue,异步的方式也能无脑写吗?

小项目堆机器更划算,3 个 15k 开发能搞定的事情,换成异步可能要 4 个 30k 的开发,一年多 100 万成本,加 10 台高配服务器都够了。嫌弃 cpu 切换开销大?来 20 个核,只做切换,别的啥也不干。

1000 线程时,切换开销比前置 nginx 的开销还小,把一个只占不到 1/10 的东西优化到 0,提升也不明显。
jokerlee
    98
jokerlee  
   2018-09-17 00:12:33 +08:00 via Android
@xiaoshenke 你试试用 rxjava 或者 java8 自带的 CompletableFutrue 写个复杂业务试试,比同步模型写代码速度慢不知道几倍,java 只要不加协程,业务层就不可能大规模应用非阻塞模型
xiaoshenke
    99
xiaoshenke  
   2018-09-17 00:18:56 +08:00 via Android
@jokerlee 你说的是 rxjava 啊… rxjava 只是响应式风格 api 吧不是非阻塞模型
xiaoshenke
    100
xiaoshenke  
   2018-09-17 00:20:19 +08:00 via Android
@jokerlee 不过这玩意不是很熟 不做评价
1  2  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2782 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 31ms · UTC 13:04 · PVG 21:04 · LAX 05:04 · JFK 08:04
Developed with CodeLauncher
♥ Do have faith in what you're doing.