从负载均衡到路由,微服务应用现场一键到位
微服务体系架构中,服务之间的依赖关系错综复杂,我们往往会使用负载均衡组件配合注册中心来实现服务间的感知。而这种感知行为需要调用方、负载均衡组件、注册中心、被调用方互相配合才能够实现,在出现问题时我们又可能很难确定是哪一部分的问题,在常规场景中,注册中心会有对应的控制台可以查看,而调用方、负载均衡组件、被调用方处则需要我们手动增加日志打印语句并重启应用才能得到相关的信息,而有些组件又难以找到合适的位置添加我们日志代码,使得这类问题的排查效率低下。
负载均衡原理剖析
Cloud Native
我们以 Spring Cloud 应用为例分析一下,微服务负载均衡到底是怎么一回事?
https://github.com/aliyun/alibabacloud-microservice-demo/tree/master/mse-simple-demo
public void updateListOfServers() {
List<T> servers = new ArrayList<T>();
if (serverListImpl != null) {
//从注册中心获取可用服务列表
servers = serverListImpl.getUpdatedListOfServers();
LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",
getIdentifier(), servers);
if (filter != null) {
//根据加载的过滤器过滤地址
servers = filter.getFilteredListOfServers(servers);
LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",
getIdentifier(), servers);
}
}
//更新可用服务列表
updateAllServerList(servers);
}
protected void updateAllServerList(List<T> ls) {
// other threads might be doing this - in which case, we pass
if (serverListUpdateInProgress.compareAndSet(false, true)) {
try {
for (T s : ls) {
s.setAlive(true); // set so that clients can start using these
// servers right away instead
// of having to wait out the ping cycle.
}
setServersList(ls);
super.forceQuickPing();
} finally {
serverListUpdateInProgress.set(false);
}
}
}
com.netflix.loadbalancer.DynamicServerListLoadBalancer#updateAllServerList
-> com.netflix.loadbalancer.DynamicServerListLoadBalancer#setServersList
-> com.netflix.loadbalancer.DynamicServerListLoadBalancer#setServerListForZones
-> com.netflix.loadbalancer.LoadBalancerStats#updateZoneServerMapping
无侵入的微服务洞察能力
Cloud Native
分布式特性:满足在分布式场景下,即使是复杂微服务体系架构下,该能力需要打通微服务链路、日志调整、流量条件匹配,上下游联动等一系列分布式场景下的能力。 无侵入特性:无需重启应用,动态增强与卸载,可以动态增强整个应用或者是任意节点。 完整的现场保留能力:可以将抓取到的现场上下文等信息,自动保留至远端的日志系统中。 灵活的规则配置:可以灵活匹配任意流量,增强任意方法点位,可以灵活控制所需的保留上下文内容。
洞察 loadbalancer 还原服务发现第一现场
目标类: com.netflix.loadbalancer.LoadBalancerStats 目标方法: updateZoneServerMapping(java.util.Map)
观察服务发现结果
appName:log-demo-spring-cloud-a
destinationEndpoint:
end:1662541729796
endpoint:10.0.0.24
hostname:log-demo-spring-cloud-a-58b8b7ccc9-gnmsv
interface:com.netflix.loadbalancer.LoadBalancerStats:updateZoneServerMapping(java.util.Map)
ip:10.0.0.24
parameters:[{"unknown":[{"alive":true,"host":"10.0.0.125","hostPort":"10.0.0.125:20002","id":"10.0.0.125:20002","instance":{"clusterName":"DEFAULT","enabled":true,"ephemeral":true,"healthy":true,"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000,"instanceId":"10.0.0.125#20002#DEFAULT#DEFAULT_GROUP@@sc-B","ip":"10.0.0.125","ipDeleteTimeout":30000,"metadata":{"__micro.service.app.id__":"hkhon1po62@622bd5a9ab6ab48","preserved.register.source":"SPRING_CLOUD"},"port":20002,"serviceName":"DEFAULT_GROUP@@sc-B","weight":1.0},"metaInfo":{"appName":"DEFAULT_GROUP@@sc-B","instanceId":"10.0.0.125#20002#DEFAULT#DEFAULT_GROUP@@sc-B"},"metadata":{"$ref":"$[0].unknown[0].instance.metadata"},"port":20002,"readyToServe":true,"zone":"UNKNOWN"},{"alive":true,"host":"10.0.0.52","hostPort":"10.0.0.52:20002","id":"10.0.0.52:20002","instance":{"clusterName":"DEFAULT","enabled":true,"ephemeral":true,"healthy":true,"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000,"instanceId":"10.0.0.52#200...展开
parentSpanID:-1
ruleName:[237]
serviceType:DYNAMIC
spanID:4096
start:1662541729795
success:true
tag:_base
traceID:ea1a00001816625413997651001d0001
userId:1784327288677274
parameters 部分是被包装成 JSON 格式的入参,将其格式化后可以看到这便是我们想要获取的可用服务列表。
[
{
"unknown": [
{
"alive": true,
"host": "10.0.0.125",
"hostPort": "10.0.0.125:20002",
"id": "10.0.0.125:20002",
"instance": {
"clusterName": "DEFAULT",
"enabled": true,
"ephemeral": true,
"healthy": true,
"instanceHeartBeatInterval": 5000,
"instanceHeartBeatTimeOut": 15000,
"instanceId": "10.0.0.125#20002#DEFAULT#DEFAULT_GROUP@@sc-B",
"ip": "10.0.0.125",
"ipDeleteTimeout": 30000,
"metadata": {
"__micro.service.app.id__": "hkhon1po62@622bd5a9ab6ab48",
"preserved.register.source": "SPRING_CLOUD"
},
"port": 20002,
"serviceName": "DEFAULT_GROUP@@sc-B",
"weight": 1.0
},
"metaInfo": {
"appName": "DEFAULT_GROUP@@sc-B",
"instanceId": "10.0.0.125#20002#DEFAULT#DEFAULT_GROUP@@sc-B"
},
"metadata": {
"$ref": "$[0].unknown[0].instance.metadata"
},
"port": 20002,
"readyToServe": true,
"zone": "UNKNOWN"
},
{
"alive": true,
"host": "10.0.0.52",
"hostPort": "10.0.0.52:20002",
"id": "10.0.0.52:20002",
"instance": {
"clusterName": "DEFAULT",
"enabled": true,
"ephemeral": true,
"healthy": true,
"instanceHeartBeatInterval": 5000,
"instanceHeartBeatTimeOut": 15000,
"instanceId": "10.0.0.52#20002#DEFAULT#DEFAULT_GROUP@@sc-B",
"ip": "10.0.0.52",
"ipDeleteTimeout": 30000,
"metadata": {
"__micro.service.app.id__": "hkhon1po62@622bd5a9ab6ab48",
"preserved.register.source": "SPRING_CLOUD",
"__micro.service.env__": "[{\"desc\":\"k8s-pod-label\",\"priority\":100,\"tag\":\"gray\",\"type\":\"tag\"}]"
},
"port": 20002,
"serviceName": "DEFAULT_GROUP@@sc-B",
"weight": 1.0
},
"metaInfo": {
"appName": "DEFAULT_GROUP@@sc-B",
"instanceId": "10.0.0.52#20002#DEFAULT#DEFAULT_GROUP@@sc-B"
},
"metadata": {
"$ref": "$[0].unknown[1].instance.metadata"
},
"port": 20002,
"readyToServe": true,
"zone": "UNKNOWN"
}
]
}
]
一键解决全链路灰度流量逃逸问题
Cloud Native
有时某个功能发版依赖多个服务同时升级上线。我们希望可以对这些服务的新版本同时进行小流量灰度验证,这就是微服务架构中特有的全链路灰度场景,通过构建从网关到整个后端服务的环境隔离来对多个不同版本的服务进行灰度验证。在发布过程中,我们只需部署服务的灰度版本,流量在调用链路上流转时,由流经的网关、各个中间件以及各个微服务来识别灰度流量,并动态转发至对应服务的灰度版本。如下图:
我们配置全链路灰度的流量流向是否符合预期,我们的流量是否按照我们配置的灰度规则进行匹配。 我们灰度的流量出现了大量的慢调用、异常,我该如何确定是我们新版本代码的业务问题还是因为我们在流量灰度过程中考虑不全导致的系统问题,如何快速定位问题,从而实现高效的迭代。 在我们设计灰度系统的过程中,我们需要考虑如何对我们的灰度流量进行打标,有些时候在入口应用、微服务接口处可能难以找到合适的流量特征(参数、headers 等携带的具备业务语义的标识),在这样的场景下我们如何快捷地对我们的流量进行打标。
洞察灰度流量,流量逃逸问题无所遁形
我们配置全链路灰度的流量流向是否符合预期,有没有流量打到了非灰度应用 符合灰度规则的流量是否被打上了对应的灰度标签 不符合灰度规则的流量是否存在被误打上灰度标签的情况
定位灰度流量的问题
总结
Cloud Native
END
微信扫码关注该文公众号作者
戳这里提交新闻线索和高质量文章给我们。
来源: qq
点击查看作者最近其他文章