Monthly Archives: May 2016

使用 Zipkin 和 Brave 实现分布式系统追踪(基础篇)

Zipkin

一、Zipkin

1.1、简介

Zipkin 是一款开源的分布式实时数据追踪系统(Distributed Tracking System),基于 Google Dapper 的论文设计而来,由 Twitter 公司开发贡献。其主要功能是聚集来自各个异构系统的实时监控数据,用来追踪微服务架构下的系统延时问题。

应用系统需要进行装备(instrument)以向 Zipkin 报告数据。Zipkin 的用户界面可以呈现一幅关联图表,以显示有多少被追踪的请求通过了每一层应用。

瀑布图

Zipkin 以 Trace 结构表示对一次请求的追踪,又把每个 Trace 拆分为若干个有依赖关系的 Span。在微服务架构中,一次用户请求可能会由后台若干个服务负责处理,那么每个处理请求的服务就可以理解为一个 Span(可以包括 API 服务,缓存服务,数据库服务以及报表服务等)。当然这个服务也可能继续请求其他的服务,因此 Span 是一个树形结构,以体现服务之间的调用关系。

Zipkin 的用户界面除了可以查看 Span 的依赖关系之外,还以瀑布图的形式显示了每个 Span 的耗时情况,可以一目了然的看到各个服务的性能状况。打开每个 Span,还有更详细的数据以键值对的形式呈现,而且这些数据可以在装备应用的时候自行添加。

Span 详细信息

从图中可以看出如下的调用关系:整个调用链中有两个微服务 service1 和 service2,在 10ms(相对时间点)的时候,service1 作为客户端向 service2 发送了一个请求(Client Send),之后 service2 服务于 19ms 的时候收到请求(Server Receive),并用了 12ms 的时间来处理,并于 31ms 时刻将数据返回(Server Send),最后 service1 服务于 1ms 以后接收到此数据(Client Receive),因此整个过程共耗时 22ms。图中还给出了 service1 访问 service2 服务前后 Http Client 连接池的状态信息。

1.2、架构

Zipkin 架构

如图所示,Zipkin 主要由四部分构成:收集器、数据存储、查询以及 Web 界面。Zipkin 的收集器负责将各系统报告过来的追踪数据进行接收;而数据存储默认使用 Cassandra,也可以替换为 MySQL;查询服务用来向其他服务提供数据查询的能力,而 Web 服务是官方默认提供的一个图形用户界面。

而各个异构的系统服务向 Zipkin 报告数据的架构如下图。

服务向 Zipkin 报告数据

1.3、运行

使用 Docker 运行 Zipkin 最为简单,其过程如下:

这样启动,默认会使用 Cassandra 数据库,如果想改用 MySQL,可以换做以下命令启动:

启动成功以后,可以通过 http://:8080 来访问。具体获取 IP 地址的方法请参阅 Docker 的相关文档。

二、Brave

2.1、简介

Brave 是用来装备 Java 程序的类库,提供了面向 Standard Servlet、Spring MVC、Http Client、JAX RS、Jersey、Resteasy 和 MySQL 等接口的装备能力,可以通过编写简单的配置和代码,让基于这些框架构建的应用可以向 Zipkin 报告数据。同时 Brave 也提供了非常简单且标准化的接口,在以上封装无法满足要求的时候可以方便扩展与定制。

2.2、初始化

Brave 的初始化就是要构建 Brave 类的实例,该库提供了 Builder 类用来完成这件事情。

注:下文中约定,大写的 Brave 指该 Java 类库,而 Brave 类指 com.github.kristofa.brave.Brave 类型,而小写的 brave 指该类型的实例。

其中的 serviceName 是当前服务的名称,这个名称会出现在所有跟该服务有关的 Span 中。默认情况下,Brave 不会将收集到的监控数据发送给 Zipkin 服务器,而是会以日志的形式打印到控制台。如果需要将数据发送给服务器,就需要引入 HttpSpanCollector 类。当前版本(3.8.0)将这个类命名为 Collector,这个概念容易跟 Zipkin 自身的 Collector 相混淆,因此在 Issue #173 中官方建议将其更名为 Reporter,也就是说这个类是用来向 Zipkin 的 Collector 报告数据的。

Zipkin Reporter

