遇到真正的高并发问题了,特来求助 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
abcbuzhiming
V2EX    程序员

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

  abcbuzhiming 2018-09-16 20:25:02 +08:00 36326 次点击
这是一个创建于 2632 天前的主题,其中的信息可能已经有所发展或是发生改变。
以前做的项目,要么服务器够多,要么访问量比较分散,一天虽然人多,但是都是不同时段。所以没遭遇到访问瓶颈。这次真刀真枪的需要进行一次单服优化,然后就发现单服性能不可思议的低。大致情况如下:
应用服务器是 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
有个过时的东西叫,内存变硬盘
F281M6Dh8DXpD1g2
    11
F281M6Dh8DXpD1g2  
   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 也是不错的选择。
v2666
    21
v2666  
   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 吧?
Finest
    60
Finest  
   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     Solana     4238 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 66ms UTC 05:33 PVG 13:33 LAX 21:33 JFK 00:33
Do have faith in what you're doing.
ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86