经过近期的努力,已经为公司初步搭建起了一套基于 springcloud、docker、k8s、gitlab-ci 的微服务结构。虽然可以整条线跑起来了,但是还有很多支撑服务有待完善,今天主要讲一下我是如何通过 Spring Cloud Sleuth + Zipkin 来解决分布式链路跟踪问题的,以及过程中出现的问题。
Spring Cloud Sleuth 为服务之间调用提供链路追踪。通过Sleuth可以很清楚的了解到一个服务请求经过了哪些服务,每个服务处理花费了多长。从而让我们可以很方便的理清各微服务间的调用关系。
Zipkin 是一个开放源代码分布式的跟踪系统,由 Twitter 公司开源,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。
每个服务向 Zipkin 报告计时数据,例如用户每次请求服务的处理时间等,可方便的监测系统中存在的瓶颈。
Zipkin 会根据调用关系通过 Zipkin UI 生成依赖关系图。
Spring Cloud Sleuth 配合 Zipkin,将信息发送到 Zipkin,利用 Zipkin 的存储来存储信息,同时可以利用 Zipkin UI 来展示数据。Spring Cloud Sleuth 与需要进行供链路追踪的系统进行绑定。Spring Cloud 提供了spring-cloud-sleuth-zipkin 来方便集成 zipkin (指的是Zipkin Client,而不是Zipkin服务器),该 jar 包可以通过 spring-cloud-starter-zipkin 依赖来引入。
在整个结构中,我理解有这么几种角色:
这里首先要说一下,本文中涉及到的所有系统,依赖的软件版本如下:
Spring Boot 2.0 之前 Zipkin Server 是需要我们自己创建一个对应的 project 的。而 Spring Boot 2.0 之后,Zipkin 已不再推荐自定义 Zipkin Server 了,官方推荐了以下2种方式来部署 Zipkin Server:
在前言中已经提到,我的所有服务是通过 k8s 进行部署的,所以,Zipkin Server 也不例外。k8s 环境如何搭建不是本文的重点,所以这里就不进行介绍了,直接说一下 Zipkin Server 所涉及的2个 YAML 文件:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: annoroad-zipkin
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: annoroad-zipkin
template:
metadata:
labels:
app: annoroad-zipkin
spec:
terminationGracePeriodSeconds: 60
containers:
- name: annoroad-zipkin
env:
- name: DEPLOY_TAG
value: tag5
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE # 传入当前命名空间
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: SERVICE_NAME # 因为pod 通过域名互相访问,需要使用headless服务名称
value: annoroad-zipkin-service
- name: STORAGE_TYPE
value: mysql
- name: MYSQL_HOST
value: rm-1azzwo8172t6v014mm.mysql.rds.aliyuncs.com
- name: MYSQL_USER
value: user
- name: MYSQL_PASS
value: 123321
- name: MYSQL_DB
value: annoroad_zipkin_database
- name: COLLECTOR_PORT
value: '10400'
- name: QUERY_PORT
value: '10401'
image: registry-vpc.cn-beijing.aliyuncs.com/annoroad-cloud/annoroad-zipkin:latest
imagePullPolicy: Always #每次都重新拉取镜像
readinessProbe:
httpGet:
path: /health
port: 10401
initialDelaySeconds: 30
timeoutSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 10401
initialDelaySeconds: 60
timeoutSeconds: 10
ports:
- name: http
containerPort: 10400
这里提到的 registry-vpc.cn-beijing.aliyuncs.com/annoroad-cloud/annoroad-zipkin:latest 镜像,其实就是 openzipkin/zipkin 镜像,为了公司内部统一镜像名称我将 openzipkin/zipkin 打成 tag(registry-vpc.cn-beijing.aliyuncs.com/annoroad-cloud/annoroad-zipkin ),过程如下:
[[email protected] /]# docker pull openzipkin/zipkin
[[email protected] /]# docker tag openzipkin/zipkin registry.cn-beijing.aliyuncs.com/annoroad-cloud/annoroad-zipkin
[[email protected] /]# docker push registry.cn-beijing.aliyuncs.com/annoroad-cloud/annoroad-zipkin
本文中 zipkin server 通过设置环境变量 STORAGE_TYPE:mysql 来指定存储类型(mysql),默认为缓存存储(STORAGE_TYPE:mem)。zipkin server 还可通过环境变量来获取 mysql 的相关信息,例如:MYSQL_HOST、MYSQL_USER、MYSQL_PASS 等等,所以我们可以根据真实环境来设置这些环境变量。我们还可以通过变量 STORAGE_TYPE 切换不同的存储策略。
这里还有注意两个PORT:
apiVersion: v1
kind: Service
metadata:
name: annoroad-zipkin-service
labels:
app: annoroad-zipkin-service
spec:
ports:
- name: 4collector
port: 10400
protocol: TCP
targetPort: 10400
- name: 4query
port: 10401
protocol: TCP
targetPort: 10401
selector:
app: annoroad-zipkin
type: LoadBalancer
YAML 文件已经准备就绪,下面就可以部署 Zipkin Server 了,执行以下命令:
[[email protected] /]# kubectl apply -f annoroad-zipkin-deployment.yaml -n test --record
[[email protected] /]# kubectl create -f annoroad-zipkin-service.yaml -n test
Zipkin Server 已经部署了,我们如何能看到UI界面呢?首选要获取 Zipkin UI 访问入口,如下:
[[email protected] /]# kubectl get svc -n test
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
annoroad-zipkin-service 252.16.10.32 23.6.80.234 10400:31351/TCP,10401:30040/TCP 1d
上边的 23.6.80.234 是一个公网地址,有了这个地址我们就可以访问 Zipkin UI 了。打开浏览器,在地址栏输入 http://23.6.80.234:10401,将会出现如下界面:
至此,恭喜你,Zipkin Server 已部署完成了!!!!!!!
这里还有一点需要说明的是,上图中的服务名 annoroad-alpha 对应的是 annoroad-alpha 项目中 application.xml 文件中的 spring.application.name,如下图:
如果未指定该值,则该 project(annoroad-alpha) 在 zipkin 中的服务名为 default。
这里我以 annoroad-alpha 项目为例,步骤如下:
</dependencies>
<!-- zipkin 分布式请求跟踪监控 begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<!-- zipkin 分布式请求跟踪监控 end -->
</dependencies>
spring:
# 调用链 Sleuth + ZipKin
sleuth:
sampler:
# 采用比例,默认 0.1 全部采样 1.0
probability: 1.0
zipkin:
# 指定了 Zipkin 服务器的地址
base-url: http://annoroad-zipkin-service:10401/
这里的 annoroad-zipkin-service 对应了 k8s 环境中 name 为 annoroad-zipkin-service 的Service,也就是 annoroad-zipkin-service.yaml 定义的 Service。
annoroad-alpha 是如何将请求信息推送给 Zipkin Server 的呢?Zipkin 提供了很多种方式来实现。
本文采用的 http 的方式,也就 annoroad-alpha 通过请求 base-url 将请求 annoroad-alpha 的信息推送给 Zipkin Server。
这里再着重说一下初次配置 base-url 的几点疑惑:
2019-09-27 14:27:37.863[INFO ]com.netflix.loadbalancer.BaseLoadBalancer: 197-Client: localhost instantiated a LoadBalancer: DynamicServerListLoadBalancer:{
NFLoadBalancer:name=localhost,current list of Servers=[],Load balancer stats=Zone stats: {
},Server stats: []}ServerList:null
2019-09-27 14:27:37.871[INFO ]com.netflix.loadbalancer.DynamicServerListLoadBalancer: 222-Using serverListUpdater PollingServerListUpdater
2019-09-27 14:27:37.874[INFO ]com.netflix.loadbalancer.DynamicServerListLoadBalancer: 150-DynamicServerListLoadBalancer for client localhost initialized: DynamicServerListLoadBalancer:{
NFLoadBalancer:name=localhost,current list of Servers=[],Load balancer stats=Zone stats: {
},Server stats: []}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@5161aaf1
这里说的「服务调用者」就是 Postman,通过 Postman 请求 annoroad-alpha 服务,annoroad-alpha 再通过请求 base-url 将请求信息推送给 Zipkin Server,最终效果如下:
这里拿一个实际的调用场景来讲一下 Zipkin UI,调用关系如下:
如上图,整个调用链是 postman -> annoroad-openapi -> annoroad-alpha -> annoroad-beta,这里 的 annoroad-alpha、annoroad-beta 增加了对 spring-cloud-starter-zipkin 的依赖,也就是说对着两个服务进行了调用链路跟踪。
打开 Zipkin UI,我们可以看到如下界面:
这里红框中的部分称为“Trace”,TA 是一系列“Span”组成的一个树状结构。我们点开 TA,将会看到如下界面:
这里 annoroad-alpha 为根 Span,此 Span 中 span id 和 trace id 值相同,两个子 Span 都是 annoroad-beta,一个是请求 /annoroad-beta/hello,另外一个是请求 /annoroad-beta/bizexp。Span 是基本的工作单元,TA 包括一个64位的唯一ID,一个64位 trace 码,描述信息,时间戳事件,key-value ,如下图:
再跑爬虫程序的时候突然遇到了如下报错:org.apache.http.ConnectionClosedException: Premature end of chunk coded message body: closing chunk expected... at org.apache.http.impl.io.ChunkedInputStream.getChunkSize(C...
华为1.static有什么用途?(请至少说明两种) 1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。 3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块
1、write()函数定义:ssize_t write (int fd, const void * buf, size_t count); 函数说明:write()会把参数buf所指的内存写入count个字节到参数放到所指的文件内。返回值:如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。 附加说明:(1)write()...
转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 因为在之前的项目中,xml和json数据格式都有使用过,所以对json格式的简单、高效的特点印象深刻。如果使用json语言进行开发,强烈推荐使用json数据格式! JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析
Android基础入门教程——1.5.1 Git使用教程之本地仓库的基本操作标签: Android基础入门教程Git是什么? 一个分布式版本控制系统,和SVN类似,但远比SVN强大的一个版本控制系统 ①Git可以方便的在本地进行版本管理,如同你本地有一个版本管理服务器一样 我们可以选择在合适的时间将本地版本推送到统一的版本管理服务器 ②Git每次会提取整个代码仓库的完整镜像,相
WebSettings webSettings = view.getSettings(); webSettings.setJavaScriptEnabled(true); //view.clearCache(true); //view.clearHistory(); // User settings webSettings.setJavaScriptEn
此笔记本(notebook)使用评论文本将影评分为积极(positive)或消极(nagetive)两类。这是一个二元(binary)或者二分类问题,一种重要且应用广泛的机器学习问题。本教程演示了使用 Tensorflow Hub 和 Keras 进行迁移学习的基本应用。我们将使用来源于网络电影数据库(Internet Movie Database)的 IMDB 数据集(IMDB datase...
项目介绍ws: tail -f 查看服务器日志功能使用方式spring boot 项目直接 java -jar LogView.jar 启动即可,没用数据库!右侧为服务器当前的路径的文件,文件夹可以点击!想看哪个日志,结合上面的路径放入待查看Input查看。 项目分为"宿主机服务器"和"远程服务器" 两种查看方式,只支持linux tail -f *.log 查看日志使用http://127.0.0.1:7003/logView/...
错误信息如下[WARNING] Error injecting: org.apache.maven.plugin.surefire.SurefirePluginjava.lang.TypeNotPresentException: Type org.apache.maven.plugin.surefire.SurefirePlugin not present at org.eclip...
系统时间,硬件时间,UTC时间,本地时间,查看、修改系统时间和硬件时间的方法,计算系统时间的应用程序。
情景在爬取非英文网站的页面时, 如果发现获取后的网页字符串无法正常显示, 出现乱码. 通常都是因为解码所使用的编码不是网页原来所使用的编码. 需要查询网页本身的编码.查询网页编码方法一:1. 打开浏览器开发者工具, 切换到console工具.2. 在控制台输入 document.chardet 即可显示出网页的编码格式.方法二:使用python获取网页编码格式.import r...
有关命令: 进入zookeeperclient[[email protected] mq]# cd zookeeper/bin[[email protected] bin]# lsREADME.txt zkCleanup.sh zkCli.cmd zkCli.sh zkEnv.cmd zkEnv.sh zkServer.cmd zkServer.sh[[email protected]...