使用 HttpSpanCollector 的方法如下:

使用 HttpSpanCollector.create 方法可以创建该类的一个对象,第一个参数就是 Zipkin 服务的地址(默认部署时的端口为 9411)。

如果使用 Spring 的话,为了方便扩展,建议添加一个名为 ZipkinBraveFactoryBean 的类,其内容大致如下:

然后只需要在 application-context.xml 配置文件中使用该 FactoryBean 就可以了:

2.3、装备标准的 Servlet 应用

Brave 提供了 brave-web-servlet-filter 模块,可以为标准的 Servlet 应用添加向 Zipkin 服务器报告数据的能力,需要做的就是在 web.xml 文件增加一个 BraveServletFilter。

不过这个 Filter 在初始化的时候需要传入几个参数,这些参数可以通过 brave 对象的对应方法获得,但是注入这些构造参数,最简单的办法还是使用 Spring 提供的 DelegatingFilterProxy。

在 web.xml 中添加如下内容(最好配置为第一个 Filter,以便从请求最开始就记录数据):

然后在配置文件中添加以下内容(创建 brave Bean 的有关代码请参考上文):

最后一个类 com.github.kristofa.brave.http.DefaultSpanNameProvider 存在于 brave-http 模块中。当使用 Maven 或 Gradle 来管理项目的话,brave-http 会随着 brave-web-servlet-filter 的引入被自动关联进来。

一切无误的话就可以启动服务。如果给定了 zipkinHost 参数,数据就会被发送到指定的 Zipkin 服务器上,然后可以在其 Web 界面上看到相关内容;否则会有类似如下的信息打印到系统控制台(做了格式美化):

2.3、装备 Spring MVC 应用

Brave 自带了 brave-spring-web-servlet-interceptor 模块,因此装备 Spring MVC 项目变得非常容易,只需要在配置文件中添加一些 interceptor 就好了:

2.4、装备 MySQL 服务

brave-mysql 模块在 JDBC 驱动层面添加了一些拦截器,可以对 MySQL 的查询进行监控。在使用之前也需要通过 Spring 进行一下配置。

该配置的目的是要给 MySQLStatementInterceptorManagementBean 类注入一个 ClientTracer 实例,这个实例会在后来的 MySQL JDBC 驱动的拦截器中被使用。初始化完成以后只需要在连接字符串中添加如下参数就可以了:

其中的 zipkinServiceName 用来指定该 MySQL 服务的名称,如果省略的话,会默认以 mysql-${databaseName} 的形式来呈现。

这里需要特别说明一点,因为 MySQL 服务是跟 Java 服务分离的,因此上文初始化 brave 对象时提供的服务名称,并不适用于 MySQL 服务,所以才需要在这里另外指定。

MySQL 服务的监控数据

可以看出,添加了 statement interceptor 之后,可以看到 service2 请求 MySQL 查询的起止时间,以及执行的 SQL 语句等信息。

三、总结

本文主要介绍了 Zipkin 服务和其 Java 库 Brave 的一些基本概念及原理,并且针对 Brave 开箱提供的一些装备组件进行了详细的使用说明。在后面进阶篇的文章中,会对如何扩展 Brave 以实现自定义监控信息的内容进行介绍,敬请期待!

企业级 IM 的差异化发展之路

钉钉与微信

钉钉 X 微信

2016 年 4 月 18 日,微信团队发布了继微信和微信支付后的第三个重量级产品企业微信,正式吹响了与阿里钉钉交锋的号角,并且还扬言:要像干掉来往一样的干掉钉钉。一时间,企业级 IM 这个既陌生又熟悉的产品,成为了互联网界热议的话题。

那么企业级 IM 到底是什么?它又跟移动办公产品有什么区别?当钉钉和企业微信展开厮杀的时候,企业级 IM 的差异化发展之路到底在何方?

既然是叫“企业级 IM”,那么不难看出其产品特性的两个着眼点:企业应用和即时通讯。企业应用一方面是应用于企业内部,另一方面也在于能够整合企业内部的各种管理流程与制度。小了来说是各种轻量级应用,大了来说可以汇聚成管理信息系统。而即时通讯就更不言而喻了,曾经当 QQ 几乎成为国内即时通讯代名词的时候,有多少企业早已不由自主的经由 QQ 群完成了许多内部的沟通事宜,可见企业还是非常需要这样一类产品的。无奈的是,无论 QQ 还是微信,其社交成分要远远大于协同办公的成分,无法成为组织内部沟通协作的首选。

