实时数据可视化

实时数据特征 通常来说,可视化的报表会以更高效率的方式将数据背后隐藏的信息传递给我们。通过一个简单的BarChart,我们就很容易对比某商品在第二季度中的销量差异;而通过一条简单的LineChart,则很容易看出员工平均工作时间在某个月份的分布。这些报表都或多或少与时间相关:随着时间的流逝,某项指标会因为各种各样的因素而产生变化。 另一方面,在某些领域,我们需要更高时效性的报表。比如产品的线上指标分析:有多少用户当前在线,主站的负载情况如何,有多少在线交易正在形成等等。此外,很多运维数据也希望有更高的实时性,比如目前服务器的负载如何,过去的5分钟的负载情况又是什么样子的等等。 这类报表的特点是: 高时效性 对于细粒度的指标,数据量可能会很大 过了某段特定的时间段,数据的价值会骤降 比如上图是Mac上的CPU使用情况的实时报表,它展现了一段时间内的各个核上的计算负载。这些信息不断产生,有不断被丢弃,没有人关注一个小时之前的CPU占用,只要能展示出最近几分钟的就好。 基于这些特性,如何存取数据、如何分析度量结果、如何滚动历史数据等等都会遇到和其他图表不尽相同的问题。另外,由于实时数据的可视化与时间是强相关的 – 它本质上必须是一个动态的图表,这与其他的图表类型又有不同。我们在这篇文章中将会讨论这些问题,以及解决这些问题的常见方案。 数据指标 对于实时数据,我们关注不同事件发生的次数,以及事件发生时持续的时长等。我们首先需要定义一些对象: 计数器(counter) 计时器(timer) 标量(gauge) 计数器 计数器涉及需要被记录次数的事件(通常是每发生一次,计数器加一/减一),这类数据的增长/减少规律比较固定,比如: 响应为200的请求 - response.code === 200 从某个session产生的请求 - session.id === 'b1b2b3bab22123bb1a' 计时器 计时器涉及所有应该记录时间长度的事件,通常这类时间我们可以通过引入一个时间段(interval)来计算一些统计信息,比如平均值,方差,标准差,最大值,最小值等。比如: 请求响应时间 - response.time 停留时间 - stay.time 标量 还有一种经常会用到的量,我们不关注过程中它的变化倾向,只关注某个时刻上的数字/状态,比如: 节点是否可用 某一时刻的进程数 某一时刻的CPU负载/内存占用率 数据处理典型流程 对于生产环境,实时数据既可以以日志的形式提供,也可以是来源于事件数据库。日志是最常见的形式,几乎所有的系统都会以各种各样的方式记录日志,大部分的日志会提供滚动机制:日志会被记录到一个固定尺寸的文件中,旧的日志会被滚动的写入到另一个文件(通常还会有配套的定时任务来清理更早的日志等)。另一方面,对于很多基于事件的软件系统中,事件会被写入到数据库中,这些数据也可以用作实时数据可视化的来源。 原始数据往往不能直接用来做可视化展现,通常我们需要做一些预处理,这些过程包括: 原始数据获取 结构化 初步统计 高阶统计 数据结构化 有很多的工具可以帮助我们实现这些步骤,比如我们通过一个简单的配置,就可以让logstash自动将源源不断产生的日志数据写入到statsd(最终周期性的写入到graphite数据库中): input { stdin {} } filter { grok { match => { "message" => "%{DATA:time} %{DATA:status} %{NUMBER:request_time} %{DATA:campaign} %{DATA:mac} %{DATA:ap_mac} %{GREEDYDATA:session}" } } } output { stdout { codec => rubydebug } statsd { host => 'localhost' increment => "airport....

June 17, 2018 · 3 min · 邱俊涛 | Juntao Qiu

为什么优秀的程序员不喜欢GUI

优秀的程序员 要给优秀的程序员下一个明确的定义无疑是一件非常困难的事情。擅长抽象思维,动手能力强,追求效率,喜欢自动化,愿意持续学习,对代码质量有很高的追求等等,这些维度都有其合理性,不过又都略显抽象和主观。 我对于一个程序员是否优秀,也有自己的标准,那就是TA对命令行的熟悉/喜爱程度。这个特点可以很好的看出TA是否是一个优秀的(或者潜在优秀的)程序员。我周围就有很多非常牛的程序员,无一例外的都非常擅长在命令行中工作。那什么叫熟悉命令行呢?简单来说,就是90%的日常工作内容可以在命令行完成。 当然,喜欢/习惯使用命令行可能只是表象,其背后包含的实质才是优秀的程序员之所以优秀的原因。 自动化 Perl语言的发明之Larry Wall有一句名言: The three chief virtues of a programmer are: Laziness, Impatience and Hubris. – Larry Wall 懒惰(Laziness)这个特点位于程序员的三大美德之首:唯有懒惰才会驱动程序员尽可能的将日常工作自动化起来,解放自己的双手,节省自己的时间。相比较而言GUI应用,不得不说,天然就是为了让自动化变得困难的一种设计(此处并非贬义,GUI有着自己完全不同的目标群体)。GUI更强调的是与人类的直接交互:通过视觉手段将信息以多层次的方式呈现,使用视觉元素进行指引,最后系统在后台进行实际的处理,并将最终结果以视觉手段展现出来。 这种更强调交互过程的设计初衷使得自动化变得非常困难。另一方面,由于GUI是为交互而设计的,它的响应就不能太快,至少要留给操作者反应时间(甚至有些用户操作需要人为的加入一些延迟,以提升用户体验)。 程序员的日常工作 程序员除了写代码之外,还有很多事情要做,比如自动化测试,基础设施的配置和管理,持续集成/持续发布环境,甚至有些团队好需要做一些与运维相关的事情(线上问题监控,环境监控等)。 开发/测试 基础设施管理 持续集成/持续发布 运维(监控)工作 娱乐 而这一系列的工作背后,都隐含了一个自动化的需求。在做上述的工作时,优秀的程序员会努力的将其自动化,如果有工具就使用工具;如果没有,就开发一个新的工具。这种努力让一切都尽可能自动化起来的哲学起源于UNIX世界。 而UNIX哲学的实际体现则是通过命令行来完成的。 Where there is a shell, there is a way. UNIX编程哲学 关于UNIX哲学,其实坊间有多个版本,这里有一个比较详细的清单。虽然有不同的版本,但是有很多一致的地方: 小即是美 让程序只做好一件事 尽可能早地创建原型(然后逐步演进) 数据应该保存为文本文件 避免使用可定制性低下的用户界面 审视这些条目,我们会发现它们事实上促成了自动化一切的可能性。这里列举一些小的例子,我们来看看命令行工具是如何通过应用这些哲学来简化工作,提高效率的。一旦你熟练掌握这些技能,就再也无法离开它,也再也忍受不了低效而复杂的各种GUI工具了。 命令行如何提升效率 一个高阶计算器 在我的编程生涯的早期,读过的最为振奋的一本书是《UNIX编程环境》,和其他基本UNIX世界的大部头比起来,这本书其实还是比较小众的。我读大二的时候这本书已经出版了差不多22年(中文版也已经有7年了),有一些内容已经过时了,比如没有返回值的main函数,外置的参数列表等等,不过在学习到HOC(High Order Calculator)的全部开发过程时,我依然被深深的震撼到了。 简而言之,这个HOC语言的开发过程需要这样几个组件: 词法分析器lex 语法分析器yacc 标准数学库stdlib 另外还有一些自定义的函数等,最后通过make连接在一起。我跟着书上的讲解,对着书把所有代码都敲了一遍。所有的操作都是在一台很老的IBM的ThinkPad T20上完成的,而且全部都在命令行中进行(当然,还在命令行里听着歌)。...

January 17, 2017 · 3 min · 邱俊涛 | Juntao Qiu

基于inotify的告警脚本

自动告警脚本 最近项目上有这样一个需求:系统中有一个后台服务会不断的生成监控日志,根据系统的运行情况,它每天会在目录/var/alarms下生成一个文件,文件名带有时间戳,其中内容格式如下: $ cat /var/alarms/alarms-20150228130522.csv node,summary,occurrence,proiority VIQ002,heartbeat failure,2/12/2015 01:23 AM,critical VIQ002,packages are rejected,2/12/2015 01:22 AM,major VIQ002,connection cannot be established,2/11/2015 01:23 AM,medium VIQ001,packages are rejected,2/11/2015 01:23 AM,warning VIQ001,connection cannot be established,2/09/2015 01:23 AM,medium ... 运维团队需要监控这个目录,如果里边的文件发生了变化,就要及时的发送邮件给工程团队解决。我们当然不可能人工的监控该目录,然后编写邮件,再拷贝粘贴,所以需要编写一个脚本来自动化这个任务。 处理方法有两种: 编写一个crontab的任务,每隔五分钟轮询一下,然后编写脚本来探测变化,发送邮件 使用操作系统提供的inotify相关API探测变化,编写脚本发送邮件 不过作为程序员,第二种方法显然更高级一些。另外相对于检测文件变化(对比目录树,检查时间戳,而且还要记录上一次变更的状态等),编写一个发送邮件的脚本要简单得多。 使用inotify 如果在Linux下,我们可以使用inotify相关的工具,你可以使用你正在使用的系统下的包管理工具来安装。也可以直接从源码包编译安装。 安装之后,系统中就有了一个叫做inotifywait的命令,这个命令提供多个参数。默认的inotifywait在接收到指定的事件(文件变化)后,会打印信息并退出。可以使用-m参数让inotifywati处于监听状态。-e参数指定需要监听的事件类型,下面是几个常见的事件类型: CREATE,创建 MODIFY,修改 CLOSE_WRITE,CLOSE,写入成功 还可以通过--format来指定事件的输出,%w表示监控的文件名,%f表示如果被监控的对象是目录,则当发生事件时返回文件名。比如下面的命令: $ inotifywait -m -e close_write /var/alarms --format "%w%f" 表示以监控模式(事件发生后不退出,继续监听),监听close_write事件,在/var/alarms目录上,并且输出的格式为%w%f。 这样我们在另一个窗口上模拟事件发生: $ touch /var/alarms/alarms-20150228130522.csv 当前的窗口就会出现/var/alarms/alarms-20150228130522.csv这样的输出。有了这个功能,我们只需要编写一段简单的脚本就可以完成上一小节中的问题了: #!/bin/bash DIR=$1 inotifywait -m -e close_write $DIR --format "%w%f" | while read FILE do cat ${FILE} | mail -s "Alarm: $FILE" juntao....

March 1, 2015 · 1 min · 邱俊涛 | Juntao Qiu