跳转至

software

Grafana Variable 的 regex 过滤方式

用 InfluxDB 收集到 Mountpoint 数据的时候,经常会掺杂一些不关心的,如 TimeMachine,KSInstallAction 和 AppTranslocation 等等。所以,为了在 Variables 里过滤掉他们,需要用 Regex 进行处理。网上有人提供了方案,就是通过 Negative Lookahead 实现:

/^(?!.*TimeMachine)(?!.*KSInstallAction)(?!.*\/private)/

这样就可以把不想看到的这些 mountpoint 隐藏,节省页面空间了。当然了,这里其实也可以用白名单的方法进行处理,直接写 regex 就可以了。

《加速奔向 2019》小程序编写和运营回顾

前言

关注清华的同学可能知道,昨天,“清华大学”公众号发了一篇名为《2018,我们共芳华丨@THUers 致相伴一年的你,请查收这份心意》的推送,内容大概就是,有那么 100 个新年台历礼品要送出去,大家如果想要的话,就扫描小程序。小程序模仿了火车抢票的病毒式营销的模式,要求大家分享到群聊或者朋友圈,让别人给自己加速,加速到 2019 的前 100 名即可填写信息领取奖品。

然后大家就在推送里看到了我。就酱。

开始

这件事情据说策划了有一段时间了,只是因为各种原因一直没有做,最后这个锅就路由到了我的头上。一开始说就是个加速小程序,逻辑很简单,但后来逐渐发现需求越来越多,主要是界面上的,动画上的,还有一些非技术因素的功能,嗯。这其实算是一个不大好的软件工程案例。

过程

线上的问题与解决方案

然后就是上线了。大概是昨天(2018-12-27)中午的时候推送发出去,很快流量就开始来了。很快,在朋友圈看到有同学在转发了,也有人反映说,网络有点卡,加载资源有点多。我去机器上用 iftop 看了下,流量大概是 250Mb/s,没打到千兆。我一开始看了下,CPU 和内存占用都良好,以为是网络出口限制的问题,就想着没办法了,就这样吧,扛过去再说。不过,忽然有了转机。

TUNA 技术群里,忽然有人在讨论 SOMAXCONN 的问题,我想到,会不会是有些参数没开够大,导致了性能瓶颈,又受到啊荣的点拨,立马调整了这些变量:

net.core.somaxconn
fs.file-max
net.core.netdev_max_backlog
net.ipv4.tcp_max_syn_backlog
nginx: worker_rlimit_nofile
nginx: event.worker_connections

很快带宽从 200Mb/s 左右打到了 400Mb/s 多,在 iftop 中看到的峰值接近 600Mb/s,见下图:

事后回来看,发现配置一套科学的监控系统真的很有用,如 TCP 连接的状态图:

这里最高的黄线代表的是 TIME_WAIT,意味着很多的 TCP 连接都卡在了等待资源上,而一当我修改参数以后,立刻就降了下来,ESTBALISHED 的连接有了显著的提升。这个问题从另一个图也可以明地看出:

这个图是 TCP Handshake Issues,可以看到无论是 activeopen 还是 passiveopen,都很高,意味着这里无论是发还是收都遇到了问题。而修改参数以后,这些问题立马得到了很好的改善。

其实这些本应该在上线前做好的,但我低估了清华大学的影响力,没有做好相应的准备,还是在优秀的运维人员的指点下得到了较好的效果。

用户数据分析

当然了,除了 Grafana+InfluxDB+Telegraf 这一套监控系统,我们也部署了 ElasticSearch+Logstash+Kibana,只不过我们还是用 Grafana 做了 ElasticSearch 的前端了。通过对 Nginx 日志的分析,我们得到了这些关键的数据(从 12-26 12:00 到 12-27 12:00 一天时间):

除了这些,还有很多有趣的数据,例如用户里北京的最多,也可以大致地看出各个地方网络和手机的普及程度;用户使用的手机的机型里前几名都是苹果的,从单项占领了排名的前很多位,之后则是华为小米 OPPO 等,但总体上反而是安卓用户更多。

微信小程序官方也提供了一些数据统计可供参考。例如页面的访问次数信息,一共大约有二十多万次,打开小程序有十三万多次,访问人数是五万多,还有女性用户比男性用户多等等。这个时代,有数据确实能够得到许多有价值的判断。