当来往完败给微信的时候,阿里仍不死心的想要切入即时通讯这个腾讯最核心的业务领域,于是就此诞生了钉钉。马云更是豪赌 10 亿,另辟蹊径的从企业内用户寻找突破口,让钉钉迅速站稳了脚跟。腹地被偷袭的腾讯自然不会善罢甘休,企业级 IM 市场顿时风生水起、剑拔弩张。企业级 IM 毕竟不是什么新鲜玩意,国外的 Slack 和 HipChat 早已是行业中的佼佼者,但显然钉钉与企业微信跟 Slack 和 HipChat 看上去并不怎么相似,不只是 Copy to China 这么简单。其两者都在通讯功能的基础上增加了类似签到、审批、任务管理和文件共享等企业内常用的功能,而且还能够开放给第三方合作伙伴进行二次开发,俨然一个企业管理流程互联网化的开放平台,让很多中小企业似乎找到了协同办公的感觉,从而忘记了这些东西原本在移动办公领域已经是必备的功能了。

然而企业内部的系统,必然不同于互联网化的系统。一个组织并不会因为“系出名门”、“免费”或“更加易用”等特性就放弃正在使用的古老系统;而且企业内部的管理流程也远非轻量级应用所能覆盖,尤其是在以流程驱动管理的企业内部,动辄十几步甚至几十步的流程都大有所在,而且流程信息量也绝非任务管理这等规模的应用所能比拟的;最后无论钉钉抑或企业微信,都还仅仅是将即时通讯和轻量级应用做了一个简单的叠加,流程数据还存在流程中,而碎片化的聊天信息依旧隐含着大量的珍贵知识,企业级 IM 是否应该走得更深入一些。

文章 An Inside Look at a Flat Organization That Serves Millions 的作者 Nate Lee 在介绍如何管理一个扁平化组织的时候,提出了一个命题: Assume that new hires won’t be able to talk to any of their co-workers for 48 hours. This is of course never the case, but if it was, they should have enough information at their fingertips to do their job. They should be able to read up on any problem or feature or question they have.(假设新来的员工在 48 小时内不能和其他同事讲话。在这种假定下,他们应该动动手指就能得到足够的信息去开展工作。如果在工作中遇到了问题,他们也应该能够通过阅读自己弄明白。)结合 Nate Lee 在文章中给出的解决方案,外加我个人的一些理解,我觉得企业级 IM 应该可以往如下一些方向发展。

一、流程与消息的整合

与其在企业级 IM 内部实现轻量级应用,不如让其与现有系统做更好的集成。在这一点上不能不提 HipChat,她与 Bitbucket、Jira 以及 Github 都有非常完美的集成,能够在上述系统发生变化的时候以即时消息的形式推送给用户,而且开放的 API 也使得越来越多的第三方系统能够与其整合,使其功能日益强大。如果真的要在企业级 IM 内部嵌入流程应用,那么就该想想如何实现融合。

想象一个场景,开发人员在写程序的时候通常都要关注变更管理系统,而当一个问题并没有被很好描述的时候,开发人员要么像回复论坛中的帖子一样提出问题,并等待答复(就像 Github 那样),要么就更直接拉几个相关的人进入一个讨论组开始聊天,直到把问题讨论清楚。这两种方式显然都不是最优的。第一种方式就好像在使用邮件,邮件虽然更正式、更严谨,但是受到排斥的根本原因就是时效性,不能够“即时通讯”,只能书写然后等待。但是无疑所有的交流痕迹都会被保存下来,当日后需要回顾的时候,查阅就变得异常方便了;第二种方式解决了时效性的问题,但最严重的缺陷就是有可能丢失所有针对该问题的讨论细节,仅仅会把一些结论性质的东西更新到问题的描述中,更有可能连这些结论性质的东西都会随着懒惰与监管的不到位逐渐流失。

