高德服务单元化方案和架构实践

导读:本文主要介绍了高德在服务单元化建设方面的一些实践经验,服务单元化建设面临不少共性问题,如请求路由、单元封闭、数据同步,有的有成熟方案能够借鉴和使用,但不一样公司的业务不尽相同,要尽量的结合业务特色,作相应的设计和处理。

1、为何要作单元化

  • 单机房资源瓶颈

随着业务体量和服务用户群体的增加,单机房或同城双机房没法支持服务的持续扩容。nginx

  • 服务异地容灾

异地容灾已经成为核心服务的标配,有的服务虽然进行了多地多机房部署,但数据仍是只在中心机房,实现真正意义上的异地多活,就须要对服务进行单元化改造。redis

2、高德单元化的特色

在作高德单元化项目时,咱们首先要考虑的是结合高德的业务特色,看高德的单元化有什么不同的诉求,这样就清楚哪些经验和方案是能够直接拿来用的,哪些又是须要咱们去解决的。sql

高德业务和传统的在线交易业务仍是不太同样,高德为用户提供以导航为表明的出行服务,不少业务场景对服务的RT要求会很高,因此在作单元化方案时,尽量减小对总体服务RT的影响就是咱们须要重点考虑的问题,尽可能作到数据离用户近一些。转换到单元化技术层面须要解决两个问题:mongodb

1.用户设备的单元接入须要尽量的作到就近接入,用户真实地理位置接近哪一个单元就接入哪一个单元,如华北用户接入到张北,华南接入到深圳。缓存

2.用户的单元划分最好能与就近接入的单元保持一致,减小单元间的跨单元路由。如用户请求从深圳进来,用户的单元划分最好就在深圳单元,若是划到张北单元就会形成跨单元路由。服务器

另一个区别就是高德不少业务是无须登陆的,因此咱们的单元化方案除了用户ID也要支持基于设备ID。架构

3、高德单元化实践

服务的单元化架构改造须要一个至上而下的系统性设计,核心要解决请求路由、单元封闭、数据同步三方面问题。性能

请求路由:根据高德业务的特色,咱们提供了取模路由和路由表路由两种策略,目前上线应用使用较多的是路由表路由策略。优化

单元封闭:得益于集团的基础设施建设,咱们使用vipserver、hsf等服务治理能力保证服务同机房调用,从而实现单元封闭(hsf unit模式也是一种可行的方案,但我的认为同机房调用的架构和模式更简洁且易于维护)。ui

数据同步:数据部分使用的是集团DB产品提供的DRC数据同步。

单元路由服务采用什么样的部署方案是咱们另外一个要面临的问题,考虑过如下三种方案:

第一种SDK的方式由于对业务的强侵入性是首先被排除的,统一接入层进行代理和去中心化插件集成两种方案各有利弊,但当时首批要接入单元化架构的服务不少都尚未统一接入到gateway,因此基于现状的考虑使用了去中心化插件集成的方式,经过在应用的nginx集成UnitRouter。

服务单元化架构

目前高德帐号,云同步、用户评论系统都完成了单元化改造,采用三地四机房部署,写入量较高的云同步服务,单元写高峰能达到数w+QPS (存储是mongodb集群)。

以帐号系统为例介绍下高德单元化应用的总体架构。

帐号系统服务是三地四机房部署,数据分别存储在tair为表明的缓存和XDB里,数据存储三地集群部署、全量同步。帐号系统服务器的Tengine上安装UntiRouter,它请求的负责单元识别和路由,用户单元划分是经过记录用户与单元关系的路由表来控制。

PS:因历史缘由缓存使用了tair和自建的uredis(在redis基础上添加了基于log的数据同步功能),目前已经在逐步统一到tair。数据同步依赖tair和alisql的数据同步方案,以及自建的uredis数据同步能力。

就近接入实现方案

为知足高德业务低延时要求,就要想办法作到数据(单元)离用户更近,其中有两个关键链路,一个是经过aserver接入的外网链接,另外一个是服务内部路由(尽量不产生跨单元路由)。

措施1:客户端的外网接入经过aserver上的配置,将不一样地理区域(七个大区)的设备划分到对应近的单元,如华北用户接入张北单元。

措施2:经过记录用户和单元关系的路由表来划分用户所属单元,这个关系是经过系统日志分析出来的,用户常常从哪一个单元入口进来,就会把用户划分到哪一个单元,从而保证请求入口和单元划分的相对一致,从而减小跨单元路由。

因此,在最终的单元路由实现上咱们提供了传统的取模路由,和为降延时而设计的基于路由表路由两种策略。同时,为解无须登陆的业务场景问题,上述两种策略除了支持用户ID,咱们同时也支持设备ID。

路由表设计

路由表分为两部分,一个是用户-分组的关系映射表,另外一个是分组-单元的关系映射表。在使用时,经过路由表查对应的分组,再经过分组看用户所属单元。分组对应中国大陆的七个大区。

先看“用户-(大区)分组”:

路由表是按期经过系统日志分析出来的,看用户最近IP属于哪一个大区就划分进哪一个分组,同时也对应上了具体单元。当一个北京的用户长期去了深圳,因IP的变化路由表更新后将划进新大区分组,从而完成用户从张北单元到深圳单元的迁移。

再看“分组-单元”:

分组与单元的映射有一个默认关系,这是按地理就近来配置的,好比华南对应深圳。除了默认的映射关系,还有几个用于切流预案的关系映射。

老用户能够经过路由表来查找单元,新用户怎么办?对于新用户的处理咱们会降级成取模的策略进行单元路由,直至下次路由表的更新。因此总体上看新用户跨单元路由比例确定是比老用户大的多,但由于新用户是一个相对稳定的增量,因此总体比例在可接受范围内。

路由计算

有了路由表,接下来就要解工程化应用的问题,性能、空间、灵活性和准确率,以及对服务稳定性的影响这几个方面是要进行综合考虑的,首先考虑外部存储会增长服务的稳定性风险,后面咱们在BloomFilter 、BitMap和MapDB多种方案中选择BloomFilter,万分之几的误命中率致使的跨单元路由在业务可接受范围内。

经过日志分析出用户所属大区后,咱们将不一样分组作成多个布隆过滤器,计算时逐层过滤。这个计算有两种特殊状况:

1) 由于BloomFilter存在误算率,有可能存在一种状况,华南分组的用户被计算到华北了,这种状况比例在万分之3 (生成BloomFilter时可调整),它对业务上没有什么影响,这类用户至关于被划分到一个非所在大区的分组里,但这个关系是稳定的,不会影响到业务,只是存在跨单元路由,是可接受的。

2) 新用户不在分组信息里,因此通过逐层的计算也没有匹配到对应大区分组,此时会使用取模进行模除分组的计算。

若是业务使用的是取模路由而非路由表路由策略,则直接根据tid或uid计算对应的模除分组,原理简单不详表了。

单元切流

在发生单元故障进行切流时,主要分为四步骤:

  1. 打开单元禁写 (跨单元写不敏感业务能够不配置)
  2. 检查业务延时
  3. 切换预案
  4. 解除单元禁写

PS:更新路由表时,也须要上述操做,只是第3步的切换预案变成切换新版本路由表;单元禁写主要是了等待数据同步,避免数据不一致致使的业务问题。

核心指标

单元计算耗时1~2ms

跨单元路由比例底于5%

除了性能外,因就近接入的诉求,跨单元路由比例也是咱们比较关心的重要指标。从线上观察看,路由表策略单元计算基本上在一、2ms内完成,跨单元路由比例3%左右,总体底于5%。

4、后续优化

统一接入集成单元化能力

目前大部分服务都接入了统一接入网关服务,在网关集成单元化能力将大大减小服务单元化部署的成本,经过简单的配置就能够实现单元路由,服务可将更多的精力放在业务的单元封闭和数据同步上。

分组机制的优化

按大区分组存在三个问题:

经过IP计算大区有必定的误算率,会致使部分用户划分错误分组。

分组粒度太大,单元切流时流量很差分配。举例,假如华东是咱们用户集中的大区,切流时把这个分组切到任意一个指定单元,都会形成单元服务压力过大。

计算次数多,分多少个大区,理论最大计算次数是有多少次,最后采起取模策略。

针对上述几个问题咱们计划对分组机制作以下改进

经过用户进入单元的记录来确认用户所属单元,而非根据用户IP所在大区来判断,解上述问题1。

每一个单元划分4个虚拟分组,支持更细粒度单元切流,解上述问题2。

用户确实单元后,经过取模来划分到不一样的虚拟分组。每一个单元只要一次计算就能完成,新用户只需通过3次计算,解上述问题3。

热更时的双表计算

与取模路由策略不一样,路由表策略为了把跨单元路由控制在一个较好的水平须要按期更新,目前更新时须要一个短暂的单元禁写,这对于不少业务来讲是不太能接受的。

为优化这个问题,系统将在路由表更新时作双(路由)表计算,即将新老路由表同时加载进内存,更新时再也不对业务作彻底的禁写,咱们会分别计算当前用户(或设备)在新老路由表的单元结果,若是单元一致,则说明路由表的更新没有致使该用户(或设备)变动单元,因此请求会被放行,相反若是计算结果是不一样单元,说明发生了单元变动,该请求会被拦截,直至到达新路由表的一个彻底起用时间。

优化前服务会彻底禁写好比10秒(时间取决于数据同步时间),优化后会变成触发禁写的是这10秒内路由发生变动的用户,这将大大减小对业务的影响。

服务端数据驱动的单元化场景

前面提到高德在路由策略上结合业务的特别设计,但总体单元划分仍是以用户(或设备)为维度来进行的,但高德业务还有一个大的场景是咱们将来要面对和解决的,就是以数据维度驱动的单元设计,基于终端的服务路由会变成基于数据域的服务路由。

高德不少服务是以服务数据为核心的,像地图数据等它并不是由用户直接产生。业务的发展数据存储也将不断增长,包括5G和自动驾驶,对应数据的爆发式增加单点全量存储并不实现,以服务端数据驱动的服务单元化设计,是咱们接下来要考虑的重要应用场景。

写在最后

不一样的业务场景对单元化会有不一样的诉求,咱们提供不一样的策略和能力供业务进行选择,对于多数据服务咱们建议使用业务取模路由,简单且易于维护;对于RT敏感的服务使用路由表的策略来尽量的下降服务响应时长的影响。另外,要注意的是强依赖性的服务要采用相同的路由策略。


本文做者:高德技术小哥

阅读原文

本文为云栖社区原创内容,未经容许不得转载。

相关文章
相关标签/搜索