1.Pinpoint简介
Pinpoint 是用 Java 编写的 APM(应用性能管理)工具,用于大规模分布式系统。在 Dapper(dapper.docx) 之后,Pinpoint 提供了一个解决方案,以帮助分析系统的总体结构以及分布式应用程序的组件之间是如何进行数据互联的。
它采用java agent 的方式对 jvm应用的无侵入的改造。同时对性能的影响非常小(只增加约3%资源利用率)。 支持以下模块。
tomcate 6/7/8,Jetty 9
Spring, Spring Boot
Apache Http Client 3.x/4.x,JDK HttpConnector,GoogleHttpClinet,OkHttpClient,NingAsyncHttpClient
Thrift Cliet,Thirft Service
MySql,Oracle,MSSQL,CUBRID,DBCP,POSTGRESQL
Arcus,Memcached,Redis
IBATIS,MyBatis
Gson,Jackson,Json Lib
Log4j,Logback
2.Pinpoint架构
以下是pinpoint的架构图,如图所示 Profiled Applications 是 对应的注入pinpoint agent的jvm容器。 其他分为3种消息:1).tcp 9994端口的 agent配置信息、Api信息、String信息、Exception信息。 2).udp 9995 端口 发送JVM内存使用情况,线程相关信息,每隔30秒一个包,每个包为6条信息。 3).Udp 9996 端口 这个端口数据是最关键也是数据最多的,是全链路Trace 报文。
那么以上所有的消息都是通过Tcp/udp,Thrift协议发送到云端的Collector,collector收集数据并保存到hbase。 同时pinpoint web UI 读取Hbase数据展示链路等数据。
3.问题探讨
提供pinpoint的架构和内在逻辑的分析,我们发现pinpoint agent 是其精华所在。但是他包含以下问题
1). agent数据直接发送到 固定的collector地址 没有服务发现,collector挂了数据就无法收到。
2). agent数据是原始数据,直接发送到Collector未进行压缩,未进行缓存
3). Collector在 agent Jvm 高并发环境下,只能最多进行1对3的收集,对于大规模 应用服务器情况下Collector显得非常无能。
- 改造
如下图所示,我们增加 Mecury 的代理层。 它的作用有
1).提供Etcd 服务发现获取Load最低的Collector
2).对Agent发送的数据进行预处理:数据解析,数据压缩,定时发送到Collector。其中数据压缩可以用Snappy。
3).采用Golang 实现数据的收集,同时mecury 还充当获取服务器 监控数据发送到Collector
4). Mecury执行部分Java Shell指令对Jvm进行外部监控
当然Collector 我们也是采用golang进行重写,自此 Collector(golang 实现) 压力下降上千倍,在生产环境下可以支持1对300+agent的服务器。
- 总结
以上对Pinpoint agent 和pinpoint Collector的 改造方案。我所在公司已经改造完成,并在生产环境大面积使用。
当然我们还有很多事情可以做,比对如何高效的实时报警,如何存储监控数据(hbase是否还能满足需求),如何做跨语言的监控,监控Ui如何展示全面实时。
- collector 的数据处理
上图所示,数据经过压缩达到Collector。
1).此时我们队监控数据进行数据清洗,数据合并的工作,注意这里无需做数据的详细处理,讲数据打成块。这里的块指的是讲各个mecury数据合并再次压缩成大块,这点极其重要。
2).我们将数据提供消息队列(可以是nats,nsq,kafka等)数据分发到实时计算单元,并保持元数据到hbase。
3).实时计算对元数据提取有效数据,并根据报警策略将报警结果提供Email,短信发送到Owner。这里实时计算单元我们可以借助Spark,当然也可以直接简单实现。
4).离线计算以分钟为维度,进行数据计算链路结果,中间过程,入库到hbase和mysql
5).最后apmUi通过查询数据展示监控数据,报警策略,全链路展示。
总结
通过上面的架构,我们的改造的apm基本雏形已经成型。那么后续我们还有哪些需要思考。
1)、业务监控:基于业务Id实时查询和监控报警
2)、监控所以不同服务状态,通过监控指标服务升降级
3)、App端监控,Web监控,跨语言监控
7、如何构建javascript、golang agent
如图所示我们将pinpoint的协议进行改造,并生成go语言版本的agent
type TSpan struct {
AgentId string thrift:"agentId,1" json:"agentId"
ApplicationName string thrift:"applicationName,2" json:"applicationName"
AgentStartTime int64 thrift:"agentStartTime,3" json:"agentStartTime"
TransactionId []byte thrift:"transactionId,4" json:"transactionId"
// unused fields # 5 to 6
SpanId int64 thrift:"spanId,7" json:"spanId"
ParentSpanId int64 thrift:"parentSpanId,8" json:"parentSpanId"
StartTime int64 thrift:"startTime,9" json:"startTime"
Elapsed int32 thrift:"elapsed,10" json:"elapsed"
Rpc *string thrift:"rpc,11" json:"rpc"
ServiceType int16 thrift:"serviceType,12" json:"serviceType"
EndPoint *string thrift:"endPoint,13" json:"endPoint"
RemoteAddr string thrift:"remoteAddr,14" json:"remoteAddr"
Annotations []TAnnotation thrift:"annotations,15" json:"annotations"
Flag int16 thrift:"flag,16" json:"flag"
Err int32 thrift:"err,17" json:"err"
SpanEventList []TSpanEvent thrift:"spanEventList,18" json:"spanEventList"
ParentApplicationName *string thrift:"parentApplicationName,19" json:"parentApplicationName"
ParentApplicationType *int16 thrift:"parentApplicationType,20" json:"parentApplicationType"
AcceptorHost *string thrift:"acceptorHost,21" json:"acceptorHost"
// unused fields # 22 to 24
ApiId *int32 thrift:"apiId,25" json:"apiId"
ExceptionInfo *TIntStringValue thrift:"exceptionInfo,26" json:"exceptionInfo"
// unused fields # 27 to 29
ApplicationServiceType *int16 thrift:"applicationServiceType,30" json:"applicationServiceType"
LoggingTransactionInfo *int8 thrift:"loggingTransactionInfo,31" json:"loggingTransactionInfo"
}
我们将Agent发送的数据发送到mecury,mecury再次进行数据解析,数据压缩,发送到collector。
javascript 我们将新增 GetWay网关层。我们见agent数据提供websocket发送到高性能GetWay层。GetWay将网页的监控数据链路数据错误信息,进行预处理,压缩发送到collector。自此将全链路数据打通,同时也收集了前端的性能数据。
总结
javascript/golang agent改造到此结束。不过后续还有很多问题需要处理:
1).如何处理离线数据,并能在web端实时高效的展示。
2).如何结合全链路监控和系统监控,做业务监控,服务监控
作者:逆月林
来源:CSDN
原文:https://blog.csdn.net/niyuelin1990/article/details/78058980
版权声明:本文为博主原创文章,转载请附上博文链接!
有疑问加站长微信联系(非本文作者)