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

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

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

一、为什么要做单元化

  • 单机房资源瓶颈

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

  • 服务异地容灾

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

二、高德单元化的特点

在做高德单元化项目时,我们首先要考虑的是结合高德的业务特点,看高德的单元化有什么不一样的诉求,这样就清楚哪些经验和方案是可以直接拿来用的,哪些又是需要我们去解决的。

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

1.用户设备的单元接入需要尽可能的做到就近接入,用户真实地理位置接近哪个单元就接入哪个单元,如华北用户接入到张北,华南接入到深圳。

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

另外一个区别就是高德很多业务是无须登录的,所以我们的单元化方案除了用户ID也要支持基于设备ID。

三、高德单元化实践

服务的单元化架构改造需要一个至上而下的系统性设计,核心要解决请求路由、单元封闭、数据同步三方面问题。
wangwei1.png
请求路由:根据高德业务的特点,我们提供了取模路由和路由表路由两种策略,目前上线应用使用较多的是路由表路由策略。

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

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

单元路由服务采用什么样的部署方案是我们另一个要面临的问题,考虑过以下三种方案:
wangwei2.png
第一种SDK的方式因为对业务的强侵入性是首先被排除的,统一接入层进行代理和去中心化插件集成两种方案各有利弊,但当时首批要接入单元化架构的服务很多都还没有统一接入到gateway,所以基于现状的考虑使用了去中心化插件集成的方式,通过在应用的nginx集成UnitRouter。

服务单元化架构

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

以账号系统为例介绍下高德单元化应用的整体架构。
wangwei3.png
账号系统服务是三地四机房部署,数据分别存储在tair为代表的缓存和XDB里,数据存储三地集群部署、全量同步。账号系统服务器的Tengine上安装UntiRouter,它请求的负责单元识别和路由,用户单元划分是通过记录用户与单元关系的路由表来控制。

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

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

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

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

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

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

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

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

再看“分组-单元”:

分组与单元的映射有一个默认关系,这是按地理就近来配置的,比如华南对应深圳。除了默认的映射关系,还有几个用于切流预案的关系映射。
wangwei5.png
老用户可以通过路由表来查找单元,新用户怎么办?对于新用户的处理我们会降级成取模的策略进行单元路由,直至下次路由表的更新。所以整体上看新用户跨单元路由比例肯定是比老用户大的多,但因为新用户是一个相对稳定的增量,所以整体比例在可接受范围内。
wangwei6.png
路由计算

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

通过日志分析出用户所属大区后,我们将不同分组做成多个布隆过滤器,计算时逐层过滤。这个计算有两种特殊情况:

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

2) 新用户不在分组信息里,所以经过逐层的计算也没有匹配到对应大区分组,此时会使用取模进行模除分组的计算。
wangwei7.png
如果业务使用的是取模路由而非路由表路由策略,则直接根据tid或uid计算对应的模除分组,原理简单不详表了。

单元切流

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

打开单元禁写 (跨单元写不敏感业务可以不配置)

检查业务延时

切换预案

解除单元禁写

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

核心指标

单元计算耗时1~2ms

跨单元路由比例底于5%

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

四、后续优化

统一接入集成单元化能力

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

分组机制的优化

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

通过IP计算大区有一定的误算率,会导致部分用户划分错误分组。

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

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

针对上述几个问题我们计划对分组机制做如下改进

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

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

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

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

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

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

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

前面提到高德在路由策略上结合业务的特别设计,但整体单元划分还是以用户(或设备)为维度来进行的,但高德业务还有一个大的场景是我们未来要面对和解决的,就是以数据维度驱动的单元设计,基于终端的服务路由会变成基于数据域的服务路由。
wangwei9.png
高德很多服务是以服务数据为核心的,像地图数据等它并非由用户直接产生。业务的发展数据存储也将不断增加,包括5G和自动驾驶,对应数据的爆发式增长单点全量存储并不实现,以服务端数据驱动的服务单元化设计,是我们接下来要考虑的重要应用场景。

写在最后

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

