到每年结束的时候都会发现这一年过的好快。在2020年回顾2019年,大概也是很重要的一年。虽然大部分时候回忆起来都很平凡,甚至没有太多细节的记忆,但是大事却也有不少。总的来说,买房,结束两地分居,交房,搬家,换工作算是这一年中的几件大事了。

结婚的时候我们两个人完全没有任何买房的想法。但是在18年下半年,我们去在北京定居的学姐家做客,进门前完全没有想过买房的事情,等她俩相谈甚欢的三个小时结束后,在我们赶着最后一班公交车回闵庄的时候已经开始蠢蠢欲动要计算我们的预算了。

不管从什么角度来说,买房毕竟都是个大事,也许过去的二十多年我们都没有做过(金额)这么大的决定。即使被学姐夫妇“怂恿”到蠢蠢欲动了,但当时也还是想着在长沙或者武汉之间选择。大概有那么半个月我们在商量武汉和长沙,了解了长沙和武汉的情况,最后都决定了去武汉了。我对武汉并没有太多了解,不过她在武汉读书比较熟悉,又考虑到武汉到两家的距离来说算是一个比较合适的位置,长远来看对武汉的前景似乎也比长沙更有想象空间,就决定是武汉了。

可是天有不测风云,在看了两周的武汉楼市(也就是公众号看看)后,一天老婆突然说现在去武汉买房觉得好亏啊,因为她有一些朋友几年前在武汉买的房价格比18年末是便宜很多很多了,觉得很难接受,于是乎我们还是决定看看上海的房子,看我们就是这么随意的一对人。

阅读全文 »

最近有一个需求是用户需要对实例进行告警,之前使用grafana配置的邮件告警,问题是邮件系统对外部用户的送达不太可靠,经常收不到告警,于是考虑使用prometheus提供的alert manager功能,通过webhook来调用自己的邮件与短信接口实现告警。

安装与运行

alertmanager 是prometheus提供的二进制,直接下载, 解压运行就可以了。可以对其进行一些配置,主要配置一个webhook的地址。一个webhook 的配置如下:

global:
resolve_timeout: 5m

route:
group_by: ['alertname']
group_wait: 10s
group_interval: 10s
repeat_interval: 10m
receiver: 'webhook'
receivers:
- name: 'webhook'
webhook_configs:
- url: 'http://127.0.0.1:18080/api/webhooks/prometheus'
send_resolved: true

直接指定配置文件启动 /data/alertmanager/alertmanager --web.listen-address=":9093" --cluster.listen-address="0.0.0.0:9094"

阅读全文 »

前段时间想起来好久没有写过东西了,有时候老婆也会说你怎么现在都不写东西了。工作快两年了,这两年确实过的比较“突然”,白驹过隙、时光荏苒这类的词语用来形容毕业之后的时间,真的不过分;不要说写东西了,就是稍微带点思考做事也已经是一个深刻的活动了。

生活

生活中各种事情所花费的时间,就像大学时候的生活费开销一样,初一看这么多钱都花哪里去了,花点时间清算盘点,又没有大的出入,就显得很无力:明明什么印象深刻的事情也没有做,什么值的开心吹嘘一番的好东西也没有买,怎么钱就花完了呢?时间也是,明明我才开始工作,我还是一个萌新,刚刚从学校走出来,见到同事还想叫一声前辈,见到父母还觉得自己是个孩子,可突然想起来已经工作两年了,新来的同事一个比一个年轻了,自己悄无声息地就要变成老员工了,就知道我们的青春一去不复返了。

阅读全文 »

这只是官方文档的一篇翻译以及笔记,因为最近要使用到反射,故翻译此文。

Golang 中的反射

在计算中,反射是程序能检查自身结构的一种能力,这种检测通常通过类型实现。这是元编成的一种形式,也常常导致很多困扰。

这篇文章中,我们尝试通过解释在Go中反射是如何工作的以说明一些概念。每种语言的反射模型都不太一样(很多语言甚至不支持反射),但是这篇文章是关于Go的,所以下面内容中, “反射”一词都是指Golang中的反射。

类型和interfaces

因为反射建立在类型系统之上,我们先重新认识一下Go中的类型。

阅读全文 »

很多人觉得《三块广告牌》在奥斯卡的角逐输给了《水形物语》实在是太难接受了,因为很多人连《水形物语》这部片子本身就不能接受。

