共享出行业务下的高并发场景及解决方案(解决方案很具体!!很好!!)

转载自:https://gitbook.cn/books/5ae2bcf8fcb8aa431d69d3a3/index.html

某共享汽车出行平台从随着业务的发展,可能大家听到出行以为是滴滴,然而不是,不过今年美团等巨头也入场共享汽车行业,表明公司业务至少是不错的,城市也在不断扩张,随着最初的 3 台车到目前运营几千台车,也在不断发展过程中,拥有了自己的固件平台,也正式由于此导致在一些业务过程中,由于系统访问量迅速膨胀,很多复杂的问题要在短时间内解决,且不能影响线上业务,这是对我乃至团队成员是一个不小的挑战,本文将会阐述共享汽车平台架构演变过程遇到的一些有代表性的问题和解决方案。

LBS 的瓶颈和解决手段

场景:用户下单后并且取车后,乃至还车车辆所有的行驶轨迹

  1. 车辆每隔几秒钟上报一次经纬度,存储在 mysql 里;
  2. 用户在首页根据当前定位,通过 mysql 数据推荐出最优的有车辆的网点;
  3. 将订单通过短信服务推送给用户;
  4. 用户到最近匹配网点取车,开始行程。

mysql 集群是一主多从的复制集方式,读写都很密集(1w+/s 写、2w+/s 读)时出现以下问题:

  1. 从服务器 CPU 负载急剧上升;
  2. 查询性能急剧降低(尤其随着车辆增长时,慢查询很多,导致还车接口极度慢);
  3. 查询吞吐量大幅降低;
  4. 主从复制出现较大的延迟。

基于当时 mysql 的 sql、主从延迟问题,还有定时任务脚本凌晨大量的锁等待,需要技术团队去解决这些问题,然而对于 sql 大量的查询,可以做多从去解决,分担查询压力,提高查询速度;车辆轨迹的写入,考虑到 mysql 写入压力过大,会考虑把车辆轨迹写入到redis队列里,再设定一个业务低峰期时期,去同步 redis 数据到 mysql,毕竟 redis 内存有限,mysql 作为数据存储还是可以的(存储引擎 innodb 变更为 tokudb,基于高压缩比,数据写入),如此基本解决了主从延迟、sql 查询、db 写入压力。

长连接服务稳定性

我们的长连接服务通过 Socket 接收底层硬件上报车辆轨迹给服务端。尤其在公司 B 轮融资后,车辆迅速变多,长连接服务非常不稳定。

先说说硬件问题,现象是 CPU 的第一个核经常使用率 100%,其他的核却非常空闲,系统吞吐量上不去,对业务的影响很大。经过较长时间排查,最终发现这是因为服务器用了单队列网卡,I/O 中断都被分配到了一个 CPU 核上,大量数据包到来时,单个 CPU 核无法全部处理,导致 LVS 不断丢包连接中断。最后解决这个问题其实很简单,换成多队列网卡就行。

再看软件问题,长连接服务当时用 swoole 实现,使用 swoole 本身技术人员把控有限,也出现各种问题:正常 php 的终止是 exit,错用 swoole 终止、线程分配过少、内存分配过低、swoole跟底层硬件通信缺少监控。最后团队成员基于这些问题,在预发布环境,迅速去修复,也做了硬件的tcp负载,减少单台 swoole 的压力。

高并发业务案例

随着系统访问量迅速增大,日订单从几千到数十万,从分时套餐到包日、包天、包月,导致个人中心、优惠券兑换、用户订单这些平时量小时,没任何影响到各种慢等待、重复数据写入、穿透 redis、核心表主从延迟等。

1. 高并发带来的后果

服务端

导致站点服务器或 DB 服务器资源被占满崩溃,数据的存储和更新结果和理想的设计是不一样的,比如:出现重复的数据记录,多次添加了用户日志记录及充值送流水等。

用户

尼玛,这么卡,老子来参加活动的,刷新了还是这样,垃圾 app,体验太差,充值不了,无法使用订车,再也不来了!

经历

在做公司用户端 app 过程中,经常会有这样的需求,比如运营想做个充值送活动、优惠券兑换活动等,如果没有考虑高并发下 的数据处理,那就 game over,很容易导致用户充值多送等各种超出正常业务的逻辑,更会导致大量错误数据,这就是设计产品需要考虑的问题。

由于面向用户,一个活动的损失直接带来的是金钱和用户的流失。不像传统企业 erp 系统、cms 系统,专门给内部员工用的。互联网产品,用户和资金流水是至关重要。

2. 并发下的数据处理

  • 通过表设计添加唯一约束、数据处理逻辑,使用事务防止并发下的数据错乱问题,而 db 的唯一约束,程序层还需要处理 db 写入报错异常处理,否则在程序内循环可能导致程序中间终止;
  • 通过服务端锁进程防止高并发下的错乱问题,这里主要讲述的是在并发请求下的数据逻辑处理接口,如何保证数据的一致性和完整性。这里的并发可能是大量用户导致的,也有可能是用工具模拟请求导致的。

案例1:通过表设计防止并发导致数据错乱

需求点:充值 1000 送 1000 活动,只能送一次

已有表:充值流水表,资金表

风险:在高并发下,会导致一个用户充值送会送多次优惠

设计