反思

这次学到了很多东西,验证了监控系统的必要性,它能够实时看到服务的运行状态并进行调优,事后也可以回过头来进行进一步的分析和总结。不足的是,遇到大客户量的时候,静态资源就应该用 CDN 服务而不应该自己搭建,成本不高而且用户体验会很好。这次后端在数据库操作都用了原子操作,没有出现大的问题,但如果以后遇到更复杂的需求的时候就没有这么容易了。

配置 homebridge-mi-aqara 并添加为 telegraf 的数据源

最近有了设备,想把设备拿到的数据都导一份存到 influxdb 里,但是目前找到的只有 homebridge-mi-aqara 可以访问并拿到数据,然后它又提供了 mqtt 的数据获取方案,于是自己写了个脚本去读取这些数据。

首先当然是配置一下 homebridge-mi-aqara,按照网上的教程来,这个不难。然后本地开一个 MQTT Broker(如 mosquitto),配置为本地监听,然后我编写了脚本 telegraf-mi-aqara.py ,使用前需要 pip install paho-mqtt,并且按照实际路径修改一下内容。验证能够跑起来后,写一个 telegraf 配置:

[[inputs.exec]]
        commands = ["/usr/bin/python3 /path/to/telegraf-mi-aqara.py"]
        timeout = "5s"
        data_format = "influx"

现在就可以读取到各项信息,如温度,湿度,是否开门,开关用电情况等等。

2018-12-16 更新:

研究了一下绿米网关局域网通信协议,得到了第二个版本 telegraf-mi-aqara-v2.py,它与第一版的区别是,第一版是主动向网关读取信息,而这一版则是监听组播包,等待网关发消息。这个脚本负责把读取到的组播信息发送到 MQTT,再让 telegraf 从 MQTT 里解析 JSON 消息,写入数据库。Telegraf 配置如下:

[[inputs.mqtt_consumer]]
        servers = ["tcp://127.0.0.1:1883"]
        qos = 0
        connection_timeout = "30s"
        topics = [
                "/telegraf-mi-aqara"
        ]
        persistent_session = true
        client_id = "Telegraf"
        data_format = "json"
        json_string_fields = ["model", "sid", "status"]
        tag_keys = ["model", "sid", "short_id"]

由于设备不全,有些字段可能不完整。如果大家自己要用的话,可能需要自行修改一下。

Grafana 可视化实践:清华大学 2018 年度人物评选

最近这段时间,清华内部正在投票选出今年的年度人物,想到最近刚好在学习使用 Grafana+InfluxDB+Telegraf 全家桶,于是想着能不能写个爬虫把数据都拿下来,然后用 Grafana 画出来,就可以得到一个投票随时间变化的趋势。爬虫很简单,就是登录,获取页面信息,然后按照 InfluxDB 的输入格式进行输出即可。代码放在了 jiegec/student-tsinghua-vote18 下。

接着就是用 Grafana 进行可视化,大概得到了这样一个曲线:

为保护隐私,把名字隐去了。实际上的投票时间是从 12-3 号开始到 12-7 号结束,但由于宿舍停电的原因所以采样的点在半夜的时候都没有,所以看起来有点奇怪,但还是能够反应总体的趋势的。比如可以看到前两名很早就一马当先,而后一直遥遥领先,下面的选手则排名变动很大,特别是截止前最后一段时间,大家都在拼命拉票,可见大家都是 DDL 选手啊。如果对上面这个图求个导,看看变化率的话:

这显现出了很有意思的一个趋势,就是每天十二点左右都有一个高峰期,然后在零点前大概熄灯附近的时间也是一个高峰期,另外就是截止前最后的抢票阶段,大家都在疯狂拉票,从中午拉到最后时刻。由于停电的原因,在零点附近的数据都比较的鬼畜,不过影响不大,趋势一目了然。

Grafana 真香!期望可以学到更多高端的查询语法和可视化的骚操作,现在有很多东西不知道该怎么可视化,比较苦恼,不知道大家有没有什么经验可以分享。

编写 010 Editor 的 FLV Template