相关文章
|
4天前
|
Cloud Native 安全 API
云原生架构下的微服务治理策略与实践####
—透过云原生的棱镜,探索微服务架构下的挑战与应对之道 本文旨在探讨云原生环境下,微服务架构所面临的关键挑战及有效的治理策略。随着云计算技术的深入发展,越来越多的企业选择采用云原生架构来构建和部署其应用程序,以期获得更高的灵活性、可扩展性和效率。然而,微服务架构的复杂性也带来了服务发现、负载均衡、故障恢复等一系列治理难题。本文将深入分析这些问题,并提出一套基于云原生技术栈的微服务治理框架,包括服务网格的应用、API网关的集成、以及动态配置管理等关键方面,旨在为企业实现高效、稳定的微服务架构提供参考路径。 ####
24 5
|
7天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
5天前
|
负载均衡 监控 Cloud Native
云原生架构下的微服务治理策略与实践####
在数字化转型浪潮中,企业纷纷拥抱云计算,而云原生架构作为其核心技术支撑,正引领着一场深刻的技术变革。本文聚焦于云原生环境下微服务架构的治理策略与实践,探讨如何通过精细化的服务管理、动态的流量调度、高效的故障恢复机制以及持续的监控优化,构建弹性、可靠且易于维护的分布式系统。我们将深入剖析微服务治理的核心要素,结合具体案例,揭示其在提升系统稳定性、扩展性和敏捷性方面的关键作用,为读者提供一套切实可行的云原生微服务治理指南。 ####
|
5天前
|
消息中间件 缓存 Cloud Native
云原生架构下的性能优化实践与挑战####
随着企业数字化转型的加速,云原生架构以其高度解耦、弹性伸缩和快速迭代的特性,成为现代软件开发的首选模式。本文深入探讨了云原生环境下性能优化的关键策略与面临的主要挑战,通过案例分析,揭示了如何有效利用容器化、微服务、动态调度等技术手段提升应用性能,同时指出了在复杂云环境中确保系统稳定性和高效性的难题,为开发者和架构师提供了实战指南。 ####
18 3
|
5天前
|
运维 Kubernetes Cloud Native
深入理解云原生架构:从理论到实践
【10月更文挑战第38天】本文将引导读者深入探索云原生技术的核心概念,以及如何将这些概念应用于实际的软件开发和运维中。我们将从云原生的基本定义出发,逐步展开其背后的设计哲学、关键技术组件,并以一个具体的代码示例来演示云原生应用的构建过程。无论你是云原生技术的初学者,还是希望深化理解的开发者,这篇文章都将为你提供有价值的见解和实操指南。
|
5天前
|
Kubernetes Cloud Native 持续交付
云原生技术在现代应用架构中的实践与思考
【10月更文挑战第38天】随着云计算的不断成熟和演进,云原生(Cloud-Native)已成为推动企业数字化转型的重要力量。本文从云原生的基本概念出发,深入探讨了其在现代应用架构中的实际应用,并结合代码示例,展示了云原生技术如何优化资源管理、提升系统弹性和加速开发流程。通过分析云原生的优势与面临的挑战,本文旨在为读者提供一份云原生转型的指南和启示。
19 3
|
5天前
|
运维 Kubernetes Cloud Native
云原生技术在现代应用架构中的实践与挑战####
本文深入探讨了云原生技术的核心概念、关键技术组件及其在实际项目中的应用案例,分析了企业在向云原生转型过程中面临的主要挑战及应对策略。不同于传统摘要的概述性质,本摘要强调通过具体实例揭示云原生技术如何促进应用的灵活性、可扩展性和高效运维,同时指出实践中需注意的技术债务、安全合规等问题,为读者提供一幅云原生技术实践的全景视图。 ####
|
6天前
|
缓存 负载均衡 JavaScript
探索微服务架构下的API网关模式
【10月更文挑战第37天】在微服务架构的海洋中,API网关犹如一座灯塔,指引着服务的航向。它不仅是客户端请求的集散地,更是后端微服务的守门人。本文将深入探讨API网关的设计哲学、核心功能以及它在微服务生态中扮演的角色,同时通过实际代码示例,揭示如何实现一个高效、可靠的API网关。
|
4天前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####
|
5天前
|
Dubbo Java 应用服务中间件
服务架构的演进:从单体到微服务的探索之旅
随着企业业务的不断拓展和复杂度的提升,对软件系统架构的要求也日益严苛。传统的架构模式在应对现代业务场景时逐渐暴露出诸多局限性,于是服务架构开启了持续演变之路。从单体架构的简易便捷,到分布式架构的模块化解耦,再到微服务架构的精细化管理,企业对技术的选择变得至关重要,尤其是 Spring Cloud 和 Dubbo 等微服务技术的对比和应用,直接影响着项目的成败。 本篇文章会从服务架构的演进开始分析,探索从单体项目到微服务项目的演变过程。然后也会对目前常见的微服务技术进行对比,找到目前市面上所常用的技术给大家进行讲解。
16 1
服务架构的演进:从单体到微服务的探索之旅