首先根据需求我会添加一张充值流水记录表,重点来了,这张表需要把用户唯一标识字段 (userid,chargeid,charge_type) 字段添加为唯一约束,或者唯一索引,这样就可以防止并发的时候插入重复用户的充值送流水记录。

然后再程序代码逻辑里,先执行真实资金充值数据的添加。这里可以防止并发,添加成功后再进行充值流水的添加,可以防止重复地添加充值送流水了。

最后我还是建议所有的数据操作都写在一个 sql 事务里面, 这样在添加失败时可以回滚数据。

案例 2:通过程序防止错乱数据

需求:缓存数据到 cache 里,当缓存不存在的时候,从数据库中获取并保存在 cache 里。如果存在从 cache 里获取,每天 10 点必须更新一次,其他时间点缓存两个小时更新一次到 10 点的时候,凡是打开页面的用户会自动刷新页面。

问题点:这里有个逻辑用户触发缓存的更新,用户刷新页面,当缓存存在的时候,会取到最后一次缓存更新时间。如果当前时间大于十点,并且最后缓存时间是 10 点前,则会从数据库中重新获取数据保存到 cache 中。 客户端页面会在 10 点时候用 js 发起页面的刷新,就是因为有这样的逻辑,导致 10 点的时候有很多并发请求同时过来,然后就会导致很多的 sql 查询操作。 理想的逻辑是,只有一个请求会去数据库获取,其他都是从缓存中获取数据。(因为这个 sql 查询很耗服务器性能,所以导致在 10 点的时候,突然间数据库服务器压力暴增)

解决方案

通过(锁)lock,在从数据读取到缓存的那段代码前面加上锁,这样在并发的情况下只会有一个请求是从数据库里获取数据,其他都是从缓存中获取。

3. 访问量大的统计接口

需求:用户行为数据统计接口,用来记录用户搜索网点次数,用户通过点击网点,或者链接,或者其他方式进入到网点详情的行为次数。

问题点:这接口是给移动端用的,尽管接口有使用签名,但是网点有几千个,用户有百万,高峰时期的点击量很大

分析

设想如果同时有 1W 个用户同时在线点击网点,而且网点还需要加载所有车辆,估算 100 台,这样就会有 100W 个请求过来,服务端需要把请求数据入库。在实际线上环境可能还会超过这个请求量,如果不经过进行高并发设计处理,服务器分分钟给跪了。

解决问题

我们使用缓存数据库 redis,把所有网点用 hash 方式存储,每一次那个用户的点击、属于那个时间段的,由于这些数据只是对运营推动产品有用,所以可以设计让缓存数据定时同步到 db(不繁忙时刻)。

这里还有个解决方案,后期准备考虑用 mongodb 文档性数据库,鉴于它的高性能存储及数据切片,可以快速扩张。

其实还可以用 mysql 的日志存储系统 tukodb(专业写入:官方称至少比 innodb 高 9 倍、高性能压缩:官方宣称 1:12、可以在线添加索引和字段,速度快)。

4. 高并发下的服务器压力均衡,合理站点设计、db 部署

  1. 服务地 nginx 做负载均衡,压力均摊到后端服务器
  2. 部署 mysql 主从架构,合理利用三级缓存架构(本地缓存、nginx 缓存、redis 缓存)
  3. 在高并发接口的设计中可以使用高性能语言 go(尝试接入一些业务,效果还不错)
  4. 图片服务器分离,静态文件走 CDN
  5. 数据库的优化查询,索引优化及设计,去 join
  6. 消息存储机制,将数据添加到信息队列中 (redis list),然后再写工具去入库

基于上述问题及一些场景的解决手段,为了避免去年年底春节活动时期充值送活动的大流量涌入,光微信端首页就有接近百万的访问导致整个微信端业务瘫痪,开始基于上述一些服务化的架构设计。

因此在开年就开始服务化实施,根据业务系统设计拆分为个人中心服务、优惠券服务、充值送服务、活动服务、订单服务、资金服务、网点车辆服务、车辆轨迹服务、消息服务等,之所以开始实施服务化的架构设计,主要是便于单个小组维护特定的服务;分摊由于特定服务压力过大导致的整个系统可用性。

在笔者写此文时,服务化只完成了个人中心服务、资金服务,鉴于目前当前运行了一月的效果,也经历每周的活动,在当前不管服务层、缓存层、数据层架构设计下,至少不会让 mysql 连接数如去年般动不动超过 8000,也顺利撑住 QPS 过万的压力,大访问量下数据量大的接口响应时长为平均 3s,表小的业务接口平均时长为 1s内。

总结

笔者认为,其实高并发场景下的业务,出现的问题还是有蛮多问题是差不多的,比如超卖(充值多送)、业务卡顿(锁等待)、部分服务器压力大(负载均衡不合理导致,没有做到有效均摊压力),所以不管什么行业业务,可以先找到可以借鉴的成熟方案去试错,再在业务发展过程中,去形成自己公司业务的架构方案,毕竟技术方案是基于业务场景,光靠一篇文章也不可能写出高并发中出现的所有问题和解决方案,其实大多的文章更多是基于自己项目中经历过的场景,分享一些解决方案和思路,关于一些技术问题,可以私聊交流,笔者相当热爱交流和探讨。


 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值