相比于《三块广告牌》,水形物语确实,就像电影里面的怪物一样,是个怪物。广告牌是一部风格、手法都很有创新的电影,而水形物语则更像时导演过去风格的重复,多方的杂糅;加上导演情有独钟的“人兽”的元素,实在很难被人接受,可就是这部电影力压了广告牌,拿了几乎所有广告牌志在必得的那些大奖。

有人说,水形物语在奥斯卡能压过广告牌一头,因为它实在是太过政治正确了,黑人元素,女权元素,同性恋元素,甚至人兽恋元素都不放过,简直就像白莲花一样的正确:爱压过一切;而广告牌初看起来甚至稍微有一点种族歧视和恐同元素在里面。但也许这也是为什么国内三块广告牌的口碑远超水形物语吧,我们并不那么关心黑人,女权和同性恋,我们更关心不公平得到重视,正义得到伸张。三块广告牌在豆瓣的评分高达22.7w人评出8.7分,而水形物语则是17.2w人评出7.3分(国外评分网站三块广告牌也略高一点,不像国内这么悬殊)。

电影的名字为《The shape of Water》,水是片中很重要的一个意象。水在电影中有三个主要的内含: 一是我们常说水是生命之源,人类从水中进化而来,从(羊)水中诞生出来,水代表生命,但这只在纪录片和末世科幻中比较常出现。二是朋克风格的代表,湿漉漉和烟雾朦胧是赛博朋克的典型环境因素,也常用来构造一种冷峻无感情的环境,像《银翼杀手》和《暴雪降至》。而第三个,水常用于代表爱与暗示性欲,这是最常见的一种用法,静止的水和缓慢流动的水,甚至像这部电影中的大雨,都是电影中常见的性暗示。所以水形物语,水是没有形状的,The shape of Water,大概就是The shape of Love, Love也是没有形状的。电影后面大段的水元素的场景也暗合这一主题。

这部电影是一部难得的现代童话,童话故事一般只出现在远古时代或者架空世界,以近现代为背景的比较少见。据说导演托罗对拍一部《水形物语》一样的片子预谋已久,考虑到托罗以往的影片风格,这部片子其实在情节和造型上已经是很克制了。毕竟美女与野兽这种风格本就不是所有人都能喜欢,而现代版的美女与野兽(女主也许还算不上美女还是个哑巴),还对野兽的不可描述器官“旁敲侧击”,不仅让人对导演的品位,或者恶趣味,表示怀疑(这种克制也可能是作为“墨西哥三杰”中唯一没有拿小金人的托罗对奥斯卡的妥协)。所以观影过程中,一直觉得这是一部很“冒犯”的现代童话故事,但换种思路,它其实是一种更归本溯源的表达,抛开人作为人的独特性,抛开现代文明的框架,也许影片表达的是一种更加纯粹,更加原始的情感。如果你还是不能接受故事的设定,那其实换种思路,女主本来就不是人,片子从很多情节反映了这一特点,女主看起来像人,表现的像一个哑巴人,像人一样睡觉,像人一样工作,但她其实不是人类。

第一点,女主的生活习惯很不像人,开头的一幕,睡在水中,像鱼一样,回归正常镜头后睡在沙发,没有床。第二点,早上先洗个澡还要在水里爽一发再出出去,然后就展示出女主脖子上的三道伤痕,看起来还是很”新鲜“的刮伤;女性身上的伤痕常用来表示家庭暴力,但这部片子显然没有家庭暴力这种东西,所以不禁让人怀疑这三道奇怪的伤痕有什么特殊的意义,当然看到最结尾你会发现这确实是个有故事的设定。第三点,我们都知道聋和哑是有因果关系的,很多哑巴并不是因为声带的生理缺陷而不能说话,而是因为天生失聪没有听人说过话才不会说话,就成了哑巴;而女主只是哑,并不聋,并且天生如此也没有说有什么生理缺陷,所以女主的设定就是充满奇特的。其实开一下脑洞的话,你会觉得这部片子根本就不是什么人兽恋,女主和怪物其实是一个生物,甚至是一个而不是一种。“怪物”是女主思想化生出来的,所以才具有那些神奇的力量,才和女主的精神上那么相似相亲。这么一想,是不是觉得这部片子的可接受度就大大提高了。

如果看到这一点,这部片子就显得更有深意了,所以它能得更多的奖就并不是因为黑人元素,也不是女权元素和LGBT元素了;它真正获奖的原因是一种向内挖掘的深度,不拘泥于型,就像片名叫《水形物语》,古人说“既自以心为形役,奚惆怅而独悲?”,古人也都知道“水无常形”;不要被“形”束缚的,才能向内挖掘更深的情感,而水是无形的代表。《水形物语》就是抛开所有的规则,抛开人在自然中的独特性,抛开人反观人与人看待其他一切生物两种视角中间的隔阂,再来反思人的情感与行为;更进一步地,如果抛开人看待自己与人看待别人之间的隔阂,在来反思自己的情感与行为,是不是会有另一种体验与结论,通俗一点来说,推己及人而以。这么一看,是不是影片高度就上去了。