最近在做 FLV 和 H264 方面的研究,研究了很多标准和文档,然后用 010 Editor 对着文件进行分析。这个软件真的很好用,对研究二进制结构用处特别大。不过它自带的 FLV.bt 功能不是很好,我对它加上了 H264(AVC) 的部分支持,放在了 myFLV.bt 里。我也写了 H264 的解析,不过效率不高,大文件要卡好一会。

除此之外,很多格式,010 editor 都有支持,特别好用,它的解析器语法也很好写。

强制启用 Google Chrome 原生的 Dark Mode

Mojave 的 Dark Mode 真香,但是 Google Chrome 并不会随着系统的 Dark Mode 设置变化,所以 NightOwl 只能让部分软件按照时间变更 Dark/Light Mode。一番搜索,发现其实 Google Chrome 其实已经支持了 Dark Mode,但只能设置,不能按照系统的状态自动切换,命令如下:

$ open -a Google\ Chrome --args --force-dark-mode

然后就可以看到 Google Chrome 已经是 Dark Mode 了。但可惜并不能自动切换。

配置 Grafana+InfluxDB+Telegraf 并添加 MIIO 数据来源

之前一直想配一个监控系统,现在有机会了,就简单配了一下。发现真的特别简单,用 Homebrew 安装这三个软件并且都跑起来,然后稍微动一下配置,就可以得到可观的效果了。

然后想利用 miio 配置一下,把宿舍的空气净化器各项参数拿到,以 Telegraf 的插件形式定时上报,然后通过 Grafana 进行可视化。插件放在了 jiegec/tools 下,就是一个简单的 Python 脚本。配置方法如下:

编辑 /usr/local/etc/telegraf.d/miio.conf

[[inputs.exec]]
    commands = ["/usr/local/bin/python3 /Volumes/Data/tools/telegraf/miio.py MIID_HERE"]
    timeout = "5s"
    data_format = "influx"

默认了 miio 路径为 /usr/local/bin/miio

Mac 上安装 Arch Linux,ZFS 真香

最近在 Mac 上装了 Arch Linux,按照 Mac - Arch Linux Wiki 一路一路走,创建单独的一个 EFI 分区给 Arch Linux 放 GRUB 和内核,一个 ext4 作为根分区。由于 Arch ISO 不支持 Broadcom 的无线网卡,于是先拿 Apple Ethernet Adapter 连到路由器上装机。然后把一些需要的驱动装上了,桌面用的 KDE Plasma,Trackpad 用的 xf86-input-mtrack-git,HiDPI 设置为 2x Scale,各种体验都还可以,就是 Wi-Fi 的 802.1X 没配置好,然后 kwalletd5 老是崩没找到原因。常见的应用除了微信基本都有,也终于可以体验 Steam Play,利用 Proton 在 Linux 上跑一些只支持 Windows 的游戏,不过我已经很少玩游戏了。

然后我就想,怎么做 macOS 和 Linux 之间的文件共享。典型的操作可能是 exFAT,但是作为数据盘的话,这还是不大适合。或者就直接用 ext4,配合 extFS For Mac by Paragon 使用,也可以,最后我选择了 ZFS。

在 macOS 上安装 OpenZFS on OSX ,在 Linux 上安装 ZFS on Linux 。具体命令就是:

$ brew cask install openzfs # macOS
$ yay zfs-dkms-git # Arch Linux

由于硬盘空间所限,我只用了一个分区作为 vdev,没有采用 mirror、raidz 等方案。我首先在 macOS 上创建了一个 zpool,参考 Creating a pool - OpenZFS on OSX

$ sudo zpool create -f -o ashift=13 Data diskxsy

此时应该能够看到 /Volumes/Data 上已经挂载了一个 ZFS Dataset。我采用 cbreak-black/ZetaWatch 在菜单栏里查看 ZFS 信息。此时回到 Arch Linux 上,通过 zfs import 可以找到并且挂载这个 ZFS Dataset 到 /Data 处。

我还尝试创建了一个加密的 ZFS Dataset,对加密的部分的粒度控制可以很细。另外,我参考 Time Machine Backups - OpenZFS on OSX 也在移动硬盘上划出一个新的分区作为 ZFS,在上面创建了一个加密的 Sparse Bundle,把它作为 Time Machine 的目标。之后还会尝试一下 zfs send 作为替代的备份方案。

USB/IP 实践

