异常指标检测

源码

目前有两种算法

MAD 中位数绝对值偏差

对应的 JavaScript 实现

MAD in mathjs

DBSCAN 基于密度的聚类算法

对应的 JavaScript 实现

DBSCAN in JavaScript

准确度

要准确的判定一个指标是否异常是很难的,取决于很多因素:

  • 数据本身的特征
  • 窗口大小
  • 节假日等突发情况
  • 噪点

上面的两种算法都是经过 Datadog 工程师精心挑选的,有这样的特点:

  • 鲁棒性 避免噪点的干扰
  • 可用性 配置参数尽量少

此外各算法的参数还需要不断地尝试,才能找到一个最佳的配置。

参考资料

Detecting outliers and anomalies in realtime at Datadog - Homin Lee (OSCON Austin 2016)-Youtube

MAD(Mean 变体)-Khanacademy

DBSCAN in scikit-learn

Visualizing DBSCAN Clustering

怎样为你的 Commit 加上 GPG 的签名

源码

开源赋予了每个人贡献代码的权利,要提高开源软件整体的安全性需要从一个个提交开始。
为 Commit 带上 GPG 的签名就是一个很好的开始,它能够在一定程度上保证安全性。
GPG 是一个非常出色的加密软件。当年斯诺登就是用 GPG 把大量的绝密文件发送给了记者。
本文以 Ubuntu 为例,介绍怎样为你的 Commit 加上 GPG 的签名。

环境配置

注意只有 git 2.0 及以后的版本才支持 GPG 签名。

查看 git 版本:

1
2
~$ git --version
git version 2.8.2

确保 git2.x 版本 如果需要可以执行下面的命令升级:

1
2
3
sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git

查看 GPG 是否安装

1
2
3
4
5
6
~$ gpg --version
gpg (GnuPG) 1.4.16
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

系统里一般都已经装上了 GPG,如果没有可以 手动安装 GnuPG

1
sudo apt-get install gnupg

确保 gitGNU 都安装成功就可以开始下一步了。

生成 GPG Key

命令行输入:

1
gpg --gen-key

生成过程中需要输入一些信息:

  • 加密算法 推荐选择 RSA
  • 密匙长度 推荐选择 4096
  • 过期时间 推荐选择 1y 也就是一年
  • 名字 可以随便填
  • 邮箱 需要是 Github 认证过的邮箱
  • 注释 可以随便填

最后需要输入一个密码,类似于保护 SSH 证书的密码,可以留空,不过最好是填上。

接下来是漫长的生成过程,在等待的过程里可以多移动鼠标,多打开几个网页,以此来增加机器的随机性。

查看 GPG Key ID

GPG Key ID 是一个8位的字符串,对应着一个 GPG Key

在命令行里查看 GPG Key 列表:

1
2
3
4
5
6
~$ gpg --list-keys
/home/***/.gnupg/pubring.gpg
----------------------------
pub 4096R/6******7 2016-05-11 [expires: 2017-05-11]
uid Wang Yan <wyvernnot@gmail.com>
sub 4096R/B******E 2016-05-11 [expires: 2017-05-11]

输出结果里的 6******7 就是这个 GPG Key ID

导出 GPG 公匙

执行命令:

1
gpg --armor --export 6******7

会在命令行看到公匙的文本:

1
2
3
4
5
6
7
8
9
10
11
12
13
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1

mQINBFczB1kBEAC3afc50p08I7knynnm4ea/8VZy42zGH/qrIWoInqT8HbgwLb9s
TrulTgLMbMTTOhl4zqFtTR52ZTwfLOtnV8tCM62ZNqO6z0nd0bFPA7HVp5t9z4a5
qBF3l3AZO5TFjn8gTsxatpVf5Ug9gmkEOCAejwSPFKNvfAun+WSLZ19LaFcorrj1
...
cOyj7VNdmx1//BMp/5A6SEqJFkkLxebaJpcrv1dm1HvKGU8vty3JAdWgOjY5VVmn
nUaAr8D0uNquASkap4dki/zscK+tEJiH6HLnQGGtIf+fR2zoHAUfBvtTuUhq8w/Q
F0R/UVgc4Sg+Vz4gyYNJKO8BdTTTfvOZMDNFw4x70vXfhCZDm4QxgfUwRs//kkIh
Z3QylTf5xSk4
=kuFS
-----END PGP PUBLIC KEY BLOCK-----

拷贝这一大段到剪贴板,然后登录 Github 添加这个公匙,添加的入口在 Settings 下的 SSH and GPG Keys 里面。

配置 Git 启用 GPG 签名

首先设置 Git 默认使用的 GPG Key ID,就是上面那个 8 位的字符串。

1
git config --global user.signingkey 6******7

提交的时候加上一个 -s 参数就可以为提交签名:

1
git commit -S -m your commit message

要想以后如果每次提交都默认都开启 GPG 签名,尤其是使用 IDE 的情况下,需要修改 git 的一个全局设置项:

1
git config --global commit.gpgsign true

验证

执行 git push 后登录到 Github, 看看提交历史的右边是不是多了一个 Verified 图标。

如果看到下面的结果,那么恭喜你已经为整个开源世界的安全迈出了一小步!

提交历史

后话

如果在 Github 上把 GPG Public Key 移除, 那么之前的 Verified 提交会变成 Unverified

