基于etcd实现大规模服务治理应用实战
The following article is from 百度Geek说 Author 百度小程序团队
导读:服务治理目前越来越被企业建设所重视,特别现在云原生,微服务等各种技术被更多的企业所应用,本文内容是百度小程序团队基于大模型服务治理实战经验的一些总结,同时结合当前较火的分布式开源kv产品etcd,不仅会深入剖析ectd两大核心技术Raft与boltdb的实现原理,也会披露服务治理真实实践的经验,希望帮助大家在服务治理的道路上获得更多帮助。
全文8243字,预计阅读时间21分钟。
一、服务治理概念介绍
服务治理是IT治理的一部分,它关注服务生命周期中的相关要素,其重点环节包括服务注册和发现、服务平滑升级、流量监控、流量管控、故障定位、安全性等。
服务是需要"治理"的,但是治理是需要成本的,如果一个服务的业务逻辑简单,运行流程清晰,出现问题也能及时定位和回滚,那么该服务治理的成本可能非常低,甚至只需要人工处理就行,但是在复杂业务中,服务的提供者和服务的使用者可能分别运行在不同的进程中(甚至在不同的物理节点上),并由不同的团队开发和维护。团队协作和服务协同,都需要进行大量的协调工作。协调工作越多,复杂度越高,这样就有了服务治理的需求,通过建设统一的服务治理平台,就可以有有效的提升业务的服务治理能力,包括协同的规范化、实时监控,不断优化调用链路的效率,以及辅助降低依赖复杂度,规避风险等。在大型业务系统中,服务治理已经是技术架构中必不可缺的一部分,也是整个业务系统最重要的基础设施之一。
在服务注册发现之后,就是服务的调用,大量的服务调用,形成了流量。流量监控就是对众多服务间的调用关系、状态的清晰掌控。其主要包括了调用拓扑关系、调用追踪、日志、监控告警等,服务治理通过调用拓扑来整体监控服务调用关系,通过建立监控体系来快速发现、定位问题,从而在整体上感知业务系统的运行状况。在服务生命周期中,流量监控负责服务的运行态感知。
在业务系统运行过程中,经常会有比如促销、秒杀、明星绯闻等热点问题,或者机房断网、断电、系统大范围升级等突发事件,带来业务系统中局部服务的流量突增突降,这样就需要对服务的流量进行调度和管理。流量管理包括两个方面:从微观的单个服务来说,就是服务调用过程的管理,包括在何时采用何种均衡负载策略、路由策略以及熔断限流策略,这些策略统称为调用策略;从宏观上来说,就是流量分发的管理,可以根据某些流量特征和流量占比进行灰度发布、蓝绿发布等,这些称为流量分发策略。服务调用策略、流量分发策略,都需要通过流量监控收集的调用数据进行分析,从而制定出决策,然后在服务治理平台上落地。流量调度负责服务的运行态管理。
流量调度的策略如何在服务的提供方和调用方生效,可以重启生效,也可以在运行态实时生效,这就是看服务治理平台对服务的控制力度,服务治理平台在充分建设服务治理能力后,能实时把服务治理的策略向服务进行分发并立即生效。
每个服务都承载自身的业务职责,一些业务敏感的服务,需要对其他服务的访问进行认证与鉴权,也就是安全问题。
大型业务系统,海量的服务调用,错综复杂的调用关系,对服务的可靠性要求很高,很多基层的服务都要求99.99%的可靠性,因而维护这些服务的服务治理平台,其可靠性的要求也非常高,而要达到这么高的可靠性,服务治理平台本身也需要做到多级部署、多地热备、降级隔离、平滑上线等方案。
在保证可靠性的前提下,服务治理还必须有很高的性能,比如在监控数据中,快速准确的感知到某个服务的出现了单点故障,从而能够将流量分发到该服务的其他进程上去。如果业务系统的服务数不多,调用量不高,那么监控数据量也不会很大,服务的单点故障很容易就能查到,但是在实时的海量调用数据中,一些常规的查询手段要花费大量的时间,等感知到单点故障时,可能已经造成了不可挽回的业务损失。所以性能是考量服务治理平台治理能力的一项重要指标,如何保证高性能,高速的存储、多级缓存、线性部署都是必不可少的。
高扩展包含两个方面:大型应用系统的服务,可能是由多个团队在开发运维,其水平和技术能力也是参差不齐的,因而服务治理平台需要提供兼容和扩展的能力,通过扩展性,尽可能的把不同的服务治理起来;同时,在业务系统服务量增长时,服务治理平台也应该具备同步扩展的能力,来保证其高可靠和高性能。
二、etcd介绍
2.1 etcd发展背景与相关竞品介绍
ZooKeeper从高可用性,数据一致性,功能这三个方面而言是完全符合需求的,但CoreOS还是坚持自研etcd的原因总结有以下两点:
2.2 etcd核心技术介绍
基于Raft协议实现数据高可用和强一致性
Leader选举
日志复制
安全性
boltdb存储技术
文件存储设计
类型 | Flag标识 | 个数 | 长度 | 说明 |
meta | 0x04 | 2 | 80字节。其余为空 | 元数据信息。包含存储B+树root buck位置,可用块的数量freelist,当前最大块的offset等。分为metaA与metaB, 用来控制进行中的事务与已完成的事务(写事务只有一个进行中). 根据meta中的txid的值的大小来判断当前生效的是哪个meta。(txid会根据事务操作递增) |
freelist | 0x10 | 1或多个 Overflow引用 | 变长 | Freelist用于管理当前可用的pageid列表。由Meta元数据信息中的freelist字段来定位所在的pageid位置。 |
【data】bucket | 0x01 | 1或多个 Overflow引用 | 变长 | 存储bucket名称数据,bucket名称也是采用B+树结构存储。根root bucket的pageid由meat的root字段指定 |
【data】branch | 0x01 | 1或多个 Overflow引用 | 变长 | 存储分支数据内容。分支数据结构中只有key信息,没有value信息。指向的都是下一级节点的pageid信息 |
【data】leaf | 0x02 | 1或多个 Overflow引用 | 变长 | 存储叶子数据内容。 |
数据文件全景结构
metapage固定在page0与page1位置 Pagesize大小固定在4096字节
bolt的文件写入采用了本地序(小端序)的模式,比如16进制0x0827(2087)写入的内容为2708000000000000
查询设计
tx, err := db.Begin(true) // 开启事务
if err != nil {
return
}
b := tx.Bucket([]byte("MyBucket")) // 根据名称查询bucket
v := b.Get([]byte("answer20")) // 根据key进行查询
fmt.Println(string(v))
tx.Commit()
func (c *Cursor) search(key []byte, pgid pgid) {
p, n := c.bucket.pageNode(pgid)
if p != nil && (p.flags&(branchPageFlag|leafPageFlag)) == 0 {
panic(fmt.Sprintf("invalid page type: %d: %x", p.id, p.flags))
}
// 把当前查询节点(page,node)压入栈
e := elemRef{page: p, node: n}
c.stack = append(c.stack, e)
// If we're on a leaf page/node then find the specific node.
if e.isLeaf() {
c.nsearch(key)
return
}
// if node cached seach by node's inodes field
if n != nil {
c.searchNode(key, n)
return
}
// recursively to load branch page and call search child node again
c.searchPage(key, p)
}
三、百度基于etcd打造大规模服务治理建设思路
3.1 具体的挑战
3.2 整体架构建设思路与方案
考虑到etcd跨机房调用的高网络延时,我们采用单机房部署,同时我们也实现了主备集群切换的方案,解决在单机房实例全部宕机的情况下,etcd集群不可用的问题。
为了降低平台对etcd的强依赖,我们做了etcd降级使用缓存的方案。在监控到etcd集群的性能无法支持当前平台的时候,使用缓存存储实例数据,能够让运维人员在恢复etcd之前,系统不受影响正常运行;etcd恢复之后,切换回etcd集群继续工作。
etcd集群的kv查询性能很高,qps能达到10000以上。为了解决在极端并发下的性能问题,注册中心采用多级缓存提升查询效率,降低对etcd的访问压力。
服务间调用使用直连的方式,请求不需要经过注册中心进行转发,调用基本没有时间损耗。
考虑到将来服务实例数达到百万级别,我们需要考虑架构的高扩展性。
用户通过可视化的管理平台可以查看已注册的服务,也可通过管理平台实时更新服务治理策略的配置,实时调整服务治理策略。
将调用日志接入trace平台,用户可通过traceId在trace平台查到整个调用链的记录,便于出错时进行快速的问题定位。
多语言 SDK,支持多种rpc技术,包括百度自研的rpc技术brpc(https://github.com/baidu/Jprotobuf-rpc-socket【java/go sdk】)和http jsonrpc协议等
3.3 关键的指标与运维目标
关键指标:
运维目标:
故障发现早
故障处理快
四、总结
参考阅读:
技术原创及架构实践文章,欢迎通过公众号菜单「联系我们」进行投稿。