之前一直想玩 USB/IP,但是一直没有找俩 Linux 设备然后共享,今天终于尝试了一下,没有什么大问题。这次采用的设备是 Raspberri Pi 3 和 SaltedFish Pi。一开始尝试从后者向前者共享,但总是出现这个错误:

libusbip: error: udev_device_get_sysattr_value failed
usbip: error: open vhci_driver

然后我反过来做就好了,比较神奇。

主要过程如下:

  • pacman -S usbip 安装用户态软件
  • systemctl enable --now usbipd 启动 USB/IP 的端口监听 daemon
  • usbip list -l 查看本地有哪些 USB 设备可以共享
  • usbip bind -b [BUS_ID] 把指定的 USB 设备共享出去,其中 BUS_ID 从上个命令中查看
  • usbip list -r [IP] 在另一个设备上查看这个设备共享的 USB 设备,可以看到许多信息
  • usbip attach -r [IP] -b [BUS_ID] 把对方共享的 USB 设备 attach 到本地

效果:把一个 U 盘成功映射到了本地:

$ lsusb -t
/:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=vhci_hcd/8p, 480M
    |__ Port 1: Dev 2, If 0, Class=Mass Storage, Driver=usb-storage, 480M
$ lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda           8:0    1 14.9G  0 disk
`-sda1        8:1    1 14.9G  0 part /tmp/mnt

尝试 mount 什么的,也都没有问题。以后可以考虑把本地的 LicheeTang 通过这种方式穿透到远端,然后在远端用它的 IDE 进行编程。

UPDATE: LicheeTang 烧写有一些问题,直接 JTAG 写上去没有作用,但是 SPI Flash 是可以成功写入并且有作用的,虽然需要强制打断。感觉还是网络延迟导致了一些问题。

使用 HomeBridge 把小米空气净化器加入到 HomeKit 中

受 @NSBlink 安利,自己部署了一下 HomeBridge ,然后在 iOS 的家庭上就可以看到它。然后,通过 homebrdige-mi-airpurifiermiio 按照教程进行配置。然后就可以在家庭里看到小米空气净化器,包括空气质量,湿度,睡眠模式,温度,打开状态。然后我就可以做一些配置,如离开宿舍的时候自动关闭空气净化器,回来的时候自动打开。不过由于自己没有一个一直放在宿舍的 iPad、Apple TV 或者 HomePod,失去了中枢,这个功能可能会打折扣。

后续想买一些智能的灯啊,然后就可以用 Siri 进行打开 / 关闭了。

此外,我又试了下,可以用 homebridge-camera-ffmpeg 把摄像头配置到 HomeKit 中。这样,就可以远程查看视频流了。

部署 adminMongo 的 Docker 镜像

之前在软工的平台上部署了一个 MongoDB,但是自然是仅内网访问,想要浏览内容只能通过网页上的 Console 进去看,体验特别不好。所以想着能不能找一个在线的 MongoDB 浏览器。由于软工平台只能部署 Docker 镜像,所以我找到了mongo-expressadicom/admin-mongo。但软工平台现在还没实现环境变量的配置,所以我选了后者。

首先本地创建一个 app.json,让它监听 0.0.0.0:80,通过 deployer 传到平台上的配置,然后再把配置 mount 到 /app/config 路径上。现在就可以成功地在网页上浏览 MongoDB 了。

软工平台踩坑记

老师要求我们搞 CI/CD,CI 自然是很快就搞好了,不过 CD 还得配一下。今天研究了一下它的 Deployer 架构,发现了若干易用性问题:

  1. 缺乏文档
  2. 只有样例配置没有讲解
  3. 已有的文档 语焉不详
  4. 官方对此回复:功能太多,还没忙过来写文档

于是只好经常戳助教然后尝试理解这个东西。。然后遇到了很多的 BUG:

  1. 容器没有重启功能。。。
  2. 容器死了还是活着看一个图的颜色。。。毫无说明
  3. 容器虽然有 Console,但是输入过长后直接回到行首没有换行。。。
  4. 容器对外的域名里有下划线。。。Django 上来就一句 Invalid HTTP_HOST header: 'xxxx_xxx.app.secoder.net'. The domain name provided is not valid according to RFC 1034/1035. Express 直接就 Invalid Host header 放弃治疗。。。
  5. 助教对上一条的回复是,等我忙完 DDL 有空再做吧。。。也就是说现在要做只能自己再开一个 Nginx 容器然后自己在 proxy_set_header 上做手脚。。。

绕过 GPGMail 的激活检测

前段时间 GPGMail 宣布不再免费,在三十天的试用期后就不给用了。唉,可能是官方实在没钱维护了,也可能是官方想赚钱了。不过,既然 GPGMail 采用的是自由的许可证,意味着我们可以自己对代码进行更改。和许可证验证相关的代码如下:

- (BOOL)hasActiveContract {
    NSDictionary *contractInformation = [self contractInformation];
    return [contractInformation[@"Active"] boolValue];
}

我们只要改成 return TRUE ,在自己的电脑上手动编译、并复制到 /Library/Application Support/GPGTools/GPGMail 下即可。

另:还有一个直接对二进制打 patch 的方法(仍然符合许可证),利用了最近打 CTF 学到的一些知识。找到以上这个函数,然后把返回值修改成非零即可。这里就不提供方法了。最后的更改:

$ radiff2 -D
--- 0x0000282f  410fbec7
- movsx eax, r15b
+++ 0x0000282f  4c89e090
+ mov rax, r12
+ nop

当然了,还需要额外 codesign --remove-signature 一下。

谨慎对非自由软件采用这个方法。可能有法律风险。

在 Ubuntu 上跨版本迁移 MongoDB

由于 MongoDB 只支持当前版本和上一个版本的数据库格式,然后刚刚滚系统升级的时候升级到了 3.6.x,而数据库格式仍然是 3.2.x 的,于是需要先安装回 3.4.x 版本的 MongoDB,输入命令把数据库升级到 3.4.x 版本后,再用 3.6.x 的数据库进行升级。

以 从 Ubuntu 14.04 LTS 升级到 Ubuntu 18.04.1 LTS 为例,方法如下:

$ wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-3.4.17.tgz
$ tar xvf mongodb-linux-x86_64-ubuntu1604-3.4.17.tgz
$ cd mongodb-linux-x86_64-ubuntu1604-3.4.17/bin/
$ sudo ./mongod --config /etc/mongodb.conf &
$ mongo
> db.adminCommand( { setFeatureCompatibilityVersion: '3.4' } )
{ "ok" : 1 }
$ fg
^C
$ sudo chown -R mongodb:mongodb /var/lib/mongodb
$ sudo systemctl start mongodb
$ mongo
> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
{ "featureCompatibilityVersion" : { "version" : "3.4" }, "ok" : 1 }
> db.adminCommand( { setFeatureCompatibilityVersion: '3.6' } )
{ "ok" : 1 }
> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
{ "featureCompatibilityVersion" : { "version" : "3.6" }, "ok" : 1 }
$ # Okay now

在 Xcode 9 上启用 Vim 模拟(XVim 2)

作为一个不用 vim 编辑会死星人,用 Xcode 总是止不住自己想 Escape 的心。于是找到了 XVimProject/XVim2 进行配置。

大致方法如下:

  1. 按照 Signing Xcode 对 Xcode 进行重签名。套路和对 GDB 进行签名一样。不过这次,签名完成的时间可长多了,毕竟 Xcode 这么大。
  2. 接着按照项目的 README,首先 git clone 然后 make ,第一次打开 Xcode 的时候选择 Load Bundle 即可。

终于可以满足我 Escape Xcode 的欲望了。

Logo is a lisp dialect

Most of us have learnt how to use PCLogo to draw some graphics. Logo is a dialect of Lisp in fact, so most of us used a Lisp dialect at a early time! For some people, it is earlier than C++. Cool.

Screen Capturing Tips in macOS

I'm sure many people have already known this. But i haven't memorize it yet.

How to screen capture:

Shift+Command+3: Capture fullscreen.
Shift+Command+4: Capture region.
               : Press space to capture window. 
               : Hold option and drag, then
               : you will capture a region with its center in where you started dragging 
               : and one of its corners under your cursor.
Ctrl+OneOfTheTwoAbove: Capture to clipboard.
defaults write com.apple.screencapture location: Change the default location storing the images.

Apps enhancing the snapshots: Snappy and Mapture.

See more detailed here.