【滴滴后端架构实战】目前,滴滴打车业务量激增,系统访问量迅速膨胀,很多复杂的问题要在短时间内解决,且不能影响线上业务,这是比较大的挑战,本文将会阐述滴滴打车架构演变过程遇到的一些有代表性的问题和解决方案 。
LBS的瓶颈和方案
先看看基本的系统模型,如图1所示 。

文章插图
图1 系统模型示意图
- 乘客发单时,通过MongoDB圈选出附近司机;
- 将订单通过长连接服务推送给司机;
- 司机接单,开始服务 。
- 从服务器CPU负载急剧上升;
- 查询性能急剧降低(大量查询耗时超过800毫秒);
- 查询吞吐量大幅降低;
- 主从复制出现较大的延迟 。
长连接服务稳定性
我们的长连接服务通过Socket接收客户端心跳、推送消息给乘客和司机 。打车大战期间,长连接服务非常不稳定 。
先说说硬件问题,现象是CPU的第一个核经常使用率100%,其他的核却非常空闲,系统吞吐量上不去,对业务的影响很大 。经过较长时间排查,最终发现这是因为服务器用了单队列网卡,I/O中断都被分配到了一个CPU核上,大量数据包到来时,单个CPU核无法全部处理,导致LVS不断丢包连接中断 。最后解决这个问题其实很简单,换成多队列网卡就行 。
再看软件问题,长连接服务当时用Mina实现,Mina本身存在一些问题:内存使用控制粒度不够细、垃圾回收难以有效控制、空闲连接检查效率不高、大量连接时周期性CPU使用率飙高 。打车的长连接服务特点是:大量的广播、消息推送具有不同的优先级、细粒度的资源监控 。最后我们用AIO重写了这个长连接服务框架,彻底解决了这个问题 。主要有以下特性:
- 针对场景定制开发;
- 资源(主要是ByteBuffer)池化,减少GC造成的影响;
- 广播时,一份ByteBuffer复用到多个通道,减少内存拷贝;
- 使用TimeWheel检测空闲连接,消除空闲连接检测造成的CPU尖峰;
- 支持按优先级发送数据 。
系统分布式改造
打车最初只有两个系统,一个提供HTTP服务的Web系统,一个提供TCP长连接服务的推送系统,所有业务运行在这个Web系统里,代码量非常庞大,代码下载和编译都需要花较长时间 。
业务代码都混在一起,频繁的日常变更导致并行开发的分支非常多,测试和代码合并以及发布验证的效率非常低下,常常一发布就通宵 。这种情况下,系统的伸缩性和扩展性非常差,关键业务和非关键业务混在一起,互相影响 。
因此我们Web系统做了拆分,将整个系统从上往下分为3个大的层次:业务层、服务层以及数据层 。
我们在拆分的同时,也仔细梳理了系统之间的依赖 。对于强依赖场景,用Dubbo实现了RPC和服务治理 。对于弱依赖场景,通过RocketMQ实现 。Dubbo是阿里开源的框架,在阿里内部和国内大型互联网公司有广泛的应用,我们对Dubbo源码比较了解 。RocketMQ也是阿里开源的,在内部得到了非常广泛的应用,也有很多外部用户,可简单将RocketMQ理解为JAVA版的Kafka,我们同样也对RocketMQ源码非常了解,打车所有的消息都是通过RocketMQ实现的,这两个中间件在线上运行得非常稳定 。
借着分布式改造的机会,我们对系统全局也做了梳理,建立研发流程、代码规范、SQL规范,梳理链路上的单点和性能瓶颈,建立服务降级机制 。
无线开放平台
当时客户端与服务端通信面临以下问题 。
- 每新增一个业务请求,Web工程就要改动发布 。
- 请求和响应格式没有规范,导致服务端很难对请求做统一处理,而且与第三方集成的方式非常多,维护成本高 。
- 来多少请求就处理多少,根本不考虑后端服务的承受能力,而某些时候需要对后端做保护 。
推荐阅读
- 帮你梳理LAMP架构
- 前后端hosts配置访问问题解决思路
- 一文带你看透数据库架构的演变过程
- 精读《从零开始做架构》
- Nginx + Tomcat + Redis 架构的负载均衡及会话保持
- 春节期间还能打到滴滴吗,春节滴滴打车放假吗
- 一位Android资深工程师对移动端架构的思考
- 程序员经常谈论的前后端分离,前后端解耦
- 阿里P7架构师面试:大型网站应用之海量数据、高并发解决方案
- 微服务架构下的分布式限流方案思考
