热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

实现分布式追踪系统Jaeger从phpAPIGateway到gomicro微服务

分布式调用链跟踪系统,属于监控系统的一类。系统架构逐步演


分布式调用链跟踪系统,属于监控系统的一类。系统架构逐步演进时,后期形态往往是一个平台由很多不同的服务、组件构成,用户请求过来后,可能会经过其中多个服务。
不过,出问题时往往很难排查,如整个请求变慢、偶尔报错、不可用等,我们很难得知具体是由哪一个或哪些服务引起的,通常开发同学都会互相甩锅,最后不得不花大量时间人肉 tracing

Jaeger是Uber Technologies用GO语言开发的分布式跟踪系统,现已开源。它用于监视和排除基于微服务的分布式系统,包括:
分布式上下文传播
分布式事务监控
根本原因分析
服务依赖性分析
性能/延迟优化

架构图
两个核心概念
TraceId:
用于标识一次完整请求 trace,会从头到尾贯穿在各个服务中,通常在请求入口时生成。
SpanId:
用于标识某个调用跨度 span,一个 span 可以有多个 子span, 通常一个完整的 trace 由很多个 span 组成。

PHP使用并传递uber-trace-id到下一层链路中!在http请求时调用jaege注入请求,会生成唯一的uber-trace-id 与spanid,获取到这俩个id,组装数据Metadata ,通过grpc调用服务方法时把Metadata传递过去,而在go-micro中通过context.Context就可以获取到,如果需要服务之间继续调用,则继续传递context。这样就把一次完整的链路请求记录到Jaeger中。

基本流程

请求入口生成 trace

在方法(或服务)调用前,生成 span,记录时间

调用时,携带 TraceId SpanId (如,在 http header 或 grpc meta data 里)

调用完后关联到 trace

统一上报到 Jaeger存储。

代码示例

public function Login(Request $request)
{
$jaegerClien = new jaegerClien();
$jaegerClien->setSvcName();
$metadata = $jaegerClien->Hprose('admin/login'); //请求链路的metadata
$phone = $request->input('phone');
$password = $request->input('password');
$consul = new Consul("xyd.vip.srv");
$host = $consul->getHost();
$client = new Vipuser($host,[
'credentials' => \Grpc\ChannelCredentials::createInsecure(),
]);
$req = new vipuserReq();
$req->setMobile($phone);
$req->setPwd($password);
list($rsp, $status) = $client->Login($req,$metadata)->wait();
$code = $rsp->getCode();
$msg = $rsp->getMsg();
$data = $rsp->getData();
$token = $rsp->getToken();
if ($code == 200){
$user = json_decode($data);
$request->session()->put('token',$token);
$request->session()->put('user', $user);
$jaegerClien->setDisabled(); //关闭jaeger
return $this->_returnJosn($code,$user,$msg,0,$token);
}else{
return $this->_returnJosn($code,array(),$msg);
}
}

public function Hprose($operationName){
$this->jaegercfg = JaegerConfig::getInstance();
$tracer = $this->jaegercfg->initTracer($this->svcName, $this->jaegerUrl);
$spanContext = $tracer->extract(Formats\TEXT_MAP, $_SERVER);
$serverSpan = $tracer->startSpan($operationName, ['child_of' => $spanContext]);
$tracer->inject($serverSpan->getContext(), Formats\TEXT_MAP, $_SERVER);
//init server span end
$serverSpan->finish();
$this->jaegercfgFlush();
$spanContext = (array)$serverSpan->getContext();
$meta = new Metadata();
$meta->set('uber-trace-id', $_SERVER['UBER-TRACE-ID']);
$meta->set('X-B3-ParentSpanId', $spanContext['parentId']);
$meta->set('X-B3-SpanId', $spanContext['spanId']);
$meta->set('X-B3-Sampled', true);
return $this->getZipKinMetadata($meta);
}