影片的摄影风格和叙事风格和《潘神的迷宫》很像,某些场景的设计和调度则让人想起《罪恶都市》,而优秀的配乐让人以为是在看《爱乐之城》,甚至这部片子和《爱乐之城》是有互通的。

虽然我把这部片子拔的如此之高,但我并不喜欢这部片子,在豆瓣篇分只打了三星,不喜欢的片子,分析了再多的内涵与深度,也还是不喜欢。最后以影片结尾的一首优美的古诗结尾,相信很多人都会很喜欢这首诗:

Unable to perceive the shape of You.

I find You all around me.

Your presence fills my eyes with Your love,

It humbles my heart,

For You are everywhere.

这是对官方的The Go Memory Model文档的翻译兼笔记。

介绍

Go内存模型明确了在何种情况下在一个goroutine中读取一个变量时能够保证他能观察(observe)到被另一个goroutine写入到该变量的值。

建议/忠告

程序在修改可能被多个goroutine访问的数据时,应该把这种访问序列化。

为了序列化访问,可以使用 channel操作保护数据,或者一些syncsync/atomic包中的同步原语。

如果你的程序的行为需要阅读本文档接下来的内容才能理解,那你太聪明了。

但是,不要太聪明。

阅读全文 »

都知道Linux系统使用sar会收集系统运行的各种数据,可以用sar分析过去一段时间CPU,内存,网络使用等情况,分析系统瓶颈,在分析线上故障或性能问题时非常有用,但是一直没有好好用过,基本连io分析都不会,今天做个笔记记录以下sar的使用。

概述

sar 命令用于收集,报告,或者保存Unix/Linux系统的活动信息,一般将这些信息保存在 /var/log/sa/ 目录下,这些信息包括CPU使用率, 内存页面和使用率,网络IO和传输统计,进程创建活动,块设备活动和每秒中断计数等。

常说的sar来源于 sysstat 包,包括sar,sa1, sa2 三个工具。sar用户分析、显示 sa1 和 sa2 工具记录的日志。 sa2 工具每天在 /var/log/sa 目录下如一个报告,文件名以月份第N天命名。 sa1 工具将每天的系统活动信息以二进制数据写入到文件中。

配置

sysstat的配置文件在 /etc/sysconfig/sysstat 可以配置日至文件保存多少天,最长为一个月。各项配置在文件中都有说明。

常用命令

sar [option] [interval [count]]

常用选项:

  • -A 所用,等价于 -bBdFHqSuvwWy -I SUM -I ALL -m ALL -n ALL -r ALL -u ALL -P ALL
  • -B 报告换页(pagging)统计
  • -b 报告IO和数据传输速率统计
  • -d 报告每个块设备的活动
  • -F [MOUNT] 显示当前挂载文件系统的统计,伪文件系统(pseudo-fs)会被忽略。
  • -f [filename] 从指定文件获取信息,默认使用当前时间对应的文件
  • --human 对大小数值使用易读的单位打印
  • -P {cpu_list|ALL} 报告CPU统计,可以指定某个或某几个CPU。0是第一个CPU。
  • -p pretty print device name。
  • -q 报告队列长度和平均负载
  • -r 报告内存使用统计
  • -S 报告swap空间使用统计
  • -s [hh:mm[:ss]] 设置数据的开始时间,只有指定从文件读取数据时可用,时间使用24小时形式。默认开始时间时 08:00:00
  • -e [hh:mm[:ss]] 设置结束时间
  • -I {int_list|SUM|ALL} 统计中断信息,指定中断列表或打印统计信息或所有中断统计。
  • -n {keyword [,...]|ALL} 显示网络统计,可用的keyword包括 DEV, EDEV, FC, ICMP, EICMP, ICMP6, EICMP6, IP, EIP, IP6, EIP6, NFS, NFSD, SOCK, SOCK6, SOFT, TCP, ETCP, UDP and UDP6. 使用 sar -n ALL 1 查看当前网络情况,每秒刷新一次。
  • -t 使用用户本地时间显示记录
  • -u [ALL] 报告CPU使用率统计
  • -v 报告inode,文件和其它内核表的状态。
  • -W 报告 swapping 统计
  • -w 报告任务创建和系统切换活动
  • -y 报告 TTY 设备活动

