记录一次高并发项目的优化重构过程

前言

最近有幸接触过一个并发很高的项目,其实这个项目是一个接单任务的平台,用户群体很大,大概有300w用户到500w用户左右,每到凌晨的时候,我们的任务就会更新为全新的。因此流量最大的点就是凌晨那一个小时,因为我们的任务并不是无限多的,需要抢做的,类似秒杀场景,而凌晨高的原因是因为价格高,因此用户大都会积累到这个时间点来做任务。我这边测试过我们每秒的qps大概高峰有20000+,这个是最高峰的时候。当然这个只是在这么多用户的情况下,当然也可能用户也会继续增长。

大概业务逻辑

我们的平台主要分为两块,一块是客户的后台,也就是我们的录入系统,这个后台倒没有什么压力的。另一块就是用户接单的。这个是我们业务是否能继续下去的基础,他的业务总结下来就是如下这样的:
1、客户在我们上面发布任务,以及数量价格等等。
2、用户可以进行接单操作,领取任务然后并完成任务。
3、用户不能重复领取任务。领取任务如果没有提交完成后放弃等就不能继续领取任务。
4、用户不能领取已经领取过并成功完成的任务。
5、用户一天不能做超过多少个任务,这个我们控制的。
6、用户领取任务和做完或者失败等都需要进行上报。
7、所有未完成任务的数量还需要重新分发
8、统计分段的用户数,这个需要去重
9、统计当天完成的任务总数以及失败总数
10、统计当天活跃用户总数。

项目最初始过程

可能大家会觉得这个很好做,放数据库里面就可以操作,确实在开始移交给我之前的同事就是这样做的,但是这个项目的用户数量非常庞大。所以导致了我们的nginx经常超时。更严重的是我们的数据库cpu一直超负荷运行(高峰的时候一直是200%左右运行,这里不得不说阿里云的数据库还是稳),这个时候我接手就开始了优化与重构。

优化过程

  1. 最开始就是优代码的优化
    我们主要是从sql的角度来优化。首先将所有的sql进行了一波检查,复杂的sql我们使用explain解释来查看他的执行效率。还有对spring boot项目的tomcat的连接数以及线程数进行相应的增加。还有优化了没必要的步骤。以为大工告成的时候,这个时候我们继续监控的时候,发现平时的时候还是阔以的(这个时候用户数并没有这么高还在陆陆续续的增长过程中),但是到了凌晨这个点就还是有问题,我就打开了mysql,通过show processlist 命令来查看,发现数据库被堵塞了。导致cpu很高。这个时候我将阻塞的sql语句复制出来发现这个语句已经是最优了。打开阿里云的监控系统发现我们美妙执行的sql查询已经达到5000左右了,插入更新的还不计入。这个时候我们不可能考虑升级数据库,因为数据库的瓶颈目前只是查询过程导致的cpu暴涨,而内存一直很稳定。
  2. 代码的重构
    经历了代码优化也无法达到我们的效果的时候,我们就需要重新对整块的业务进行进一步的理解,然后进行重构,当然不能影响到现有的业务。因为我们知道我们的所有的查都会到数据库查,因为我们的上报数据是很大的,所以这个很不科学。所以我们整理了下,将这些基本的放入到redis中查询,redis的性能大家应该清楚吧,我这边就不说了
    2.1、将用户做成功的任务放入set里面,避免用户重复领取成功过的任务
    2.2、记录每一个用户成功的数量,用hash进行++操作。
    2.3、将我们的任务也放到redis中,因为有优先级,可以使用zsort来存 放。
    2.4、分时段记录用户,存入set,value就是用户名
    2.5、统计整天的活跃用户,也是使用set来存
    到这一步的时候我们就基本上将我们查询逻辑移入到redis中,这是基于业务逻辑上的重构。然后我们继续部署到线上的时候。发现确实是有效果,效果也很不错,但是我发现mysql的数据库的cpu偶尔还是会飙升,虽然这次不会那么高,但是还是会超过100%。这个时候继续寻找小漏洞,发现原来是redis中缓存的击穿和穿透导致的。
  3. redis的问题的解决
    因为我们发现我们任务完成后或者其他的时候我们会进行缓存的情况,这个其实可以理解为击穿。那么通常解决击穿的方法的就是就是双重校验,也就是说快过期的时候在继续查数据库并重写,但是我们项目由于是线上很赶时间,我就采用了一种牺牲部分用户请求的的方法。使用redis分布式锁来处理这种缓存过期,请求全部查数据库的方法。还有就是穿透,其实也就是查数据查不到,但是我会默认个给他个空数据,如果拿处理数据为空,我就不处理。避免这种穿透。
    到这一步的时候我们再次部署上去已经完全没有问题了,监控数据库的cpu和redis的监控,发现没什么大问题。但是我们的统计数据还是每次实时的插入,但是由于我们查询的逻辑已经不怎么依靠于这些统计的数据,追求完美的我,怎么可能会让这种缺陷存在呢。因为每一条插入都实时写很耗费数据库性能的。这个时候就想有没有其他方式可以批量写呢。当然之前在上家公司就用过mq的技术,这个时候就浮现出这个技术
  4. 使用mq来处理统计数据
    第二天我就开始将我们的项目引入mq,也就是所有的消息会发送到消息中间件总,然后我们消费者会将这些消息存到数据库中。其实这里我们使用了多线程来存数据,因为我们每次从消息队列中读取了好多消息,这个时候我们不可能一下子将所有的消息都存进去,我们就分批存,这个时候可以使用多线程进行存储。当然使用mq的过程也遇见好多坑,这些坑在上面的几篇文章中已经有讲过了。

到这里我们的项目基本上已经没什么问题了,能抗住这些压力。其实在接手这个项目的时候压力还蛮大的,毕竟并发很大。前面的同事留的坑也大,但是想着是个挑战就接下来了。当然前期后后20多天每一天睡过好觉。但是完成后真的给自己很大的提升。确实项目某些小问题,在高并发下就是大问题。所以设计的时候需要好好考虑用户的量。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值