文字内容
1. 鹰眼下的淘宝 分布式调用跟踪系统介绍 淘宝网 司徒放 jifeng@taobao.com
2. 大纲 鹰眼是什么 鹰眼的使用场景 鹰眼的实现 2
3. 现状 • 日趋复杂的分布式系统 – 服务框架 – 消息中间件 – 数据层 – 分布式缓存 – 分布式存储 – …… 3
4. 现状 Web网页 无线客户 TOP API 请求 端请求 请求 应用A 应用B HSF 应用C HSF 应用F TDDL 消息服务器 收消息 应用D HSF Tair 分布式 缓存 收消息 应用E HSF HSF 应用G TDDL DB 收消息 HSF HSF 发消息 应用H Tair Search 搜索 4
5. 如何理清这些后端调用关系? 5
6. 举个例子 • 设想高速收费站将车辆通行信息记录成日志 [2013-05-01 12:23:34] 鲁A123BC,平度2,S16,济南,¥12 [2013-05-01 12:23:40] 鲁A987DE,平度2,S16,淄博,¥10 [2013-05-01 12:43:15] 鲁A123BC,潍坊1,G20,济南,¥18 [2013-05-01 13:38:29] 鲁A123BC,青州西1,G20,济南,¥10 [2013-05-01 13:38:30] 鲁A567AB,青州西2,G20,潍坊,¥10 [2013-05-01 14:39:27] 鲁A123BC,淄博3,G20,淄博,¥15 [2013-05-01 16:42:58] 鲁A123BC,济南3,G20,济南,¥25 …… * 上述日志内容仅作举例示意说明用,纯属虚构,请勿当真 6
8. 举个例子 • 可以得到 – 收费站的每日总车流量和流量趋势 – 鲁A123BC在五一期间的行驶路线和费用 – G20上的车速、路况 – G20流量过高时,车的来源分布 8
9. 举个例子 • 高速上行驶的车辆:前端请求 • 高速上的收费站:处理请求的应用 • 由中间件去记录请求的网络调用情况 • 关键点:关联日志中记录的车牌号 9
10. 简介 • 鹰眼(EagleEye) – 基于日志的分布式调用跟踪系统 – 脱胎于 Google Dapper 论文 – 核心:调用链,每次请求都生成 一个全局唯一的ID(TraceId), 通过它将不同系统的“孤立的” 日志串在一起,重组成调用链, 使其价值达到 1+1 > 2 的效果 * 《三国杀》铁索连环卡牌版权归游卡桌游 (Yoka Games) 所有 10
11. 简介 • 目前状况 – 日均调用链超过 600 亿,来自 500 多个前端应用,500 多个后端 应用,还有上百个数据库、存储,调用日志超过千亿行 • 覆盖了淘宝主要使用的网络通讯中间件 ü ü ü ü ü ü ü ü 前端请求接入:Tengine(nginx) / tbsession 服务调用框架:HSF 消息通讯:Notify 数据库:TDDL 分布式缓存:Tair 分布式存储:TFS 特定功能的客户端,如搜索、支付等 其他中间件,如:HttpClient…… 11
12. 大纲 鹰眼是什么 鹰眼的使用场景 鹰眼的实现 12
13. 调用链跟踪 13
14. 调用链跟踪 • 排查前端某页面响应很慢或报错的原因 – 查看这个页面的调用链,定位瓶颈点、故障点 – 应用在日志中打印当前上下文的调用链 ID,关联异常 堆栈日志 – 关联系统资源数据,如 load、内存、JVM 状况 • 实时跟踪当前客户端的所有请求的调用链 – 了解每个请求背后的应用间交互过程 14
15. 调用路径分析 15
16. 调用路径分析 • 应用的关键路径 – 应用被调用得最多的入口、服务是哪些 – 突出关键:热点、耗时瓶颈、易故障点、变化点 – 主要用于容量评估、性能优化 • 验证调用路径是否符合预期 – 衡量网络调用的均衡性 – 调用在单元内的路由正确性 • 实时分析前端入口的容量走势 – 大促链路监控和高峰预警 16
17. 调用去向分析 • 依赖关系 – 应用直接或间接依赖了哪些服务 – 各个层次上的依赖的调用指标和错误指标 – 找出调用链路上的不正常的、多余的依赖调用 • 异常分析 – 依赖会产生哪些异常 – 异常时会造成什么影响 – 把主流程的强依赖转化为弱依赖 17
18. 调用来源分析 18
19. 调用来源分析 19
20. 调用来源分析 20
21. 透明的分布式数据传输 eagleeyex_sellerId 应用A HSF clear(“sellerId”) 应用B get(“sellerId”)= null HSF 应用F get(“sellerId”) =8d6402… get(“orderId”)= 22f9b7… 发消息 get(“sellerId”) =8d6402… 消息服务器 投递消息 投递消息 应用D 应用E HSF 应用G get(“sellerId”) =8d6402… put(“orderId”, 22f9b7…) 21
22. 透明的分布式数据传输 • 鹰眼自身需要传递调用上下文 • 在调用链上透明传输业务数据 – 子帐号业务、风控业务 • 把前端网关才有的数据传到后端某个服务中 – 项目环境隔离 • 传递线下环境的项目标识,用于路由判断 – 依赖检测系统 • 在 URL 上设置一些调试指令 22
23. 与业务日志结合 • 将业务信息与链路结合 – 交易的创建、支付相关数据 – 卖家、小二的操作记录 • 为业务提供日志“后处理”服务 ü 直接存储到 HDFS,建立 Hive 表 ü 把每条日志做消息发布,供业务订阅 ü 解析日志,生成多维度的实时统计报表 ü 为日志的指定字段建索引,提供模糊搜索 23
24. 小结 • 调用链跟踪 • 调用路径分析 • 调用去向分析 • 调用来源分析 • 透明的分布式数据传输 • 与业务日志结合 24
25. 大纲 鹰眼是什么 鹰眼的使用场景 鹰眼的实现 25
26. 整体架构 应用集群 带鹰眼埋点 的中间件 写入 日志文件 读取 日志收集agent Hadoop 集群 实时收取日志 实时收取日志 鹰眼 Storm 集群 实时日志 全量日志 MapReduce HDFS 计算结果 读取原始日志 与分析结果 数据输出与 展现 HBase 实时 数据 写入统 计数据 鹰眼服务器 26
27. 整体实现介绍 1. 埋点和生成日志 2. 抓取和存储日志 3. 汇总和重组调用链 4. 分析和统计调用链 27
28. 整体实现介绍 1. 埋点和生成日志 2. 抓取和存储日志 3. 汇总和重组调用链 4. 分析和统计调用链 28
29. 埋点和生成日志 • 如何埋点 – 通过中间件创建调用上下文,生成埋点 – 调用上下文放在本地 ThreadLocal,对应用透明 – 调用上下文随着中间件的网络调用在系统间传递 • “前端型” :生成 TraceId,创建调用链,结束调用链 • “单向型” :仅客户端,生成日志(服务端未埋点) • “双向型” :客户端+服务端,传输上下文,生成日志 29
30. 埋点和生成日志 前端应用 后端应用1 请求 start Trace clientSend clientRecv 服务调用 服务响应 后端应用2 serverRecv serverSend serverRecv 服务调用 clientSend clientRecv clientSend clientRecv 响应 endTrace 服务响应 数据库 clientRecv clientSend 数据访问 图示 数据访问 serverSend 创建 上下文 生成 日志 30
31. 埋点和生成日志 • 埋了些什么数据 – TraceId、RpcId、开始时间、调用类型、对端 IP – 耗时:多个阶段的处理耗时 – 传输量:请求大小/响应大小 – 处理结果(ResultCode) – 与中间件相关的数据 31
32. 埋点和生成日志 • 调用上下文:TraceId – 关联一次请求相关的日志,需要保证全局唯一,在各 个系统间传递 – 是否需要业务语义? • IP 地址:用于识别前端应用和来源机器 • 创建时间:在存储时用于分区 • 顺序数:用于链路采样 • 标志位:可选,用于调试和标记 • 进程号:可选,单机多进程的应用使用 32
33. 埋点和生成日志 • 调用上下文:RpcId – 标识日志埋点顺序和嵌套关系,也在各个系统间传递 • 调用关系 – 同步 / 异步 / 一对多调用 • 用什么方式实现 RpcId 适合表示上述关系? – 顺序编号:1、2、3… – 多级编号:0、0.1、0.2、0.2.1… 33
34. 埋点和生成日志 Web网页 无线客户 TOP API 请求 端请求 请求 应用A 应用B 0.1.1 应用C 0.1.2 应用F 0.1.1.1 DB 0.2.2 应用D 0.3.1 0.2.2.1 应用G 0.3.1.1 消息服务器 0.2.1 0.3 0.1 0.2 0.1.2.1 Tair 0.2.3 应用E 0.2.2.2 0.2.3.1 应用H 0.2.3.1.1 0.2.3.1.2 搜索 34
35. 埋点和生成日志 • 埋点遇到的问题 – 异步调用 • 业务使用异步线程处理逻辑时会丢失上下文 • 异步 IO:Send 和 Recv 不在同一线程 • 异步 servlet:业务逻辑在不同线程中切换执行 – 一对多的调用方式 – 非前端请求触发的调用链 35
36. 埋点和生成日志 • 写日志面临的挑战 – 尽可能减少对业务线程的影响,降低系统消耗 – 每个网络请求至少1行日志,QPS 越高日志产生越快 • 解决方案:自己实现日志输出 – – – – – – 用异步线程写日志 开关控制以及采样输出 对长字符串做编码 日志 IOPS 限制,输出缓存,按秒刷新 日志文件按大小滚动,自动清理 统一字符编码,统一时区 36
37. 整体实现介绍 1. 埋点和生成日志 2. 抓取和存储日志 3. 汇总和重组调用链 4. 分析和统计调用链 37
38. 抓取和存储日志 • 日志的生成方式决定了需要实时抓取 • 离线 + 实时相结合的方案存储调用链 – 全量业务日志、线下日志:实时存 HBase – 线上调用日志:全量存 HDFS,按需存 HBase – TradeOff:离线的代价 – “按需抓取” 38
39. 抓取和存储日志 • HDFS 存储方案 – 存全量数据 10TB+ 按 TraceId 的时间戳定位 时间段目录 按 TraceId 的哈希值定位 – 顺序块存储 块索引0 – 多级索引 – 压缩率 1:10 – 随机单链查询 200~500ms 块索引1 … 块索引n 索引二 分查找 块 内 顺 序 查 找 调用链 记录块 (压缩) 调用链 记录块 (压缩) … 调用链 记录块 (压缩) … 1 n Sequence File 0 39
40. 整体实现介绍 1. 埋点和生成日志 2. 抓取和存储日志 3. 汇总和重组调用链 4. 分析和统计调用链 40
41. 汇总和重组调用链 • 按 TraceId 汇总日志 – 一条调用链的日志散落在调用经过的各个服务器上 – 因此,这是链路日志分析必不可少的一步 • 汇总方案 – 基于HBase:用 TraceId 做 rowkey,天然汇总 – 基于HDFS :需要 MapReduce 做汇总 – 汇总真的必不可少吗? 41
42. 汇总和重组调用链 • 按 RpcId 重组调用链 – 重组的问题 • 日志数据残缺 • 埋点信息本身有错误 – 解决办法 • 冗余补全、利用父子关系推导 • 使用“占位符”表示不完整的信息 • 基于历史来修正错误数据 42
43. 整体实现介绍 1. 埋点和生成日志 2. 抓取和存储日志 3. 汇总和重组调用链 4. 分析和统计调用链 43
44. 分析和统计调用链 • 对同一个入口的调用链做统计 • 标准化入口 URL – URL 中的不规范内容和可选内容,动态参数 – 应用有多个域名,或自定义域名 – 静态化 URL 中的 RESTFUL 变量 • http://shop123456.taobao.com/view_page-9876abc.htm • 解决方案:按应用、域名归类的正则表达式替换 44
45. 分析和统计调用链 • 统计链路上每次调用的上下文 – 对 DAG 上的每个节点做深度优先遍历 – 为链路上的每个节点进行编码 A B 统计生成的 rowkey 的示意: C D E F G H + A + A B + A B E + A B E G + A B F + A C + A C E + A C E H + A D + A D F + A D F H + B …… 45
46. 鹰眼的实现小结 1. 埋点和生成日志 – 基于中间件、TraceId / RpcId、异步写、采样 2. 抓取和存储日志 – 实时抓日志,实时+离线结合的存储 3. 汇总和重组调用链 – 按 TraceId 汇总、按 RpcId 重组 4. 分析和统计调用链 – 入口标准化、带上下文的调用统计 46
47. Q&A 谢谢! 淘宝网 司徒放 jifeng@taobao.com