快的打车架构实践


快的打车架构实践 王小雪 发展历程 2012.5 2013.7 2013.12 2014.4 2015.2 5月成立,8 月上线运营 覆盖城市:70+ 收购“大黄 蜂”,开启 商务车业务 1亿用户 日订单:600w+ 滴滴快的合并 V1 (功能可用 ) V2(核心链路优化) V3(体系化 的架构 设计) V1阶段——基本功能可用  公司没有知名度  技术团队10-30人左右  日订单从几百单到几万单  作坊式研发  系统仅满足基本的功能  天气不好系统就崩溃  快的一崩溃滴滴也崩溃  反过来也是一样,很有默契 确立了原始的系统模型 MongoDB Mina V2阶段——核心链路优化 2013年底打车大战爆发,很短时间内,日订单规模从几万单迅速膨胀到几百万单。系统面 临很多问题,我们将问题分优先级,首先对核心链路进行优化,否则业务主流程都无法正 常进行。 核心链路问题及业务影响 LBS瓶颈 问题:暴增的LBS查询和写入给MongoDB带来巨大的压力,经常会延时 影响:推单时选取的司机有时离乘客很远,或者很近的却没有推送 长连接服务稳定性 问题:TCP server高峰期CPU load很高、消息被截断、连接丢失 影响:司机收不到订单;司机接单了乘客却不知道;乘客取消订单了司机不知道 LBS瓶颈和方案 长连接服务稳定性 硬件问题 不支持多队列的网卡,IO中断都被分配到了一个cpu核上,大量数据包到来的情况下,单个 cpu核无法全部处理,导致LVS不断丢包,连接不断中断。 解决方案 更换支持硬件多队列的网卡(Intel 82575、82576,Boardcom的57711等, linux 内核版本需要 在2.6.21以上) 长连接服务稳定性 软件问题(Mina框架) 1 内存使用控制不够细粒度,垃圾回收难以有效控制 2 空闲连接检查效率不高,在大量连接的情况下会出现周期性CPU 使用率飙高 3 编解码组件在高并发下会出现消息被截断的情况 解决方案(快的自己的AIO框架)  资源(主要是ByteBuffer)池化,减少GC造成的影响  广播时,一份ByteBuffer复用到多个通道,减少内存拷贝  使用TimerWheel检测空闲连接,消除空闲连接检测造成的 CPU尖峰  支持按优先级发送数据 Timer wheel V3阶段——体系化的架构改造 截止到2014年4月份,我们解决了LBS瓶颈、长连接服务的稳定性,核心业务流程的稳定 性有很大提高。技术团队100多人,日订单600万左右,业务场景越来越复杂,原来很多非 核心问题变得越来越严重。  稳定性差 经常会出现一些功能不可用。都忙着做业务需求,怎么快怎么来,后面堆积了大量的历史债  伸缩性差 核心业务和非核心业务混杂在一起  存储瓶颈 每天有几百万的订单,每天都发大量的券,单库单表已经无法支撑了  效率低下 所有业务都在一个系统里,每天很多的并行分支  安全问题 线上配置都是明文写在工程配置文件里的;XSS漏洞很多  没有监控 无法了解系统运行情况,故障定位效率很低  协议混乱 客户端和服务器的通信协议混乱,没有统一的文档和格式 体系化的架构改造 一切都是为了更高的可用性  系统全局梳理  应用分布式改造  无线开放平台  数据层改造  日志收集与检索  监控系统  风控平台  配置中心  研发流程自动化 系统全局梳理 流程与规范  建立研发流程、代码规范、SQL规范  执行严格的code review,普及质量意识  建立故障问责机制 稳定性  梳理链路上的单点  梳理链路上的性能瓶颈  梳理每个环节的故障恢复机制,比如网络闪断后能否自动重连以及重连的影响  梳理JVM 配置、tomcat配置、应用参数配置  定期对系统做性能压测,科学合理的应对营销活动  定期review系统的机器部署  建立服务降级机制 业务梳理  小规模的迭代重构  不求一步到位,但求一直进步 系统分布式改造 最初只有两个系统  http(系统名字就叫http): 处理客户端http请求,例如乘客发单、支付等  tcp(系统名字就叫tcp): 客户端心跳处理;客户端消息推送 系统分布式改造 工程架构向分布式迈进,整体划分为三个层次:业务层、服务层、数据层。 强依赖场景:A调用B,A依赖返回结果判定流程走向,用分布式RPC框架实现 弱依赖场景:A调用B,A的处理逻辑不依赖返回结果,用分布式消息队列实现 mysql redis mongodb 文件系统 订单 lbs 营销用户 支付 数据层 服务层 发单 接单 付款登录 其他业务层 以下是示例图,不是真实的架构图 系统分布式改造 RPC的选型 大规模服务化之前,应用可能通过RPC工具简单暴露和引用远程服务,通过配置服务的地址进行调用, 然而只是简单的RPC还不够。除了网络通信和数据序列化,大型分布式RPC还应具备的其他要素: 基于快的应用场景,我们引入了开 源的分布式PRC框架:dubbo。 dubbo是阿里开源的框架,在阿里内 部和国内大型互联网公司有广泛的 应用,我们对dubbo源码足够的了解。 系统分布式改造 关于Dubbo踩过的一些坑  链式调用的超时雪崩 client->A(timeout:3s),A->B(timeout:3s),A->C(timeout:3s)。B是非关键服务,C是关键服务。B不可用时,A傻等3s最终超 时,业务不可用;B变慢,高峰时期A线程耗光,业务不可用。  线程优先级隔离 Provider A提供了关键服务A1,非关键服务A2,高峰时A2耗时高导致线程池满,导致A1不能提供服务。  服务不停的上线下线 Provider内存使用不当导致频繁fullgc,触发了Zookeeper的超时被下线,Provider fullgc完成后又向zk注册自己,过一会 又fullgc  服务无法注册 用zookeeper做注册中心,配置的注册中心地址只写ip和端口,没有配置注册中心协议,导致用默认的Dubbo协议  forbid consumer异常 调用某服务时出现该异常,原因是该服务的所有实例都下线了  Zookeeper输出大量的debug日志 配置的log4j不是debug级别,但应用大量出现debug日志,zookeeper 3.4.3的日志系统是slf4j,应用里还依赖聊logback。 StaticLoggerBinder.getSingleton()加载了logback配置,默认是debug级别,log4j没有生效。 系统分布式改造 消息队列的选型 我们选择了RocketMQ,它在淘宝和支付宝得到了非常广泛的应用,也有很多外部用户。RocketMQ是 java版的kafka。选择RocketMQ是对现实衡量后一个比较合适的方案。  足够的掌控力 快的所有系统都用java实现,对java最了解;RocketMQ全部是java实现;我们非常了解源码,向作者报 告过几个bug,自己改进过某些实现。  高性能 实测千兆网卡,2K消息大小,单机TPS16000生产消费无延迟。CPU消耗不大,瓶颈在网卡。  线性伸缩 服务能力可以随着Broker的增加而得到线性的提升,而且扩展几乎没有限制;这方面和Kafka是一样的。 系统分布式改造 RocketMQ和Kafka的比较 1 主要相同点 pull模型消费;topic分区;通过磁盘持久化消息;自己刷pagecache;mmap;sendfile;read- ahead;write-behind;运行在JVM上 2 主要不同点  消息存储结构 RocketMQ单个broker的所有消息混合存储,磁盘写性能更高;Kafka按分区存储,分区内顺序写,但全 局随机,这局限了Kafka单个broker的分区数量不能太大,官方推荐不超过64,而RocektMQ单个Broker 的分区可以达到10000。RocketMQ的混合存储结构导致它额外的增加了索引,每次先查询索引,再定 位消息,增加了时间成本。  集群管理 RocketMQ用自己的NameServer,NameServer之间没有关系;Kafka用Zookeeper做集群管理  广播消费 RocketMQ可以将消息广播到一个ConsumerGroup内的所有机器,也可以广播给不同的 ConsumerGroup,Kafka只能做到后者,这是有局限性的 无线开放平台 客户端与服务端通信面临的问题  硬编码 每新增一个业务请求,都要在服务端配置一个code和对应的逻辑处理,导致web工程经常改动发布。  没有统一格式 请求和响应格式没有统一规范,导致服务端很难对请求做统一处理,例如ABTest、监测不同平台和版本 的流量。而且第三方合作伙伴集成的方式非常多,维护成本高。  流量控制和安全 来多少请求就处理多少,根本不考虑后端服务的承受能力。而某些时候需要对后端做保护,例如过多的 恶意攻击流量;后端服务快撑不住了;单个IP访问频率过高;单个用户访问频率过高等等。  开发效率 业务逻辑比较分散,有的在web应用里,有的在dubbo服务里。提供新功能时,工程师关注的点比较多, 增加了系统风险。  文档维护 业务频繁变化和快速发展,文档无法跟上,最后没人能说清到底有哪些协议,协议里的字段含义 无线开放平台 针对这些问题,我们重新设计了无线接入服务,也就是快的无线开放平台:KOP。以下是 一些大的设计原则: 一 接入权限控制 为接入的客户端分配一对app key/app secret,appkey是客户端唯一标识,app secret是一个密钥由客 户端保管,用来对请求做数字签名。KOP对客户端请求做签名校验,校验通过才会执行请求。 二 流量分配和降级  同样的API,不同接入端的访问限制可以不一样。  可按城市、客户端平台类型做ABTest。  极端情况下,优先保证核心客户端的流量,同时也会优先保证核心API的服务能力,例如登录,下 单,接单,支付这些核心的API。  被访问被限制时,返回一个限流错误码,客户端根据不同场景酌情处理。 无线开放平台 三 流量分析  综合考虑客户端、API、IP、用户多个维度,实时分析当前请求是否恶意请求,恶意的IP和用户会 被冻结一段时间,如果严重的则会进入黑名单永久封禁。  防重放攻击,为了防止请求的URL被重放,客户端生成的URL都是有有效期的,服务器会比对请求 里的时间戳和服务器当前时间,如果超过设置的阈值,将会返回一个请求过期错误。  黑白名单  基于请求URL的表达式拦截 四 实时发布 上线或下线API不需要对KOP进行发布,实时生效。当然,为了安全,会有API的审核机制。 五 实时监控  能统计每个客户端对每个API每分钟的调用总量、成功量、失败量、平均耗时  能以分钟为单位查看指定时间段内的数据曲线,并且能对比历史数据  当响应时间或失败数量超过阈值时,系统会自动发送报警短信。 无线开放平台 无线开放平台 日志收集与检索 日志场景  快速查询分布在多台机器上的日志,方便问题快速定位  用户请求跨越多个集群,一键查询出请求的日志轨迹  基于日志做实时的计算分析 日志收集与检索 关于日志收集  日志分为检索类日志和计算类日志,检索类日志通过log4j的flume appender异步传输给flume log server,组后sink到elasticsearch。  单个请求生命周期内的所有日志通过一个flag串联,flag随着dubbo请求传递到不同的JVM里,这样 能通过一个flag搜索出请求的生命周期内的操作轨迹。  日志收集的agent通过管理平台分发和部署,ageng定时上报心跳,通过管理系统能看到每个agent 的运行情况,每个机器上有脚本自动监控agent是否在运行,没有运行则强制启动,当然这个行为 是可以关闭的。 日志收集与检索 关于日志检索  当一个客户端请求一个分布式的服务器端,内部的调用路径非常复杂。当发生故障或者排查问题时, 根据某些关键字快速定位对应的日志轨迹显得非常重要。  elasticsearch一共5台物理机,每天处理1T的日志,日志检索主要是为定位问题用,写入量大,查 询量少。按照不同的业务分索引,比如出租车一个索引,代驾一个索引,每个索引10个主分片,每 个分片1个副本,分片副本没有配置太多是因为查询比较少而索引更新量很大,这样可以减少主分 片和副本之间数据同步的成本,加快索引执行的速度。  主分片的数量需要根据实际场景权衡,分片多可以增加索引执行的并发度,但是在排序和分页时会 增加更多的消耗。  为充分利用内存,单台物理机上开启两个elasticsearch实例  elasticsearch实例的GC策略用CMS,堆大小设置为8G,为及早进行平滑的回收, CMSInitiatingOccupancyFraction设为65  Bulk方式提交数据,index.refresh_interva设定为20秒 实时计算与监控 面临的问题  没有监控,不知道有故障,知道有故障了也不清楚故障点在哪里  不知道实时的运营数据 基于这些原因,我们基于Storm和HBase设计了自己的实时监控平台,分钟级别实时展现系统运行状况 和业务数据。 实时计算与监控 核心计算模型 求和,求平均,分组 举例说明 例如有一个A系统的,要监控它的每分钟错误数量、请求总数,平均耗时,并且可按城市维度查看。  日志信息定义 名称:perf ;路径:/data/logs/perf.log ;格式:20151007111111,login.html,北京,10 名称:error;路径:/data/logs/error.log;格式:20151007111111,错误详情  日志模型 perf:逗号分隔;年月日小时分钟,请求URL,城市,耗时 error:逗号分隔;年月日小时分钟,错误详情  计算规则 错误数量:select sum(count) from A.error 请求总量:select sum(count) from A.perf 总平均耗时:select avg(耗时) from A.perf 城市维度总量:select sum(count) from A.perf group by 城市 城市维度平均耗时:select avg(耗时) from A.perf group by 城市 实时计算与监控 基于storm的流式计算 只有两个bolt,以刚才的例子说明  请求总量  城市维度请求总量  总平均耗时 实时计算与监控 基于HBase的数据存储  只有插入,没有更新,避免了HBase行锁竞争  rowkey是有序的,因为要根据维度和时间段查询,这样会形成HBase Region热点,导致写入比较 集中,但是没有性能问题,因为每个维度每隔1分钟定时插入,平均每秒的插入很少。即使前端应 用的日志量突然增加很多,HBase的插入频度仍然是稳定的。 基于RocketMQ的数据缓冲  收集的日志和storm计算的结果都先放入metaq集群,无论storm集群还是存储节点,发生故障时系 统仍然是稳定的,不会将故障放大;即使有突然的流量高峰,因为有消息队列做缓冲,storm和 HBase仍然能以稳定的TPS处理。这些都极大的保证了系统的稳定性。  metaq集群自身的健壮性足够强,都是物理机。SSD存储盘、高配内存和CPU、Broker全部是M/S 结构。可以存储足够多的缓冲数据。 实时计算与监控 实时计算与监控 实时计算与监控 数据层改造 随着业务发展,单数据库单表已经无法满足性能要求,特别是发券和订单,我们开始考虑对某些数据做 分库分表了。我们选择在客户端分库分表,自己做了一个通用框架解决分库分表的问题。 但是还有以下问题:  数据同步 快的原来的数据库分为前台库和后台库,前台库给应用系统使用,后台库只供后台使用。不管前台应用 有多少库,后台库只有一个,那么前台的多个库多个表如何对应到后台的单库单表?mysql的复制无法 解决这个问题。  离线计算抽取 还有大数据的场景,大数据同事经常要dump数据做离线计算,都是通过sqoop到后台库抽数据,有的复 杂sql经常会使数据库变得不稳定。而且,不同业务场景下的sqoop会造成数据重复抽取,给数据库添加 了更多的负担。 数据层改造 统一的数据同步方案 数据层改造  数据抽取用开源的canal实现,mysql binlog方式改为Row模式,将canal抽取的binlog解析为mq消 息,打包传输给MQ.  一份数据,多种消费场景,之前是每种场景都抽取一份数据  各个消费端不需要关心mysql,只需要关心mq的topic  支持全局有序,局部有序,并发乱序  可以指定时间点回放数据  数据链路监控、报警  通过管理平台自动部署节点 数据层改造 分库分表解决了前台应用的性能问题,数据同步解决了多库多表归一的问题,但是随着时间推移,后台 单库的问题越来越严重,迫切需要一种方案解决海量数据存储的问题,同时又要让现有的上层应用不会 有太大改动。因为我们基于HBase和数据同步设计了实时数据中心。 1. 将前台mysql多库多表通过同步平台,都同步到了HBase 2. 为减少后台应用层的改动,设计了一个SQL解析模块,将SQL查询转换为HBase查询 3. 支持二级索引 数据层改造 二级索引 HBASE并不支持二级索引,对HBASE而言只有一个索引那就是rowkey。如果要按其它字段查询,那就 要为这些字段建立与rowkey的映射关系,这就是所谓的二级索引。 HBSE二级索引可以通过Coprocessor在数据插入 之前执行一段代码,这段代码运行在HBASE服务 端(RegionServer),可以让这段代码负责插入二级 索引。 实时数据中心目前的二级索引是在客户端负责插入 的,并没有使用Coprocessor,主要原因是 Coprocessor不容易实现索引的批量插入,而批量 插入,实践证明,是提升HBASE插入性能非常有 效的手段 数据层改造 二级索引  排序 在HBASE中,只有一种排序,就是按rowkey排序,因此,在建立索引的时候,实际上就定死了将来查 询结果的排序。某个索引字段的reverse属性为true,则按这个字段倒序排序,否则正序排序。  打散 单调变化的rowkey读写压力很难均匀分布到多个Region上,而打散将会使读写均匀分布到多个Region, 因此提升了读写性能。但打散也有局限性,主要的是,经过打散的字段将无法支持范围查询。而且, hash和reverse这两个属性是互斥的,且hash优先级高,就是说一旦设置了hash=true,则会忽略 reverse这个属性。  串联 另外需要特别强调的是,索引配置也影响到多表归一,作为“串联”的字段,必须建立唯一索引,如果 串联字段上没有建立唯一索引,将无法完成多表归一。 数据层改造 多表归一 HSQL引擎 一套将sql语句转换成HBASE API的引擎,可以通过sql语句直接操作HBSE。这里需要指出的是HSQL引 擎和Hive是不同的,Hive主要用于将sql语句转换成Hadoop的Map/Reduce任务,当然也可以转换成 HBASE的查询。但Hive无法利用二级索引(HBAS本来就不存在二级索引这个概念),Hive主要面向的是 大批量、低频度、高延迟、顺序读的访问场景,而HSQL可以有效利用二级索引,它面向的是小批量、 高频度、低延迟、随机读的访问场景。 Thanks
还剩38页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

anlan

贡献于2017-08-14

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf