得物社区的微服务流量治理演进之路
如果无法正常显示,请先停止浏览器的去广告插件。
1. POIZON
得物社区的微服务流量治理演进之路
得物-社区后端技术
赵旸(York)
2. POIZON
目录
01 得物社区微服务概览
02 出道即巅峰?—— Service Mesh 阶段
03
04
05
Istio下线历程
小得物流量治理
未来展望:殊途同归
3. POIZON
01
得物社区微服务概览
4. POIZON
首页推荐流
1.1 得物社区业务概览
动态详情页
国内最大潮流文化社区
聚集最懂潮流的年轻人
提升一代年轻人的潮流审美
帮助年轻人找到自己的风格
100 + 当红明星引领潮流风尚
100w + 潮流爱好者晒出开箱
500+品牌官方账号
500+认证专业达人
5. POIZON
1.1 得物社区业务概览
业务架构
C端
Feeds流、内容基础、用户基础、
创作者、发布工具、互动、活
动、搜索、商业化等
中后台
审核、内容标签、内容理解、宽
表聚合、生态治理等
另外还有直播、鉴别讨论区、交
易搭配等泛社区业务,大量微服
务整体对外提供业务支撑
6. POIZON
1.2 微服务部署
应用生命期管理
微服务部署在阿里云上,基于 Kubernetes 做应用的生命周期管理,包括部署、扩缩容、自动恢复、发布等,
Kubernetes 为微服务提供了可扩展、高弹性的部署和管理平台。
持续集成与发布
使用自研的SCM(基于gitlab)做分支管理和代码检查,在得物发布平台里选择分支和要部署的环境进行持续集
成、或通过手动发布来触发Jenkins pipeline,自动编译代码并打包成docker镜像推送到Harbor镜像仓库、生成
应用的 Kubernetes YAML配置文件、更新 Ingress 配置等,最后调用 Kubernetes 的API来部署应用。
问题:
• 微服务之间如何互相发现
• 南北/东西流量
• http/rpc 负载均衡
• Service 流量细粒度控制
• 灰度发布
7. POIZON
02
出道即巅峰? ——
Service Mesh 阶段
8. POIZON
2.1 第一阶段:Service Mesh
老集群 2020年Q1-Q3
引入 Service Mesh 原因:
traffic
• SDK开发门槛、版本升级和兼容性
• 历史技术债导致缺乏治理能力
SLB
• 业务开发可以专注于业务逻辑
• 南北流量:SLB -> Istio Ingress Gateway -> Pod(sidecar -> App)
• 东西流量:Pod(App -> sidecar) -> Pod(sidecar -> App)
Gateway
Istio Ingress Gateway
(Envoy)
configures
Destination Rule
Virtual Service
get endpoints
external
traffic
Pod
sidecar
Pod
Pod IP:port
sidecar
svc name:port
App
App
Service Mesh 将流量管理从 Kubernetes 中解耦
Service
track associated
pod instances
Endpoints
9. POIZON
Pod IP: 10.40.0.18 Pod IP: 10.40.0.15
Pod Pod
①
App Get http://reviews:9080/xx
2.2 Service Mesh端到端调用分析
App
svc name: reviews
iptables redirect
②
Port:15001
Envoy
Envoy
③ VirtualOutboundListener
④ Outbound Listener
0.0.0.0_9080
⑤
⑥
⑦
找不到和请求目的地端
口匹配的 Listener?
Inbound Cluster:
inbound|9080|http|reviews…
filter chain
Route:9080
Endpoint:
127.0.0.1:9080
Route 匹配不到
OutboundCluster?
VirtualInboundListener
filter chain
Outbound Cluster:
outbound|9080||reviews…
② 请求被iptables规则拦截,重定向到本地的15001
端口
③ 在15001端口监听的Envoy使用VirtualOutbound
Listener处理请求
④ 请求被VirtualOutboundListener根据原目标IP
(通配)和端口(9080)使用0.0.0.0_9080这个
outbound listener继续处理
⑤ 每个Listener会定义一组filter,共同组成过滤器链
(filter chain)来执行高阶的流量控制,例如转换
协议消息、生成统计信息、限流等。根据listener
中http_connection_manager filter的配置,该请
求采用“9080”route进行分发
⑥ Route是一组将虚拟主机(virtual hosts)与集群
(cluster)匹配的规则。 virtual hosts = domain +
path。本例中将domain为reviews的请求匹配到的
cluster是
outbound|9080||reviews.default.svc.cluster.local
⑦ Cluster是服务集群,包含endpoints,envoy通过
Cluster来实现流量的负载均衡,会定期轮询CDS来
获取/更新配置
兜底措施:
Port:15006
Endpoint:
10.40.0.15:9080
① 调用端发起http请求,对端svc name: reviews,
port: 9080
iptables redirect
PassthroughCluster【关键】
•
•
global.outboundTrafficPolicy.mode : ALLOW_ANY
匹配到的所有出流量都会被直接放行
BlackHoleCluster
•
•
global.outboundTrafficPolicy.mode : REGISTRY_ONLY
匹配到的所有出流量都会被直接丢弃
10. POIZON
Pod IP: 10.40.0.18 Pod IP: 10.40.0.15
Pod Pod
①
App Get http://reviews:9080/xx
2.2 Service Mesh端到端调用分析
App
⑧ 请求被转发到其中一个endpoint 10.40.0.15:9080
svc name: reviews
⑬
iptables redirect
②
Port:15001
Envoy
③
④
⑤
⑥
Envoy
VirtualOutboundListener
Outbound Listener
0.0.0.0_9080
⑫
⑪
filter chain
Route:9080
⑩
Endpoint:
127.0.0.1:9080
Inbound Cluster:
inbound|9080|http|reviews…
VirtualInboundListener
filter chain
⑦
Outbound Cluster:
outbound|9080||reviews…
Port:15006
⑧
Endpoint:
10.40.0.15:9080
⑨
iptables redirect
⑨ 请求到达对端pod后被iptable规则拦截,重定向到
本地的15006端口
⑩ 在15006端口上监听的Virtual Inbound Listener
收到了该请求,将直接在 VirtualInboundListener
采用一系列 filter chain 对入向请求进行处理,而
不是像 VirtualOutboundListener 一样分发给其
它独立的 listener 进行处理
⑪ 根据http_connection_manager filter的配置,转
给 inbound|9080|http|reviews.default.svc.clust
er.local 这个Inbound Cluster
⑫ 该Inbound Cluster配置的endpoint为
127.0.0.1:9080
⑬ 请求被转发到和sidecar同一个pod上的9080端
口,即reviews服务进行业务处理
Service Mesh对服务间流量通讯进行了抽象,把复杂
的治理能力下沉到不与业务耦合的proxy中。
额外消耗
• 资源:代理容器
• RT:上下行各多了一跳
11. POIZON
2.3 Service Mesh与侵入式框架比较
Service Mesh
侵入式框架
社区服务当时的实际情况
学习门槛 低,独立的sidecar在网络层拦截完成流量控制和 高,需要学习和理解远程通信、服务注册发现、负载
服务治理工作,让上层业务开发只专注于业务逻辑 均衡、监控、熔断限流等技术 功能齐全 细粒度的流量控制,如蓝绿发布、金丝雀发布、故 生态成熟,从注册中心到监控中心各环节的中间件一
障注入等,完善的可观察性、安全控制
应俱全,一整套体系已经在业界打磨和运作多年 Istio服务治理方面的高级特性得
物有其他替代方案,并非刚需
跨语言 不限制语言,统一的通信策略 社区服务纯Golang技术栈,没
有跨语言的诉求
运维效率 对运维要求高,包括sidecar注入、热升级、启动
顺序、容量管理、监控、回滚摘流、安全性等,配 传统运维方式,经验和效率是优势
置过于复杂 Istio配置复杂,因为配置变更出
过多次故障
问题排查 对业务研发较为“黑盒” 排查手段更可控、定位问题更快 对业务研发太“黑盒”,比如外
网流量都没打到业务容器,要去
找运维查,沟通成本高
升级效率 热升级sidecar对业务基本无感知 需要推动业务升级框架,重新部署上线 基本没有升级
通过sidecar,端到端延迟增加
约4ms,有损耗但不是瓶颈
需要开发各种语言的sdk
性能 通过代理进行通信,增加延迟和CPU开销 端到端直接通信,没有proxy网络拦截,性能更好
可定制化 对上层业务较难定制化 可定制更贴合个性化业务场景的流量策略、观测性、
可用性(超时重试、限流熔断)策略
12. POIZON
2.4 Service Mesh增大了系统复杂度和排查难度
举例:一次RT抖动问题排查过程
① 一次直播某服务RT抖动,从监控指标发现该服务全部接口RT和
全部pod的goroutine都上涨明显,首先判断影响范围为服务
级别。且同k8s集群中其余服务正常,排除网络原因;所有的
流量出入接口都受到影响,但下游依赖服务正常,也排除了依
赖服务故障。
② 首先考虑系统资源是否充足,通过查看应用的cpu、memory
指标,判断告警时间点系统资源不存在瓶颈。这里业务研发一
般只关注自己应用的状态,因而对资源情况产生了误判,以为
是数据层存在故障。
③ 但查看数据存储的性能趋势显示正常,且使用同样数据存储的
另一服务告警时段处于正常,因此不是数据层的问题。
④ 服务扩容后RT抖动也恢复正常,所以还是将目光转
向流量路径,最后查看istio-proxy的负载,定位了
告警原因:sidecar负载过高导致了此次抖动。
问题根因:sidecar和业务容器
资源配比问题。
历史原因sidecar注入时固定
2c1g配置,业务容器原先是
1c512m,但随着业务量增长
该服务pod数过多。开发当日
升配了业务容器到4c2g,在总
核数不变情况下pod缩到原来
的1/4,每个pod里的sidecar
承担的流量同期扩大了4倍,高
峰期负载打满。
13. POIZON
03
Istio 下线历程
14. POIZON
3.1 两种方式并行:加入dubbo-go
老集群 2020年Q4-2021年Q3
traffic
通过服务发现在nacos中拿到Provider的
ip和port,流量还是要经过sidecar,转发
SLB
到目标pod,再通过sidecar到达目标服务
Istio Ingress Gateway
(Envoy)
external
traffic
Pod
sidecar
Pod
Pod IP:port
Pod
sidecar
sidecar
svc name:port
App
Pod
Pod IP:port
sidecar
Pod IP:port
App
App App
dubbo-go dubbo-go
引入dubbo-go,主要使用了grpc server/client和注册中心功能
nacos
15. POIZON
3.2 下sidecar
老集群 2021年Q4
traffic
先到SLB,Istio Ingress Gateway作为proxy转发到目标pod
grpc without dubbo-go
SLB
Istio Ingress Gateway
(Envoy)
通过服务发现在nacos中拿到Provider的ip和port,直接转发到目标
pod,没有 proxy 的额外“一跳”
Pod
Pod
App
external
traffic
http
Pod
App
Pod
App
Pod IP:port
dubbo-go
App
dubbo-go
集群内http调用走的是k8s service域名解析,利用k8s的dns
和service负载均衡能力
nacos
16. POIZON
3.3 迁移kubeone&下Gateway
新集群 2022年Q1
traffic
grpc without dubbo-go
SLB
利用集群迁移机会,用Nginx Ingress Controller 代替 Istio Ingress Gateway,彻底下线 Istio
Ingress Controller
(Nginx)
Pod
Pod
tools-c
log-c
App
http
tools-c
log-c
App
Pod
tools-c
log-c
App
Pod
Pod IP:port
dubbo-go
external
traffic
新集群使用神龙7,性能提升明显
tools-c
log-c
App
dubbo-go
nacos
17. POIZON
3.4 坑点:grpc负载均衡
grpc负载均衡问题
grpc使用http2在同一连接和双工流中复用请求避免最初的时间和资源花费在TCP握手上,当客户端获取与服务器实例的连接时它将保持连接。
这是grpc的优点,但也带来负载均衡的问题。istio/envoy实现了grpc在pod间的负载均衡,下掉 istio 就必须解决这个问题。通常有两种方式
实现grpc负载均衡:
优点: 优点:
• 客户端简单,无需感知后端 • 性能好,消除了额外一跳
服务
• 分布式,去中心化,适合大
流量场景
缺点:
a. Proxy load balancing
• 多了一跳,更高延迟 缺点:
• LB中心化可能成为瓶颈 • 客户端复杂:跟踪后端负载
b. Client-side load balancing(首选)
又叫Server-side load balancing,LB追踪后端服务 客户端进程感知可用的后端服务并且实现负载均衡:
负载并实现负载均衡: ① 客户端直接向后端服务起RPC请求,没有额外开
① 客户端向LB发起RPC请求
② LB将请求转发给后端某个可用的服务
③ 后端服务将负载报告给LB
销,性能比较好
② 后端服务的负载和运行情况要能让客户端追踪到
和运行状况,实现负载均衡
• 每种语言客户端的实现负担
18. POIZON
3.4 坑点:grpc负载均衡
未接入dubbo-go的服务间的grpc调用
社区域通过grpc方式调用同集群内其他业务域(增长、鉴别)未集成dubbo-go的服务,下掉Istio sidecar后首先尝试 Client-side load
balancing 解决grpc负载均衡问题
方式一:PickFirst(默认)
PickFirst 是 golang grpc 默认的LB策略,如果直接通过
grpc.Dial(“k8s service name”)的方式去创建 ClientConn,只
会选取 service 后端 pods 中的一个进行连接
特点:客户端与服务的所有pod间只有一条长连接
坑点:往 ClientConn 上发请求,流量都会打到后端同一个pod上
方式二:RoundRobin + headless service(尝试使用)
RoundRobin 是 golang grpc 内置支持的另一种LB策略,可以通
过grpc的DialOption指定:
19. POIZON
3.4 坑点:grpc负载均衡
未接入dubbo-go的服务间的grpc调用
社区域通过grpc方式调用同集群内其他业务域(增长、鉴别)未集成dubbo-go的服务,下掉Istio sidecar后首先尝试 Client-side load
balancing 解决grpc负载均衡问题
方式二:RoundRobin + headless service
RoundRobin策略一般与k8s的headless service一起配套使用:
• “dns:///greeter_server”,其中通过URI scheme决定使用何
种grpc resolver插件来做名字解析,这里选择DNS
• headless service,配置clusterIP为None,DNS解析service域
名拿到后端pod的真实IP列表
• grpc为每个后端地址创建一个subchannel,并持续监视这些子
通道的连接状态,断开时会重连
• 当发起RPC请求时,会从状态为READY的subchannel中轮流选
择发送
trick - MaxConnectionAge (不推荐) :
grpc在长连接断开时会 re-resolve 重新建立连接,可以利用这个特性在服务
端设置keepalive.MaxConnectionAge,周期性断开连接来触发刷新,例如:
特点:客户端与服务的每一个pod都保有一条长连接
坑点:新扩容上去的pod很久都没有流量进来
• 服务扩容的时候,新实例并不会加入其中,需现有连接断开时才
能触发grpc重新连接
• DNS如coredns本身有缓存,且没有 watch 或 push 机制,压
根没有服务发现场景下的优化
20. POIZON
3.4 坑点:grpc负载均衡
未接入dubbo-go的服务间的grpc调用
最终还是选择 Proxy load balancing 方式,Nginx在1.13.10 中已增加了对 grpc 的原生支持,但是 官方文档中提到它当前支持的 grpc流量必须
基于ssl,不支持在80端口中复用HTTP1/1和HTTP2,内部grpc服务是监听非安全端口8080
解决方案:
• nginx ingress controller使用安全端口443端口支持http2
• grpc 使用 tls,并在代理层摘掉 tls,转发给内部服务的非安全端口8080
扩容和缩容grpc负载均衡均符合预期
21. POIZON
04
小得物流量治理
22. POIZON
4.1 小得物环境简介
什么是小得物环境?
小得物环境是一套全新搭建、物理隔离的[小流量][生产环境],覆盖了从网络(VPC)、接入层(SLB/DLB)、中间件(dubbo/consul)、核心应用的系
统和服务,为各类产品研发和业务发展的稳定性提供了丰富工具和应用场景。
23. POIZON
4.2「小得物-生产」双集群架构
智能DNS解析 根据出口IP
将部分流量劫持至xdw
1%
app.dewu.com
社区小得物环境
DLB中配置基于userid等
信息的二次灰度规则
网关精确路由配置与生产共用
在xdw网络环境上将内网域名
DNS劫持至xdw-internal DLB
xdw-internal DLB负责配置
path转发,将未部署小得物的
应用转发至生产
诉求:RPC优先访问小得物服
务,小得物没有则访问生产服务
99%
社区生产环境
XDW DLB PRD DLB
XDW APP gateway XDW APP gateway
xdw-internal DLB
未命中去生产
SLB SLB
Ingress Controller Ingress Controller
Service
跨环境RPC
Service
24. POIZON
4.3 小得物流量路由
自定义grpc Resolver、Balancer实现
Resolver 负责向 Balancer 提供后端列表,Balancer 负责监听后端列表、发起连接的创建与移除,Picker 负责在帧传输阶段从已建立好的连接
中选择一个
Balancer模块
Resolver模块
grpc服务端
解析目标名称 管理SubConn <<interface>>
Resolver <<interface>>
Balancer 构建解析器实例 构建平衡器实例 负责具体连接
<<interface>>
Builder <<interface>>
Builder <<interface>>
SubConn
选择SubConn 存储
<<interface>>
Picker
server3
server2
server1
② Pick
grpc客户端
① 获取连接
③ 返还某个连接
<<interface>>
ClientStream
定义grpc客户端
streaming方式
stream模块
建
立
连
接
阶
段
④ 在选择的连接上,传输头帧、数据帧
帧
传
输
阶
段
25. POIZON
4.3 小得物流量路由
hyper Resolver
grpc 解析器的作用主要有两个:
1. 解析字符串 Scheme://Authority/Endpoint 得到后端提供服务的地址列表,字符串映射的是resolver.go里的结构体Target,Scheme和
Authority不是必须的,Scheme默认是passthrough,Authority默认是空,Scheme作为key指定使用什么解析器Builder对象
2. 更新状态,触发balancer的流程,从而跟grpc服务端建立连接
内建的三种解析器:
•
passthrough:默认类型,用户传入的就是grpc服务端的地址
调用方法:conn, err := grpc.Dial(“localhost:50051”, grpc.WithInsecure(), grpc.WithBlock())
等价于:conn, err := grpc.Dial(“passthrough:///localhost:50051”, grpc.WithInsecure(), grpc.WithBlock())
• dns:利用golang net包函数做域名解析获取服务端的地址
调用方法:conn, err := grpc.Dial("dns:///svc_name:default.svc.cluster.local:50051", grpc.WithInsecure(), grpc.WithBlock())
• manual:并不是通过scheme、target来获取服务端地址,而是手动维护
先创建并注册一个Resolver,再调用 InitialState 方法把服务端地址手动传给Resolver对象维护,这种类型解析器常用于测试
26. POIZON
4.3 小得物流量路由
hyper Resolver
实现自定义的解析器(Scheme命名为hyper),支持多注册中心服务发现:可从多个注册中心订阅 ServiceName 的地址变化,然后根据优
先级进行地址合并排序得出最终 addrs 更新 grpc 的 subConn 。
定义名字服务接口
注册中心优先级
配置中心里配置服
务sns-cnt-center
支持多注册中心
根据优先级进行最
支持的 Registry 类型:
•nacos: 主注册中心,支持简洁服务名,如 provider:sns-cnt-center
•dubbo:基于 nacos,兼容 dubbo-go 的服务名,如 CntCenterGrpc.ICntCenter
•k8s:备注册中心,通过 watch endpoint 资源获取地址,pod 需要 get、list、
watch 权限,优点是不需要单独去运维 etcd 等额外中间件
•direct: 直连 url,可用于本地开发
可以通过接口扩展 registry 来支持 etcd、consul、zookeeper 等其他注册中心。
终地址计算,按照
priority 从大到小
排序,同优先级地
址去重合并,得出
优先级最高且不为
空的地址集
(priority负数表
示禁用)
27. POIZON
4.3 小得物流量路由
hyper Resolver
通过实现grpc resolver两个核心接口 Builder、Resolver 满足自定义hyper解析器逻辑,调用方式:
conn, err := grpc.Dial(“hyper:///sns-cnt-center”, grpc.WithInsecure(), grpc.WithBlock()) // 以简洁服务名作key获取后端服务地址
各 Registry 的优先级可通过配置中心动态调整,配置调整后会调用 ResolveNow 更新所有 grpc client 的 SubConn
多注册中心收益:稳定性、扩展性
watch
nacos
watch
NacosRegistry <<interface>>
IRegistry
DubboRegistry <<interface>>
IRegistry
hyper resolver
只监听小得物的nacos,生
产nacos数据同步合并到小
得物nacos(分钟级)
k8s
watch
ark
DirectRegistry <<interface>>
IRegistry
K8sRegistry <<interface>>
IRegistry
通过远端配置动态更新
Registry优先级
更新最终地址
聚合多个Registry地址,根据 priority
合并、排序,得到优先级最高的非空
地址集作为最终地址
grpc SubConns
28. POIZON
4.3 小得物流量路由
Tag Picker
grpc 每次远程调用都会创建一个ClientStream,ClientStream会调用Picker接口的Pick方法选择一个缓存的rpc链接,然后在这个链接上传输
数据。通过实现自定义TagPicker,解析预设的 tag 规则来筛选出匹配的目标地址。
① 配置小得物环境的流量匹配规则,支持多个
规则,前面的优先匹配,后面的用作兜底
② hyper resolver解析时会将nacos元数据设置到 resolver.Address 的 Attributes。
小得物环境服务的元数据都带有 env:xdw 标识,可用于区分生产环境的服务
③ Pick时每个tag规则生成一个 TagPicker,分别对每个 resolver.Address 按照 Attributes 筛选,当前一个 TagPicker 筛选出的目标地址列表不为空
时,会忽略后面的 TagPicker 的结果
• 当小得物环境中有部署目标服务时,流量只会路由到小得物里的服务
• 当小得物里服务发现没找到目标服务时(即根据 env : xdw 筛选出的目标地址列表为空)会使用兜底的结果,即生产环境服务的目标地址,将
流量路由到生产环境
29. POIZON
流量路由开关
开启(前期、日常维护)
4.3 小得物流量路由
1%
app.dewu.com
社区小得物环境
99%
社区生产环境
XDW DLB PRD DLB
XDW APP gateway XDW APP gateway
• 小得物单服务部署
• 跨环境RPC
• 基础架构小流量灰度变更
• 服务调优
xdw-internal DLB
未命中去生产
SLB SLB
Ingress Controller Ingress Controller
Service
跨环境RPC
Service
30. POIZON
流量路由开关
关闭(稳定运营期、重要节点)
4.3 小得物流量路由
1%
社区小得物环境
app.dewu.com
99%
社区生产环境
XDW DLB PRD DLB
XDW APP gateway XDW APP gateway
• 生产发布前置
• 混沌工程
• 大促保障
xdw-internal DLB
SLB SLB
Ingress Controller Ingress Controller
Service Service
31. POIZON
05
未来展望:殊途同归
32. POIZON
5.1 未来展望:Proxyless Service Mesh?
什么是Proxy Service Mesh
Google 的 gRPC 团队支持了 Istio 的 Control Plane,并把这种架构称之为 Proxyless Service Mesh,国内很多公司也上了类似的架构,采用
Istio 的 Control Plane 来对接 bRPC,Dubbo 等 RPC 框架。当前主流的Proxyless Service Mesh 就是 Istio 的 Control Plane + RPC 框架
xDS
xDS 协议是“x Discovery Service” 的简写,这里的x表
Istio Control Plane
xDS
示它是一组基于不同数据源的服务发现协议的总称,例如:
• CDS:Cluster 集群发现服务
• RDS:Route 路由发现服务
Pod
Pod
• EDS:Endpoint 集群成员发现服务
• LDS:Listener 监听器发现服务
在 Istio 中,基于 xDS 协议提供了标准的控制面规范,并
rpc
App
rpc
App
以此向数据面传递服务信息和治理规则。
主流Proxyless Service Mesh架构
33. POIZON
5.1 未来展望:Proxyless Service Mesh?
xDS实际上定义了Service Mesh的能力标准
xDS提供了协议和标准化:既能支持envoy(sidecar形式),也能支持多语言sdk。普通的配置中心并不感知配置的实际含义,没有实现
Service Mesh的标准能力;即使RPC框架实现了Istio的所有标准能力,若没有统一的协议和配置格式,也不能算Service Mesh。
未来:重回Service Mesh?
配置中心
基于nacos2.0
Pod
Pod
rpc
App
rpc
App
社区当前“配置中心 + RPC框架”并不是Proxyless Service Mesh
34. POIZON
THANKS
35. POIZON
得物技术公众号