func (a *User) Login(ctx context.Context, req *user.Request, rsp *user.Response) error {
mobile := req.Mobile
pwd := req.Pwd
code, msg, user := UserService.Login(mobile, pwd)
jsons := "{}"
token := ""
if user != nil {
jsonsby, _ := json.Marshal(user)
jsons = string(jsonsby)
token = UserService.MakeAccessToken(ctx, user.Id, user.Mobile)
}
response.UserReturnRes(code, msg, jsons, token, rsp)
return nil
}
//使用上下文传递 span
func (a *AuthClient) MakeAccessToken(ctx context.Context, userid int64, phone string) string {
info, err := a.client.MakeAccessToken(ctx, &authSvc.Request{
Userid: userid,
Phone: phone,
})
fmt.Println("info:", info)
fmt.Println("err:", err)
if err != nil {
return ""
}
//span.Finish()
return info.Token
}

实际效果图
在这里插入图片描述在这里插入图片描述
可以看到整个链路的耗时,点击进去可以看到每个span的详细信息

实践准备工作
安装Jaeger
docker安装测试版 所有数据都是存储到内存中 只能作为测试

docker run -d --name jaeger -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 14268:14268 -p 9411:9411 jaegertracing/all-in-one:latest

Docker部署jaeger并使用elasticsearch作为存储引擎

docker + collector安装

docker run -d --name jaeger-collector --restart=always --link elasticsearch -e SPAN_STORAGE_TYPE=elasticsearch -e ES_SERVER_URLS=http://172.26.155.215:9200 -e ES_USERNAME=elastic -p 14267:14267 -p 14268:14268 -p 9411:9411 jaegertracing/jaeger-collector
注意:
--link elasticsearch,代表docker 关联,该名字必须和你安装elasticsearch —name的名字相同
--SPAN_STORAGE_TYPE=elasticsearch 代表安装jaeger选择elasticsearch作为存储
-e ES_SERVER_URLS=http://elasticsearch:9200次条目代表你选择容器安装的elasticsearch的9200端口
-e ES_USERNAME elasticsearch的用户名:默认elastic,下同
-e ES_PASSWORD elasticsearch的密码 没有设置密码不用填

docker + query安装

docker run -d --name jaeger-query --restart=always --link elasticsearch -e SPAN_STORAGE_TYPE=elasticsearch -e ES_SERVER_URLS=http://172.26.155.215:9200 -p 16686:16686/tcp jaegertracing/jaeger-query
注意,ES_USERNAME、ES_PASSWORD这两个环境变量,当你的elasticsearch未设置账号密码时,你可以不填,也可以填上默认值,elasticsearch的默认ES_USERNAME=elastic,ES_PASSWORD=changeme
部署完成query之后,根据你暴露的端口号(-p 16686:16686/tcp),浏览器输入以下地址(将localhost换成你部署query的地址)
http://localhost:16686

docker + agent安装

docker run -d --name jaeger-agent --restart=always -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778/tcp jaegertracing/jaeger-agent --collector.host-port=172.26.155.215:14267


推荐阅读
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • 本文由编程笔记小编整理,主要介绍了使用Junit和黄瓜进行自动化测试中步骤缺失的问题。文章首先介绍了使用cucumber和Junit创建Runner类的代码,然后详细说明了黄瓜功能中的步骤和Steps类的实现。本文对于需要使用Junit和黄瓜进行自动化测试的开发者具有一定的参考价值。摘要长度:187字。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文介绍了使用postman进行接口测试的方法,以测试用户管理模块为例。首先需要下载并安装postman,然后创建基本的请求并填写用户名密码进行登录测试。接下来可以进行用户查询和新增的测试。在新增时,可以进行异常测试,包括用户名超长和输入特殊字符的情况。通过测试发现后台没有对参数长度和特殊字符进行检查和过滤。 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • iOS Swift中如何实现自动登录?
    本文介绍了在iOS Swift中如何实现自动登录的方法,包括使用故事板、SWRevealViewController等技术,以及解决用户注销后重新登录自动跳转到主页的问题。 ... [详细]
author-avatar
巴香香
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有