参考文章

StatsD 简介

源码

介绍 StatsD 的发展,协议,最后附带有一个假想的例子。

自主开发一套监控系统可以从这三个部分分别着手:数据采集,数据存储和数据展示。

对于有代码经验的开发和运维人员,数据采集是很容易解决的问题,例如要统计一个方法的执行时间,只需要记录方法进入和退出的时间差即可。
而对于后台架构中常见的各种组件如 Redis 和 MySQL 等,它们往往各自提供了数量可观的指标接口,使得运维人员可以快速的获取组件的运行状况。

数据存储曾经是比价复杂的一块,首先就是数据结构的设计,此外还要考虑快速的检索,统计操作等。
好在最近有很多兴起的时序数据库,如 InfluxDB 和 OpenTSDB,它们都对存储时间序列型的数据有很强的适用性。
数据展示可以采用开源的方案例如 Grafana 。

StatsD 的使用场景

把数据推送到存储模块的过程中,有的时候没有必要把所有采集到的数据都存起来。
典型的场景是 Web 服务器,当请求达到每分钟上万条时,把每条请求的响应时间都存入数据库是不现实也没有必要。

这个时候可以考虑设计一个缓冲模块,来实现数据的累加,平均值,中间值计算等。
StatsD 正是这样一个实现数据中转的工具,它能够完成简单但是非常实用的统计步骤。
另一方面,由于往 StatsD 写入数据的时候使用的是 UDP 协议,所以对被检测的系统的影响可以控制的很小。

安装 StatsD 服务

StatsD 安装指南

https://github.com/etsy/statsd#installation-and-configuration

装好 StatsD 以后,还需安装 InfluxDB 或者 OpenTSDB,由于篇幅的关系不再展开。

本文推荐使用 CloudInsight 监控系统,如果已经有 OneAPM 的账号,安装只需要 1 分钟左右。

http://docs-ci.oneapm.com/quick-start/

StatsD 协议

StatsD 的协议其实非常简单,每一行就是一条数据。

1
<metric_name>:<metric_value>|<metric_type>

以监控系统负载为例,假如某一时刻系统 1分钟的负载 是 0.5,通过以下命令就可以写入 StatsD。

1
echo "system.load.1:0.5|g" | nc 127.0.0.1 8251

结合其中的 system.load.1:0.5|g,各个部分分别为:

  • 指标名称 metric_name = system.load.1
  • 指标的值 metric_value = 0.5
  • 指标类型 metric_type = g(gauge)

指标名称

指标命名没有特别的限制,但是一般的约定是使用点号分割的命名空间。

指标的值

指标的值是大于等于 0 的浮点数。

指标类型

StatsD 封装了一些最常用的操作,例如周期内指标值的累加、统计执行时间等,因此对指标的值分成以下几种:

gauge 标量

标量是任何可以测量的一维变量。例如人的身高,体重、某一时刻北京市 PM2.5 的值等。

counter 计数器

如果某个变量没有办法一下子测量出来,这时就可以使用计数器,分步累加。

例如要统计某个接口的流量

1
ent0.traffic:100|c

在每个周期里 StatsD 会自动累加流量的值,并把平均值传给后端。

ms 时间

记录执行时间。请求响应时间是 12 ms,写入到 StatsD 服务器的方法是:

1
echo "request.time:12|ms" | nc 127.0.0.1 8251

StatsD 会自动计算以下指标:

1
2
3
4
5
request.time.avg
request.time.count
request.time.max
request.time.mean
...

set 集合

统计变量不重复的个数。例如:当前在线的用户

‘echo “online.user:9587|s” | nc 127.0.0.1 8251’

‘echo “online.user:9588|s” | nc 127.0.0.1 8251’

StatsD 实例

以做一个完美的煎饼果子的过程为例,参数和类型的对应关系如下:

计数器

  • 鸡蛋
  • 薄脆
  • 面粉

标量

  • 油温
  • 辣度

集合

  • 口味

计时器

  • 做每一个煎饼果子的时间

运行代码

1
2
3
4
git clone git@github.com:wyvernnot/introduction-to-statsd.git
cd introduction-to-statsd
npm install
npm run-script pipe
1
http://localhost:8080

参考

Redux 如何单元测试

源码

redux 里有一些好玩的东西,如果与 React 一起学习各种环境搭起来速度比较慢,也比较麻烦。如果使用单元测试来学习,
并且阅读源代码,可以更快地搞懂。

TOP Level

Redux 顶层的 API 允许你创建 Store, 合并 Reducer,并通过 storeEnhancer 来引入中间件进行扩展。

  • createStore(reducer, [initialState], [enhancer])
  • combineReducers(reducers)
  • applyMiddleware(…middlewares)
  • bindActionCreators(actionCreators, dispatch)
  • compose(…functions)

Store API

Store 创建后有这些方法可供调用

  • dispatch
  • subscribe
  • getState

Redux 常用插件

redux-actions

简化 Action 的创建,使其符合 FSA 标准

  • createAction(type, payloadCreator, metaCreator)
  • handleAction(type, reducer | reducerMap)
  • handleActions(reducerMap, defaultState)

redux-promise

使用 Promise 作为 Action 的 payload,以此减少不必要的代码

redux-thunk

使用 Funtion 作为 Action, 从而延迟执行