或许想象中的系统应该是这样工作的。当开发人员需要针对某个问题展开讨论的时候,可以直接针对这个问题发起一个话题,工具应该有能力自动将相关人员拉入这个话题讨论组,并定位到当前的流程状态。所有接下来的讨论均会被这个话题记录下来,并关联到当前状态上。某些核心的讨论结果还可以直接更新回或添加到问题的描述信息,一次交流就解决了历史留存和沟通时效的问题,将来再回过头来查看的时候,每个状态的每个时间点上都有若干聊天记录呈现在旁边,辅佐查看问题的人了解达成最终结论的演变过程。

不仅如此,即时通讯除了可以解决沟通上的时效性以外,结合流程的时候还能够提高流程的工作效率。就拿最简单的报销流程来讲,倘若一个报销事宜经由申请人填报、主管经理审批、部门总监审批、财务人员审批最后到公司负责人审批这样的流程。若其中任何一个审批环节出现问题,都会导致流程被退回。虽然这本身正是流程存在的意义,但是显然被退回的流程一定程度上影响了流程的运作效率。如果填报人员或某一级审批人员在处理信息的过程中发现有疑问,那么针对当前环节上的流程进行一番讨论,消除分歧,可以促使流程走到终点的可能性大大提高。

二、话题

其实上面的能力都离不开一个功能就是话题,可以有针对流程的话题,也可以有自由创建的话题。话题无非限定了群组里面讨论的内容,当一个话题讨论完成以后,就应该将其关闭,避免发生偏离。在需要的时候还可以将话题之间进行关联或者是让话题与流程、文档抑或某个用户进行关联。话题将碎片化的消息进行了归类与划分,多维度的话题关联让话题有了更多的延展,同时还能加快话题的定位速度,久而久之一个由话题构建成的知识库就慢慢诞生了,无需再特意去整理这些交流过程中显现出来的隐性知识,后来者可以非常方便的经由话题逐渐深入了解组织正在发生的事情。

三、个人助理

个人助理的想法是由微软小冰带来的灵感,她就像是一个逗逼的邻桌,只要你跟她说话,她就总能出乎意料的给你反馈。既然企业级 IM 定位在了聊天,那么为什么我还要去应用中开始某个八竿子打不着的流程能?如果每个人都有一个像微软小冰那样的助手,你可以跟她说需要走一个流程、需要记录一份文档、需要展开一个话题甚至需要进行一次电话会议,她会应该帮你把余下的事情都处理妥当,你需要的就等待最后的结果。Tony Aube 在 No UI Is The New UI 中对未来的人机交互给出了大胆的假设,想必以后需要做什么事情之前都最好找你的机器人助手帮个忙。而且时间久了她还会更了解你,你无需再跟她说复杂的指令来让他做一个事情,可能仅仅一个字,甚至一个动作她就知道了你的初衷。

还是以报销作为容易理解的场景,你直接跟你助手说你要发起一个报销,她会告诉你报销的注意事项,以及最近是否有制度上的更新。然后她会根据权限和组织关系把此次报销的相关人员都拉入一个话题,你直接说出你要报销的条目,她会帮你将其整理成一份标准格式的表单,并提交到流程系统,同时知会相关人员。如果需要讨论就地就可以进行,而且信息会随着讨论的进行逐渐更新,直到最后你确认提交此次申请,其他人可以同时就完成审批。

四、状态更新

我们平时都喜欢更新 QQ 或微信的状态以及签名档,好让朋友们知道我们现在的心情或者正在做的一些事情,这个功能拿到工作中也同样适用。哪个领导不想知道自己的下属在做什么,难道要每天去问问看吗?当你在处理某项工作、打开某个文档抑或参与某个话题的时候,所有的状态都会自动进行更新,主管领导就可以看到每个人的当前工作内容,不会有人再不停的追问你在做什么,你的工作上的一切(包括发呆)都会被清楚的记录下来(可能会有种被窥视的感觉,不过汇报工作内容本来就是需要的,把控好力度就 OK 了)。

最后,所有这些设想中的功能都需要即使通讯与企业应用做到有机的结合,这本来也该是企业级 IM 天生具有的能力。这些异想天开的功能,嘴上说说容易,但实现起来还需要一段漫长的路,甚至是颠覆用户体验的变革。企业级 IM 产品必然会迎来一次集中爆发,让我们拭目以待。