Ref:

在远端服务器执行某些很耗时的操作的时候,我们习惯使用tmux(或者scree)来保持远端的进程不因为ssh连接断开而终止。更复杂一点的情况,我们希望使用在tmux中连接一个远端服务器上的tmux会话,这在有些场景下会很方便。

首先描述一下这个场景,我们有一个开发机器A,这是一台局域网服务器,有root权限,用户独立,可以配置无密码登陆的。但是还有一个连接到现网服务的跳板机B,这是一台安全加强的服务器,无root权限并且严格限制用户权限,必须使用token登陆的服务器。每一次登陆B服务器都需要输入变化的Token作为密码,当然我们在B服务器上可以运行tmux会话复用终端,现在的场景是,希望在A服务器保持一个到B服务器的连接,以保证部分任务可以利用这个连接实现无密码在B 服务器上操作。

Local => A => B

直接的方法可以在一个tmux会话中ssh到服务器,然后使用ssh连接,然后在服务器 attach 到一个会话,但是这样有一个问题,tmux快捷键前缀复用的问题,一般我们习惯使用 Ctrl+a作为第二前缀,并且一般不怎么使用默认的 Ctrl+b 前缀。在上面的场景中,可以 SSH 到 A 服务器,然后在 A 服务器开启一个tmux会话,在会话中登陆到B服务器(输入一次Token),但是这样不能在这个连接终端复用,需要在这个到B 的连接开启一个Tmux会话,但是用两个问题要解决:

  1. 上面说的tmux快捷键前缀操作符重复
  2. 在显示界面有两个状态栏

第一个问题一般可以通过按两次前缀快捷键操作嵌套的B服务器的tmux会话,但是这样很麻烦,像老妈妈操作电脑一样,第二个问题其实比较好解决,可以通过tmux命令隐藏一个状态栏。

一直想怎么能比较“优雅”地解决第一个问题,但是都没有好的方法。之前同事推荐了一个github上面的配置,可以通过一个开关似的快捷键在A的tmux会话和B 的tmux会话之间切换,比按两次前缀好一些,但是要记住当前处于什么会话,也有点不好。

一直有一个想法是通过配置不同的前缀操作键(prefix)实现直接操作B端的会话。理解tmux的快捷键捕获的话这个思路就比较好理解,其实tmux是只捕获前缀按键(prefix)的,如果按下的快捷键不是前缀健就会发送给会话的连接。如果A的没有Ctrl-a 这个前缀,那么“寄居”在A的tux会话中的B 中的tmux会话就可以直接使用 Ctrl+a作为前缀操作了。

但是,有一个问题是tmux的前缀按键是在tmux服务中生效的。我们知道tmux能保持断开ssh连接继续执行,是因为tmux是一个BS架构的服务(tmux二进制文件本身既是服务器端有时客户端),后台运行一个tmux的服务,每次运行tmux,如果没有后台服务则启动一个服务,然后attach上去。如果后台已经有服务了则作为客户端连接到该服务。而prefix是服务启动时绑定的。也就是说prefix不是session级别的,所有的连接都一个服务的session都是一个前缀。

那是否可以通过开启多个tmux服务实现,之前捣鼓的时候尝试在一台服务器上运行两个版本的tmux服务,但是都失败了,如果已运行一个低版本的tmux,不能使用高版本的tmux作为客户端,并且创始使用高版本的tmux启动服务议会报Lost connection。但是对于同一个版本的tmux使用下面的命令可以启动两个服务:

tmux -L t2

但是tmux默认会找 $HOME/.tmux.conf 作为配置文件启动服务,所以会导致新的服务的prefix和之前的一样,所以我们要使用一个别的配置,或者直接使用一个空的配置文件,这样 Ctrl-a就不是新服务的prefix了。

tmux -L t2 -f /dev/null

这样,我们只需要在这个服务上创建会话,然后通过这个会话连接到B服务的tmux session就可以用 Ctrl-a 作为前缀了,这样一个近乎透明的tmux嵌套就实现了。几个关键的命令如下:

# 创建服务
tmux -L t2 -f /dev/null

# 连接到新的服务创建会话
tmux -L t2 [new-session -s jump]

# 在会话中连接到B服务器

# 在B中连接到新的会话
tmux attach session-name

这样可以用 Ctrl-b作为A上面的会话的前缀,用Ctrl-a作为B 的会话的前缀,一般来说不需要使用 Ctrl-b的。

