滴滴出行海量数据背后的高可用架构

zzxx11 2年前
   <p style="text-align: center;"><img src="https://simg.open-open.com/show/e4d6570d1838db49cda7cef5fc3a7c0e.jpg"></p>    <h2>作者介绍</h2>    <p>许令波,花名君山,现任滴滴出行技术研究员,从事容器化和资源调度方面的技术建设。曾在淘宝工作七余载,经历了淘宝网 PV 从 1 到 50 亿的增长历程。其中涉及端与管道、应用层代码级、应用架构和端到端等全链路的优化,架构方面从单个应用到分布式、无线多端、中台以及国际化的演进。这些积累的经验同时也在滴滴得到应用实践。</p>    <h2>挑战</h2>    <p>高可用架构建设的</p>    <p>流量与业务复杂性</p>    <p>何为高可用?原则有三: <strong>故障监测</strong> 与 <strong>排除、消除达点故障</strong> , <strong>互备和容灾</strong> 。大流量网站的架构建设最重要的挑战来自“ <strong>流量</strong> ”与“ <strong>业务复杂性</strong> ”两方面:</p>    <ul>     <li> <p><strong>流量。 </strong> 高可用架构首要应对的是大流量且变动复杂场景下的可用性问题。故在建设过程中,架构需要具备高伸缩性,能实现快速扩展。读Cache也是解决大流量带来麻烦的手段。</p> </li>     <li> <p><strong>业务复杂性。 </strong> 于网站而言,业务复杂性比流量带来的挑战要大,因除技术性问题,还涉及人的因素。如整个业务流程没经过很好的整理,后续会带来繁多且复杂的问题。</p> </li>    </ul>    <p>在网站建设过程中, <strong>一方面</strong> 架构上要做到分布式化,业务功能域要做到服务化,这样可以保证架构的高可用、高伸缩性。 <strong>另一方面</strong> 业务架构与组织架构要相匹配,网站流量逐渐增大的同时组织架构与业务架构要随之变化,相互匹配。</p>    <p>反之,如在业务发展过程中,做系统变更会带来一系列问题。如开发和发布效率会因写码风格和发布频率(假设所有业务写到同一系统)受到影响;问题排查找不到对应的负责人等。</p>    <h2>实践</h2>    <p>故障检测与排除、 分布式服务化改造和大流量系统高可用迭代</p>    <p>2011 年,淘宝 PV 处于从 1 亿到 10 亿的 PV 阶段, <strong>系统性能成为最大挑战。</strong> 针对大流量系统设计高可用的静态化方案,应用在详情、购物车以及秒杀系统中;参与双11大促时,交易全链路进行优化, <strong>这些经验在滴滴也得到了应用实践。</strong> 主要为以下三方面:</p>    <ul>     <li> <p>针对故障检测,做了全平台压测</p> </li>     <li> <p>针对业务快速增长情况,对系统做分布式服务化改造</p> </li>     <li> <p>大流量系统高可用迭代</p> </li>    </ul>    <h3>故障检测与排除——全平台测压</h3>    <p>压测是全业务,全流程的压测。在正常情况下制造线上系统的线上流量,也就是自己来攻击自己系统,流量可自控。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/415af4027ff00ff14ec39836c27735f7.jpg"></p>    <p style="text-align: center;">产生流量的线上发压平台</p>    <p>如上图,是产生流量的线上发压平台。和淘宝浏览某个商品行为相比, <strong>滴滴流量发起较复杂</strong> <strong>,涉及时间、地理位置等多维度。</strong></p>    <p>平台有前台 Web 系统、后台服务系统和数据存储三层。在测压过程中,遇到一些问题。如:</p>    <ul>     <li> <p>测试数据和线上数据如何区分开?</p> <p>原则上是可写在一起,但为避免带来问题,这里做了和正式表一样的影子表,同库不同表。</p> </li>     <li> <p>怎样识别是在做压测?</p> <p>用 Trace 来传递标识,通过中间件传递,中间件不完善也可通过参数来做。</p> </li>    </ul>    <p>由于滴滴的数据和一般数据存在差异,全平台压测数据构造要做特殊处理。发单时产生的当前位置、目的地等数据都会回传系统。这里会出现坐标问题,如用真实坐标会干扰线上某些因素。</p>    <p>故把坐标偏移到太平洋,模拟端,把精度、纬度等也做偏移。虚拟乘客和司机,做 ID 偏移、手机号替换。</p>    <p>如下都是在做全平台测压时,发现的问题:</p>    <p>业务线</p>    <ul>     <li> <p>顺风车: 接口耗时增长,如列表页面:100ms => 700ms</p> </li>     <li> <p>顺风车: 日志搜集的上传服务夯死</p> </li>     <li> <p>专快: 派单访问缓存出现超时</p> </li>     <li> <p>出租车: 获取司机接口触发限流</p> </li>     <li> <p>出租车: 派单单条日志量太大影响性能</p> </li>    </ul>    <p>基础平台</p>    <ul>     <li> <p>NAT: 2台NAT启动无用的内核模块,流量大时大量丢包</p> </li>     <li> <p>LBS: 位置服务写入超时,查周边接口有超时</p> </li>     <li> <p>地图: 路径规划服务,到达容量瓶颈</p> </li>    </ul>    <p>压测工具导致的其他问题</p>    <ul>     <li> <p>专快计算超时: 由于工具问题,司机和订单陡增,km算法超时,主要是日志过多导致的。</p> </li>    </ul>    <h3>分布式改造</h3>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f07b0201960eddb1ec0fb758bca50ed3.jpg"></p>    <p style="text-align: center;">典型的分布式架构</p>    <p>上图是典型的分布式架构。最重要的接入层和服务层要做到服务的无状态化,每个节点都需对等,因为这两层主要做读请求且请求量较大。做无状态化是便于横向扩展,当业务量大时,就可迅速部署机器来支撑流量。</p>    <p>数据层大部分情况下都是有状态的,需解决的是冗余和备份,MySQL 要做存库,能读写分离,能做故障切换。</p>    <p>分布式改造关键的技术点有三:</p>    <ul>     <li> <p>分布式 RPC 框架: 主要解决系统性关联问题,就是系统拆分,必须要解决系统之间的同步连接问题;</p> </li>     <li> <p>分布式消息框架: 主要解决系统间的数据关联性,这是异步的,与RPC同步调用互补;</p> </li>     <li> <p>分布式配置框架: 主要解决状态问题,实际应用中接入层和服务层也是有状态的,最好做到无状态。因为每个机器可能存在差异,故要通过中间件,把差异性放到配置框架中解决。</p> </li>    </ul>    <p>去年,滴滴做了服务治理相关的事。 如下图,是早期的滴滴系统架构,router 接受层,到 inrouter 上层,中间有引入代码。下面是 Redis,本身是个代理。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/a33f697270757241803d1ba438129513.jpg"></p>    <p style="text-align: center;">早期的滴滴系统架构</p>    <p>这里存在的问题:</p>    <ul>     <li> <p>上下游依赖硬编码在代码里;</p> </li>     <li> <p>没有使用 inrouter/tgw 的 ip:Port;</p> </li>     <li> <p>摘除和扩容需要代码重新上线,inrouter 有网络链路稳定性隐患,以及效率上的损失;</p> </li>     <li> <p>没有清晰的服务目录,API 文档以及 SLA 和监控。</p> </li>    </ul>    <p>分布式 RPC 框架图</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/bb8e96bf7434f59bed714fd667b14999.jpg"></p>    <p>目标是把一些服务之间的调用能够通过规范化方式串联起来。上下游通过名字服务,从上游和下游端口解耦,名字服务需要在全公司统一且名字唯一。</p>    <ul>     <li> <p>Naming 服务就是做服务命名,服务注册和发现,到注册中心</p> </li>     <li> <p>RPC通道,部署私有协议,具备可扩展性</p> </li>     <li> <p>服务路由与容灾,动态路由,故障节点摘除</p> </li>    </ul>    <p><strong>这里需要提醒的是, </strong> 目前滴滴技术栈还不统一,所以导致中间件会复杂一些,应该最早期把技术栈统一,选择 Java 或者 Go 等,可以避免后续的问题。</p>    <p>服务命名要规范,服务名自描述,要构建统一服务树。为了效率和规范性, <strong> 协议建议选择私有 RPC 协议。 </strong> 公有如 http 协议,测试方便,带来方便性的同时也带来的其他问题,就是容易被滥用。</p>    <p>服务路由建议是全局摘除, 像机器一旦不可用就通知上游,及时摘掉,但也有一定的风险。如网络闪断,下面机器全挂,会导致所有服务都不可用。所以需在全员镇守情况下做全局确认,不要拖着整个服务,要从上游做决策,再换个IP,重新做一次。</p>    <p>分布式服务化改造的大团队协作,从单业务系统做分布式改造的一个出发点就是解决大团队分工和协作问题。代码的分支拆分,减少代码冲突,使得系统独立,打包和发布效率都会提高;部署独立,线上故障排查和责任认定会更加明确。</p>    <p>同时,带来的问题是依赖的不确定性增加,性能上的一些损耗。像一次请求,如果一下调来七八个请求,这也会带来一些问题,所以这个过程要有一定的合理性,就是公司现在处于什么阶段,现在需不需要拆分。所以系统、效率等方面要做一个平衡。</p>    <h3>大流量系统的高可用迭代</h3>    <p>大流量系统的架构实现高可用的策略部署,带有 <strong>分组功能的一致性 Hash 的 Cache</strong> 、 <strong>静态内容前置到 CDN</strong> 和 <strong>热点侦测</strong> 等。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/c668c0746dd1d8c726d1480aea3cfa4e.jpg"></p>    <p>系统 APS 和服务层有五层代码</p>    <p>如上图,一个系统 APS 和服务层有五层代码,通过水平扩展加机器也解决不了问题。在业务层,没办法做水平扩展,必须做有状态的变化, <strong>部署带有分组功能的一致性 Hash 的 Cache。</strong></p>    <p>为了具备更大的伸缩性需要把 <strong>静态内容前置到</strong> <strong> CDN 。 </strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/238c5fb37ac863631714d212b8fa735f.jpg"></p>    <p>静态内容前置到 CDN</p>    <p>在服务端即使做扩展,量还是有限,读的请求,读的数据往前推,最终推到 CDN 上。CDN 体系比较多且有地域性,可抗百万级别的流量,但要解决冗余带来的时效性、一致性的问题。这样做带来的好处,除提高伸缩性,还节省带宽,节点分散,可用性更高。这里提醒下,CDN 可用性需要做评估,如不是自建,需要让提供 CDN 的供应商给出可用性指标,避免后续维系困难。</p>    <p>热点侦测</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/92c9b4e44242c472588d543ce5acd98d.jpg"></p>    <p style="text-align: center;">热点侦测流程图</p>    <p>前台系统到后台系统,整个请求是有链路的,一个请求从发起最终到服务端,到数据库层中间需经历多层,过程中存在时间差。特定情况下,会有 1-2 秒延时。利用这一点,当前端请求自导到接受层时,做实时热点侦测,当发现接收层发生变化,可及时通过认证等手段对这个请求做标记,把热点数据记录下来。</p>    <p>之后,把热点数据的信息通知下一个系统,这样就可起到从上游系统发现问题,保护下游的目的。当发现某个请求特别热时,提前对它做拦截。热点数据通过实时发现,日志采集过来,做统计,然后把这个热点数据再导到写数据系统的后端系统 cache 中,这样可保护后端的部分热点系统。</p>    <p>1% 的热点会影响 99% 的用户,这种情况在电商是特别明显的,如某个商品特别热卖,商品请求流量占全网流量很大部分。且上屏容易产生单点,查数据库时将定在同一机器。这样很容易导致某个商品会影响整个网站的所有商品。所以要在数据库做保护,如在本地做 cache、服务层做本地 cache、或者在数据库层单独做一个热点库等。</p>    <p>大流量系统的高可用迭代,需要注意的点有:</p>    <ul>     <li> <p>热点隔离</p> </li>     <li> <p>先做数据的动静分离</p> </li>     <li> <p>将99%的数据缓存在客户端浏览器</p> </li>     <li> <p>将动态请求的读数据cache在web端</p> </li>     <li> <p>对读数据不做强一致性校验</p> </li>     <li> <p>对写数据进行基于时间的合理分片</p> </li>     <li> <p>实时热点发现</p> </li>     <li> <p>对写请求做限流保护</p> </li>     <li> <p>对写数据进行强一致性校验等</p> </li>    </ul>    <h2>经验</h2>    <p>高可用架构建设的</p>    <p>体系化、积累和沉淀</p>    <p>通过多年的高可用架构建设,这里有一些经验值得分享。最大的体会就是需要做稳定性体系化建设,包括建立规范和责任体系;其次就是工具要完善和体系化,以及需要配套的组织保障。</p>    <p>建议 <strong>在责任体系的建设方面,</strong> 公司一定每年都要制定高可用指标(KPI)、故障等级也要明晰,影响多少客户都要做描述、责任和荣耀体系也同等重要,这是个长期且苦逼的事。</p>    <p>工具方面, 要完善且体系化,做规范,做 KPI,最终要做到工具化,通过工具化把流程、规范能固定。工具要体系化,像全机压测,单机压测等等都可做工具。</p>    <p>一个高可用架构的建设,不是一朝一夕,需要各方面积累和沉淀,一定要注意三方面的处理流程。</p>    <ul>     <li> <p>关于变更: 在变更之前必须制定回滚方案,涉及到对变更内容设置开关,出现问题可快速通过开关关闭新功能;接口变更、数据结构变更、回滚要考虑第三方依赖,在变更之中出现问题,第一时间回滚。</p> </li>     <li> <p>指导原则: 将故障清晰描述和暴露出来,获取第一手资料,找到问题反馈源头,解决问题,消除故障同时找到对应系统和业务的直接负责人。</p> </li>     <li> <p>处理流程:问题发现后第一时间上报到“消防群、组建应急处理小组、跨团队合作,通知到对方系统的负责人,P1故障要通知到客服与公关接口人,尽量做到集中办公,问题处理完毕,立即总结和制定改进方案、系统TL负责,改进方案的执行情况。</p> </li>    </ul>    <p>  </p>   <p>来自:http://mp.weixin.qq.com/s/t9DRMwA8BsmVvn3mVcatJQ</p>    <p></p>    <p> </p>