简介:2021 年是小米中国区电商部门变动调整较大的一年,小米中国区晚期电商、服务体系建设在 Go 语言构建的微服务体系之上,由外部自研的 Go 语言微服务框架 koala 撑持起数以千计的微服务利用。随着业务的倒退,新批发体系的成立以及业务中台遍及与推广,咱们更偏向于领有丰盛生态的 Java 为主的微服务体系技术选型,新我的项目及服务大多基于 Apache Dubbo、Spring Cloud 的微服务生态。
作者 | 董振兴
背景
2021 年是小米中国区电商部门变动调整较大的一年,小米中国区晚期电商、服务体系建设在 Go 语言构建的微服务体系之上,由外部自研的 Go 语言微服务框架 koala 撑持起数以千计的微服务利用。随着业务的倒退,新批发体系的成立以及业务中台遍及与推广,咱们更偏向于领有丰盛生态的 Java 为主的微服务体系技术选型,新我的项目及服务大多基于 Apache Dubbo、Spring Cloud 的微服务生态。
思考到服务迁徙的微小老本以及服务稳定性的保障,咱们最终决定在大范畴投入与应用以 Apache Dubbo 为主的服务体系的同时,保留原有 Go 微服务项目。因为原有跨部门的技术选型差别,留存的服务蕴含基于 Thrift、gRPC 等不同协定服务,咱们心愿多套微服务体系可能无缝稳固地交融。在通过大量调研之后,确定了以 Dubbo+Nacos+etcd+sidecar+mirpc+Dubbo-go 的为外围的一套互通的微服务体系。
微服务治理
1、相干组件
mione
mione 是一套由小米公司新批发效力团队开源的“我的项目创立 -> 开发 -> 测试 -> 公布 -> 运维”端到端的零碎服务和研发工具,反对物理机部署、docker 部署、K8s、dockerFile 部署等多种部署状态,通过人工智能、自动化技术的利用助力开发者晋升研发效力,继续疾速交付无效价值。具体理解能够通过官网
目前外部基于 Java Dubbo 生态的微服务基本上都托管于 mione,并以 Nacos 为注册核心,这些服务作为 consumer 基本上通过 Apache Dubbo、side-car 两种形式实现调用。
koala
koala 是小米外部自研的 Go 语言的微服务框架,基于 etcd 的注册核心以及 Thrift 协定。作为服务的提供方,服务注册将本身元数据等信息注册到 etcd 中,并对外提供 Thrift 的服务。
Java Dubbo 的 consumer 服务则通过 side-car 兼容 Thrift/gRPC 协定,基于 etcd 进行服务发现调用。
sidecar
sidecar 同样是小米外部自研的用于服务注册及发现,反对跨服务调用的组件,名为 soa-agent,以 side-car 的形式同服务部署于 mione 容器中,服务借助该组件实现兼容协定的 RPC 调用,具体技术细节这里不做具体介绍。
Apache Dubbo-go
咱们以 side-car 的形式解决了 Java 服务的 consumer 到 Go 服务基于 Thrift/gRPC 的调用,而 Go 服务到新我的项目,即基于 Apache Dubbo 生态的 Java 服务的调用,在通过大量调研与参考后,决定应用还在一直进行迭代的 Apache Dubbo-go。
Apache Dubbo-go 是以后 Apache Dubbo 多语言反对中较为热门的我的项目,社区也较为沉闷。Apache Dubbo-go 由 Go 语言实现,继承了 Apache Dubbo 的设计理念与架构,领有较好的可扩展性。它可能架起 Java 和 Go 之间的桥梁,与 gRPC/Apache Dubbo 生态互联互通,这正式对于是咱们以后痛点较好的解决方案,所反对的 Nacos 注册核心也与咱们以后中间件的技术选型符合。
Apache Dubbo-go 的利用
通过调研后,咱们选用了过后较为稳固的 v1.5.7 版本进行接入。
Apache Dubbo 官网文档中提供了应用 Apache Dubbo-go 的个别调用形式,但该形式须要业务方调用方严格遵守切合服务方提供的接口格局、数据格式,因而咱们抉择应用泛化的形式进行调用。
对于一个 Java 的 Apache Dubbo 服务提供的接口如下:
public interface DubboHealthService {List<Health> health();
String ping(String param,int param2);
AaRes health1(List<AaReq> list);
Health health2(AaReq aaReq);
}
//impl
@Service(timeout = 1000, group = "dev", version = "4.0")
public class DubboHealthServiceImpl implements DubboHealthService {......}
在 Apache Dubbo-go 的 client 配置文件中,须要的外围配置如下:
# registry config
registries:
"demoNacos":
protocol: "nacos"
timeout: "3s"
address: "xxx.xxx.xxx"
username: "****"
password: "****"
references:
"UserProvider":
registry: "demoNacos"
protocol: "dubbo"
interface: "com.xiaomi.youpin.test0930.api.service.DubboHealthService"
cluster: "failover"
version: "4.0"
group: "dev"
generic: true
methods:
- name: "health"
retries: 0
timeout: "0.5s"
......
首先配置对应注册核心,包含选型及地址,Nacos/zookeeper 等,其次配置须要调用的具体接口,办法、超时工夫等信息。因为咱们应用泛化调用,须要进行配置 generic: true。这里咱们在应用 v1.5.7 版本时发现了对于泛化调用下办法级别超时工夫并不失效的状况,进行了修复,具体能够参考该 pr
配置实现后,泛化调用的形式咱们进行了肯定的封装:
//......
var paramTypes []string
var paramVals []interface{}
for _, param := range req.Params {paramTypes = append(paramTypes, param.GetKey())
paramVals = append(paramVals, param.GetVal())
}
// 增加 context 信息
m := make(map[string]string)
m["xxx(generic_flag)"] = "xxx(flag)"
// 服务端返回 json 字符串
m["xxx(return_flag)"] = "true"
ctx = context.WithValue(context.Background(), constant.DubboCtxKey("attachment"), m)
//invoke 调用
response, err = config.GetRPCService(req.AppName).(*config.GenericService).Invoke(ctx, []interface{}{req.MethodName, paramTypes, paramVals})
if err != nil {err = fmt.Errorf("dubbo call request appName: %s methodName: %s rpc invoke failed,err:%+v", req.AppName, req.MethodName, err)
return
}
这里实际上业务只须要传入须要调用的 Apache Dubbo 办法,参数列表例如 [“java.lang.String”] 以及参数值即可。
为了切合业务须要,咱们在外部保护的 Java Dubbo 版本中也做了肯定水平的兼容与革新,Apache Dubbo-go 中通过 context,即 attachment 能够带上两个非凡标识,服务端的 Java Dubbo 版本中将依据该非凡标识接管解决与返回以 json 格局的数据。
这样一来,留存的 Go 服务就可能应用 Apache Dubbo 协定与 Java Dubbo 生态的服务达到互联互通,同时也因为 Apache Dubbo 的劣势,也具备了肯定水平的服务治理能力。
在线上运行该版本 Apache Dubbo-go 时,也发现了 Apache Dubbo-go 提供的像黑名单机制等的一些不太正当之处,例如该机制下,当服务端呈现报错后,调用方会将该服务端的 ip 记录黑名单,再进行调用时可能呈现 no provider 的状况,而实际上服务端可能仅是针对某个申请的解决报错,服务实际上可能失常运行,那么这时候该机制便有待商讨,咱们理论应用时也是进行了摘除。具体细节可见该 pr。
现状与将来倒退
1、以后架构
目前小米新批发曾经基于上述 mione 的体系以及上述介绍的这一部分组件,建设了一套较为欠缺的,包含微服务标准化、可继续集成部署、以及可见可控的观测性平台的服务治理体系。
在传统的微服务体系下,咱们通常须要满足两个服务治理的根本的需要:一站式的服务治理平台、普适性的服务开发框架。
前者咱们通过 mione 实现了包含但不限于基于容器化的 CICD、服务的标准化定义、服务的生命周期治理(服务高低线、扩缩容等)、服务的根本通信和链路治理(如重试、限流降级熔断等);而后者咱们借助了 Apache Dubbo、Apache Dubbo-go 等开源 RPC 框架,联合像 Springboot 这样的传统开发框架提供了较为标准化的服务搭建开发流程。
同时,咱们外部自研了一套可见可观测性体系,帮忙咱们获取更多有价值的数据来反馈于服务治理,对服务做到更全面精确的把控。这实际上包含了 3 个档次的工具汇合:Logging(日志零碎)、Metric(度量零碎)以及 Tracing(分布式链路追踪零碎)
咱们通过上述的架构与设计实际上曾经基本上满足了传统形式下对微服务治理需要,然而,这还不够。
将来方向
1、Service Mesh 与 Serverless
Service Mesh
首先什么是 Service Mesh?Service Mesh 是一个致力于解决服务间通信的基础设施层,它负责在古代云原生利用的简单服务拓扑下实现申请的牢靠传递,它通常实现为一组轻量级的网络代理,与应用服务部署在一起,对应用服务通明。
咱们下面架构组件中的 sidecar soa-agent 实际上就是一个 service mesh 的雏形,这个组件目前承当了包含服务发现、配置托管等一些能力,当然,他可能做到的该当更多。对于业务应用服务的通明以及零侵入是 service mesh 的一大劣势,也是以后它正备受推崇的次要起因。
综合来看,Service Mesh 次要可能解决当下传统微服务体系的几大痛点:
1、欠缺的微服务基础设施
service mesh 可能将微服务的通信下沉到基础设施层,它屏蔽了微服务解决各种通信问题的复杂度。对于业务开发者来说,实际上他并不关怀像 Rpc 通信、服务注册与发现这样的非功能性细节。但传统微服务下,拿 Thrift 举例,作为开源的一套性能较高的 Rpc 框架,因为它不足一些根本的服务治理能力,Thrift 很多时候并无奈做到开箱即用,在晚期小米电商的基础架构团队就对 Thrift 做了定制化的二次开发,在生成的桩代码中退出了服务发现、打点等性能,这些代码再与自研的开发框架 koala 耦合来实现服务的闭环调用。而这些框架代码以及生成的桩代码,与业务代码也并没有显著的隔离与辨别,甚至业务可能间接批改框架代码以及桩代码,实际上埋下了较大的隐患,也造成后续降级艰难、重大阻塞等问题。
而 service mesh 则能够完满的解决像这样的痛点,通过对这些能力的下沉,他们将对业务服务屏蔽实现细节,业务服务也就不再须要关怀包含服务发现、负载平衡、流量调度、限流降级熔断、监控统计等所有细节。
2、语言无关的通信和链路治理
实际上 service mesh 在性能上并没有提供对于服务治理的任何新的个性和能力,它所可能提供的能力在 service mesh 之前其实都可能找到。service mesh 扭转的是通信和服务治理能力的提供形式,它将这些能力从业务层面解耦,下沉到基础设施中,以更加标准化和通用的形式来提供,这样一来它便能屏蔽不同语言、不同平台的差异性,在多语言、多技术栈的团队环境中,它可能提供胶水般的交融与协同能力。这也是咱们下面小米电商微服务调用架构图中 sidecar 所做到的,为跨语言的调用提供了解决方案。
3、通信和服务治理的标准化
通过标准化,带来统一的服务治理体验,缩小多业务之间因为服务治理规范不统一带来的沟通和转换老本,进步全局服务治理的效率。
鉴于以上 service mesh 带来的益处,小米电商微服务的架构在将来会进一步在已有根底上更多的调研、参考以及参加该技术落地。
然而,硬币总有正反面,service mesh 也绝不是仅有长处的万能膏药。实际上,引入多一层的组件代理转发申请,自身就不可避免地带来更多的资源耗费,在肯定水平上会升高零碎的通信性能。其次,根底性能与服务解耦有解耦的绝对优势,但侵入式框架反而在反对业务的定制与扩大能力上反而有先天劣势,这点在零碎的设计中也该当思考。第三,零碎中对于组件的引入自身也带来肯定的危险,业务将及其依赖 service mesh 的稳定性,在保障 service mesh 的稳定性上将带来更多的技术考验。目前咱们对于 service mesh 的用法实现设计如下图所示,咱们通过 Sidecar 的形式,将服务发现、负载平衡、集群策略、健康检查以及局部的监控打点等下沉到该组件中,该组件对于不同的服务部署形式部署形式稍有不同。例如对于晚期的裸物理机部署的老服务来说,该组件与服务部署在同一台物理机,而对于例如 K8s 这样的容器部署形式,只须要部署在同一个 Pod,即共享同一个 ip 即可。Sidecar 中凋谢了一些 OpenAPI,部署在一起的服务只须要拜访 localhost 对应端口的 OpenAPI 即可达到相应的服务治理能力。
将来小米新批发效力团队也将在大量的考量与取舍中,更进一步地参加与适配该技术的落地,其中要害的一步也将会有对于 Apache Dubbo、Apache Dubbo-go 等底层框架的适配与交融,必要地状况下将进行一些定制化的革新。
2、Serverless
什么是 Serverless? Serverless(无服务器架构)指的是由开发者实现的服务端逻辑运行在无状态的计算容器中,它由事件触发,齐全被第三方治理,其业务层面的状态则被开发者应用的数据库和存储资源所记录。这也是当下比拟热门的方向。
Serverless 是云原生技术倒退的高级阶段,使开发者更聚焦在业务逻辑,而缩小对基础架构的关注。它与咱们之前说的 service mesh 实际上并不在同一理念上,service mesh 偏向于将根底能力下沉,业务服务与代理一起部署。而 Serverless 则罗唆心愿开发者不再关注服务器,不再关注服务所需资源,这些资源与能力将由 Serverless 的厂商来提供。开发者只须要编写业务函数即可(函数即服务 FaaS)。雷同的是,两者的目标都是为了业务开发可能仅分心于业务逻辑。
目前咱们小米新批发效力团队也正在尝试对一些服务进行 Serverless 化,并提供了一些根底的能力。这些 Serverless 化的服务在开发中同样不须要再关怀底层的协定,无论是 Apache Dubbo、Apache Dubbo-go 都会在咱们后端的 Serverless 零碎中进行兼容与适配,同样以上的一些列服务治理的能力也将由 Serverless 零碎全权托管。
上图就是咱们目前对于服务 Serverless 化的一个根本的反对逻辑,咱们定义了成为 Serverless 服务的 Function 必须实现的接口 execute:
public interface Handler {Result execute(Event var1, Context var2);
default void init(Object... objs) { }
default String version() {return "0.0.1";}
}
业务仅须要实现该接口,并通过平台配置管理该服务的 git 库等信息,就能够以 Serverless 的形式开始提供服务,Serverless 零碎将主动拉取该 Function 的代码信息,编译打包等,提交到外围池中期待执行。并且同时,服务将无感知地接入零碎提供的服务治理、可观测性等能力。
总结
Dubbo 作为一个老牌的、弱小的微服务框架与体系,提供了跨语言的反对,这帮忙咱们将外部不同的技术栈实际上造成了闭环。而 Apache Dubbo-go 作为 Apache Dubbo 生态中一个还在一直迭代倒退的开源我的项目,会存在一些待欠缺的小问题,但更可能切实地帮忙到咱们搭建与倒退整个云原生微服务体系。同样的,咱们在欠缺传统的微服务体系架构的同时,咱们也关注与尝试目前微服务技术的一些倒退方向,像 Serverless、service mesh 这些较为热门的方向,咱们也都将继续的跟进与参加落地。咱们将一直与像 dubbogo 等开源社区单干,踊跃反馈咱们应用的教训,参加欠缺,推动更多此类开源我的项目的倒退。
作者介绍
董振兴,目前就任于小米中国区新批发技术部 - 批发中台 - 研发效力组,负责小米中国区新批发微服务中间件体系及效力相干研发工作。
原文链接
本文为阿里云原创内容,未经容许不得转载。