可以在A服务器创建一个别名,更快捷地连接B的会话

# 在A 的 bashrc
alias sshb='tmux -L t2 attach -t jump'

当然可以关闭A上面的tmux的status-bar: Ctrl+b :进入tmux命令输入界面, set status off,就OK了。这样就像是直接连接到B服务器的tmux会话了,实际上是通过A服务器的tmux跳转一层的。

这是一篇旧的笔记,最近Append了一些内容,发出来可能对有的人有用

Fedora在7月发布了版本号为26的新版本,在上周把家里的笔记本先升级到26踩坑,基本上平滑升级,没有太多问题,gnome的插件也兼容的比较好,除了几个不太常用的基本没有broken的。

可惜的是升级之后VirtualBox不能用,报的是比较常见的kernel driver not installed 的错误,以往按照给的提示操作一下安装好kernel driver就没问题了的,这次折腾了好久也不行。期间尝试过:

  1. 更新/重装 virtualbox
  2. 换到Oracle的源安装VirtualBox
  3. 手动运行 /sbin/vboxconfig,编译kernel driver
  4. 禁用modprobe kvm_intel Ref 再重装
    5.安装旧版本内核后重装virtaulbox

毫无意外以上的方法都失败了,经过一顿折腾感觉问题应该处在 secure boot上面, 想进BIOS把secure boot关掉,但是发现笔记本的BIOS密码忘记了,这条路也走不通了,不过我感觉就算关掉secure boot应该也不行。

后来找到一篇文章,自己对这个mod签名”骗过”操作系统,其实之前也看到了这篇文章,但是觉得有点麻烦就没怎么细看,今天研究了一下,其实也挺好处理的,就是生成一个key,然后用这个key给未签名的module签名,再通过mokutil导入key,重启系统就可以了,关键命令记录如下,具体细节可以查看原文。

sudo modprobe -v vboxdrv        # 查看mod信息,在这可以看到报错信息
# 生成key, 包括der和priv文件
openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj "/CN=Akrog/"

# 使用生成的key为mod签名
sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 ./MOK.priv ./MOK.der $(modinfo -n vboxdrv)
sudo mokutil --import MOK.der # 导入,注意这里要用sudo执行,前面可以用普通用户执行
# 这里会提示输入密码,这个是重启时导入证书需要输入的密码

sudo reboot # 重启进入导入证书的界面,按照操作即可
dmesg | grep 'EFI: Loaded cert' # 启动后查看我们刚刚生成的证书已经加载

# 重启后vboxdrv会自动加载,直接启动virtualbox即可。

VirtualBox可能会再运行时导致Host的CPU利用率飙升至100%,可能的原因是开启了vb的nested paging设置,再设置里面关掉可能就好了,该项设置可能需要先关闭虚拟机,设置路径在: Setting - System - Acceleration。go to the system tab, click on Acceleration and then uncheck the Enable Nested Paging checkbox. Click OK and start the virtual machine up and you should quickly notice some performance improvements 参考: DotNetMafia
和有一个CPU 飙升到100%的问题可能时虚拟机内某些程序有bug,比如我常用的为知笔记的后台进程就经常发疯到100%,在windows task manager 中kill掉就好了。

APPEND:

每次升级内核会出现模块签名无效的问题,所以升级内核需要使用对应新内核的 sign-file 脚本执行一遍,可能除了 vboxdrv,还有其他模块需要签名的,这些需要签名的列表可以在 执行 sudo systemctl restart systemd-modules-load.service 之后(这时通常会失败),通过 journalctl -xe 命令查看,只需要找出加在失败的模块然后使用之前使用过的 MOK.priv 和 MOK.der 两个文件签名一下就可以了,如果旧的密钥文件丢失了,就重新走一遍上面的流程,如果有旧的MOK文件则不需要 import MOK.der 的阶段了,比如升级 4.13.16内核之后就需要重新签名好几个module:

sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 ./MOK.priv ./MOK.der $(modinfo -n vboxnetflt)
sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 ./MOK.priv ./MOK.der $(modinfo -n vboxnetadp)
sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 ./MOK.priv ./MOK.der $(modinfo -n vboxnetpci)
sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 ./MOK.priv ./MOK.der $(modinfo -n vboxpci)
sudo systemctl restart systemd-modules-load.service

当然也可以禁用内核的升级省得麻烦,毕竟个人系统对内核版本要要求也没有那么严格,只要在 /etc/dnf/dnf.conf中加入 exclude=kernel* 这样的一行就会在 dnf update的时候排除kernel的更新了。