背景
疫情初期某地政府决定发放一批收费口罩面向该市市民,该市市民均可收费预约支付,预约工夫为早上 9 点 -12 点,因而该场景为限时抢购类型场景,会面临十分大的定时超大流量超大并发问题,在该项目标落地过程中,波及的架构演变,做了一些记录和思考。
架构图 & 剖析 -V1
原始架构图示 & 剖析(2 月 2 号早晨 22 点左右的原始架构)
2 月 2 号早晨 22 点左右的原始架构
- 客户端走 HTTPS 协定间接拜访 ECS;
- ECS 上应用 Nginx 监听 HTTPS 443 端口;
- Nginx 反代 Tomcat,Nginx 解决动态文件,Tomcat 解决动静申请;
- 程序先去 Redis 查缓存,如未命中则去数据库查问数据,同时 Redis 与 Mysql 之间的数据同步靠程序控制。
这样架构设计:
- 长处:易治理,易部署;
- 毛病:性能差,无扩展性,存在单点危险;
后果:事实证明该利用一经上线就立即被打挂了,因未知起因预约页面被泄露,导致还未到预约工夫,服务即被打挂。
架构图 & 剖析 -V2
随后我方染指,进行架构调整,24 点左右找的咱们,早上 9 点要开服,工夫太紧,工作太重,程序不能动的状况下,几十万的并发架构如何做?
2 月 3 号早上 9 点左右的架构,4 号也复原了这个架构)
2 月 3 号早上 9 点左右的架构
- 接入 SLB,通过镜像横向扩大负载能力;
- 接入读写拆散数据库架构,通过阿里云数据库主动进行读写拆散,主动同步数据;
- 调整 Nginx 协定;
- 同架构备集群启用(域名解析做了两个 A 记录);
- 剖析拜访日志发现失败起因在获取短信和登陆初始化 Cookie 的点上。
这样架构设计:
- 长处:减少了高可用性,扩大了负载能力;
- 毛病:对流量预估有余,动态页面也在 ECS 上,因而 SLB 的出带宽一度达到最大值 5.X G,并发高达 22w+。
后果:因为流量太大导致用户一度打不开页面,同时因为域名服务商 XX 的限度,客户无奈自助增加解析,且当晚分割不到域名服务商客服,导致 CDN 计划搁浅。
架构图 & 剖析 -V3
2 月 5 号的架构
- 接入 CDN 分流超大带宽;
- 勾销 Nginx 的代理;
- 做了新程序无奈准时上线的灾备切换计划(没想到还真用到了);
- 应用虚构服务器组做新老程序的切换,然而毛病是一个七层监听的 SLB 后端只能挂 200 个机器,再多 SLB 也扛不住了,导致老程序刚承接的时候再度挂掉;
- 5 号应用这个架构上线,7 分钟库存售罄,且体验极度流程,丝般顺滑,衰弱同学开发的新程序真是太爽的。
这样架构设计:
- 长处:CDN 累赘动态资源的流量升高了 SLB 的出带宽,压测的成果也十分现实;
- 毛病:须要多一个独立的域名在页面外面,波及跨域,4 号临开服之际测试发现入库 & 预约短信乱码返回,紧急切换回了老程序,即二代架构。
现实架构图 & 剖析 -V4
现实架构
- 主域名接入 CDN;
- CDN 通过设置回源 Http、Https 协定去拜访 SLB 的不同监听实现新老程序之间的切换,具体实现为回源协定对应。不同监听,监听对应不同的程序。
这样架构设计:
- 长处:动态减速升高 SLB 带宽,动静回源,无跨域问题,切换不便;
- 毛病:仍需手工设置,镜像部署 ecs 不不便,如果工夫短缺,能够间接上容器的架构该有多美妙呢,一个 scale 能够扩进去几十上百的 pod,也能够做节点主动扩容。
总结
工夫紧工作重,遇到了 N 多的坑:
- vcpu 购买额度;
- SLB 后端挂载额度;
- 客户余额有余欠费停机;
- 域名服务商解析须要分割客服能力增加;
- 第一次思考 CDN 架构的时候未思考跨域问题;
- 新程序开发期间未连贯主库测试,导致上线失败(主库乱码);
- 第一次(3 号)被打挂的时候只关注了站长交易 SLB 的流量,未详细分析失败最多的环节;
- 上线前压测缺失,纯靠人工测试性能;
- 压测靠人手一台 Jmeter(4 号早晨到 5 号早上引入了 PTS 进行压测);
- 忽然想起来客户原始的程序是放在 Windows 上的,Windows + 烂程序性能真的极差;
- 这个“小我的项目”前后居然消耗了小十万,如果一开始就给咱们做的话,应该能够缩小一半的老本。
最初的成绩统计(采样剖析,理论数据比这个还大):
成绩统计(采样剖析)
最初上线的三代架构,为了保险起见上了 150 台机器,然而依据流动期间的察看,以及对压测后果的评估,上 50 台机器应该就能够抗住了,从继续 5 小时始终解体被终端用户骂街,到 7 分钟库存售罄的领导赞叹,尽管经验了 3 个通宵的戮战,仍然能够模摸糊糊感觉到身心都失去了升华。
各种优化笔记
参数优化
- 网络调参
`net.ipv4.tcp_max_tw_buckets = 5000` _--> 50000_
`net.ipv4.tcp_max_syn_backlog = 1024` _--> 4096_
`net.core.somaxconn = 128` _--> 4096_
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_timestamps = 1(5
和
6
同时开启可能会导致
nat
上网环境建联概率失败
)
`net.ipv4.tcp_tw_recycle = 1`
- /etc/security/limits.conf
soft nofile 65535
hard nofile 65535
- nginx 参数优化
`worker_connections 1024`_-->10240;_
`worker_processes 1`_-->16;__(依据理论状况设置,能够设置成__auto__)_
`worker_rlimit_nofile 1024`_-->102400;_
`listen 80 backlog 511`_-->65533__;_
局部场景也能够思考 nginx 开启长连贯来优化短链接带来的开销
架构优化
- 扩容 SLB 后端 ECS 数量,ECS 配置对立;
- Nginx 反代后端 upstream 有效端口去除;
- 云助手批量解决服务,参数优化,增加实例标识;(划重点,大家批量应用 ECS,能够思考利用云助手这个产品)
- 云监控大盘监控,ECS、SLB、DCDN、Redis 等;
- 调整 SLB 为 7 层监听模式,前 7 后 4 敞开会话放弃导致登录状态生效。
程序优化
增加 GC log,捕获 GC 剖析问题,设置过程内存;
`/usr/bin/java -server -Xmx8g -verbose:gc -XX:+PrintGCDetails -Xloggc:/var/`log`/xxxx.gc.`log `-Dserver.port=xxxx -jar /home/app/we.*****.com/serverboot`-0.0.1`-SNAPSHOT.jar`
- 优化短信发送逻辑,登陆先查问 Redis 免登 Session,无免登 Session 再容许发送短信验证码(降短信的量,优化登陆体验);
- jedis 连接池优化;
maxTotal 8-->
20
`acceptcount`` 优化(对标 ``somaxconn``)`
- bug:springboot1.5 带的 jedis2.9.1 的 Redis 连贯透露的问题,导致 Tomcat 800 过程用满后都有限期待 Redis 连贯。起初进一步调研发现这个问题在 2.10.2 曾经修复,而且 2.10.2 向后兼容 2.9.1。
数据库优化
- Redis 公网地址变更为内网地址;
- Redis Session 超时设置缩短,用于开释 Redis 连贯;
- 慢 SQL 优化(RDS 的 CloudDBA 十分好用);
- 增加只读实例,主动读写拆散;
- 优化 backlog;
- 增加读写拆散实例数量。