关于 DiskSing | 黄大龙

80 后程序员,现居北京。网络游戏,端游页游手游都做过,后来机缘巧合加入 PingCAP 后转做开源数据库一直到现在。

RSS 地址: https://disksing.com/index.xml

请复制 RSS 到你的阅读器,或快速订阅到 :

DiskSing | 黄大龙 RSS 预览

iter

0001-01-01 08:00:00

PD

0001-01-01 08:00:00

mok

0001-01-01 08:00:00

jsonp

0001-01-01 08:00:00

region-dist-cli

0001-01-01 08:00:00

父子对谈30则

2024-03-06 08:00:00

推文合订本。 1 小朋友:蛇的英语是snake,那小蛇用英语怎么说?(注:上次跟他讲过cat/kitten,dog/puppy) 我:小蛇应该没有单独的说法,不过英语里有很多种单词都指蛇,比如 Python、Anaconda、Mamba、Cobra、Viper、Asp…… 小朋友:你怎么知道这么多! 我:编程的时候顺便学的🥲 2 语重心长地对小朋友说:你要学会站在别人的角度看待问题。 小朋友:那别人如果躺着或者坐着呢? 3 想起那天坐飞机,奶奶说:你看外面的飞机翅膀好大呀! 小朋友:那个叫机翼。 4 今天给小朋友讲《愚公移山》。他总结说愚公运气太好了,正好被神仙看到。我说我要是愚公的话就不挖山了直接搬家,他说搬着家具是爬不动山的,你比愚公还笨。 5 给小朋友讲《凿壁借光》的故事,他说把墙壁凿穿不太好,应该让爸爸妈妈多赚一些钱自己买灯。 6 昨天给小朋友讲了《揠苗助长》和《守株待兔》,他的感悟分别是“要有耐心,不要着急”和“不会总是有好运气”。 7 小朋友说:爸爸看我的时候,镜子里的爸爸就在看镜子里的我;爸爸看镜子里的我的时候,镜子里的爸爸就在看我! 8 给小朋友讲成语故事。 《刻舟求剑》 我:……那人就赶紧拿刀在船边上划拉了几下做了记号记剑掉下去的位置。你看这样可以吗? 小朋友:不可以! 我:为什么呢? 小朋友:是别人的船,别人没同意不能乱划。 《掩耳盗铃》 我:……那人就给自己的耳朵塞上棉花,戴上降噪耳机,啥也听不见了再去偷铃,这样可以吗? 小朋友:不可以! 我:为什么呢? 小朋友:因为偷东西是不对的。 9 小朋友问:无穷大是奇数还是偶数? 10 快要跨年了,跟小朋友抒情:从明天开始就是2024年,2023年再也不会回来了,我们要跟它道别…… 小朋友打断施法:除非哆啦A梦来了,还带着时光机! 11 啃甘蔗的时候突然想跟小朋友科普一下,就问:你知道炒菜用的白糖是用什么做的吗? 小朋友:甘蔗做的。 我:你怎么知道的? 小朋友:因为我们正在啃甘蔗。 我:学会揣摩出题人的意图了是吧😅 12 小朋友:整个地球最热的地方是哪里? 我:应该是泰国的曼谷。 小朋友:错啦!是地球的中间,因为都是岩浆! 13 小朋友:爸爸,游戏和真实世界是不一样的。 我:嗯?哪里不一样呢? 小朋友:游戏里面可以死很多次,只要一次没死就过关了,真实世界很多次都没死,但是死一次就再也没有了。 14 我:看,这就是导弹。 小朋友:是不给糖就捣蛋的捣蛋吗? 15 我:感恩节快到了,你最想感谢谁呢? 小朋友:最想感谢太阳。 我:为什么?? 小朋友:因为太阳是照亮世界的灯。 16 小朋友:书上说空间站的速度是7km/s,它跑100km需要多长时间? 我:14秒多。 小朋友:跑1000km呢? 我:2分钟20几秒。 小朋友:真快啊,上次你开车1000km开了两天才到。 我:是啊。 小朋友:那它跑1光年需要多长时间? 我:4万多年。 小朋友(震惊):1光年这么远啊!

都2024了,你还没随身带录音笔吗?

2023-12-29 08:00:00

2023年我最满意的数码产品就是索尼ICD-TX660录音笔,我几乎每天使用它的时间都在15小时以上,它已然成为了我生活的一部分。 ICD-TX660 为什么要录音 一开始,我的需求源于一次惨痛的经历——离婚过程中,我被前妻用捏造的证据陷害。这给我敲响了警钟,让我开始逐渐意识到保存生活中的数字资料的重要性。生活中的每一次对话,都可能成为日后的关键证据。 经历过离婚诉讼之后,我在生活习惯上最大的改进就是每天携带录音笔,早上一起床就打开录音,一直到晚上睡觉前摘下来充电,每天产生约1GB数据,我说过的每一句话都有据可查。 — 象牙山刘能 (@disksing) March 1, 2023 这就是带录音笔进行全天候录音的最主要作用了:保留证据,规避法律风险和纠纷。无论是在商业交易中确认谈话内容,还是在私人生活中避免被误解或诬告,录音都提供了一个强有力的保障,可以作为证据的备份,减少不必要的麻烦。 可能有人会觉得,这样做太过极端,法庭和诉讼离自己很远,自己在生活中也没遇到过什么恶人,似乎并不值得这样做。但是,当我自己开始这样做之后,我发现每天看到的社会新闻有好大一部分,只要身上有录音笔在录着音,都是可以避免的,比如: 女性被同事性骚扰,但是没有证据,只能忍气吞声; 男性被女性诬告性骚扰,但是也没法证明自己没有骚扰; 约个炮,结果被对方诬告强奸; 被强奸了,结果对方说是自愿的; 借了钱不还; 装修谈好了价格,后面工人坐地起价; 路上扶了个老太太被赖上; 交通事故,对方承认是自己的责任,但是后面又反悔了; 等等等等…… 当然,记录事实真相的方式不止一种,比如可以随身带执法记录仪录视频,不过这种设备体积较大,而且在很多场合并不方便使用。而录音笔则可以随身携带,不会引起他人的注意,也不会对自己的生活造成太大影响。 录音笔技术上非常成熟,一般的录音笔都能提供非常清晰的录音效果,而且续航能力也很强,好一点的录音笔可以满足全天候录音的需求。从取证的角度来说,大多数情况下也是足够的。 你可能会想,为什么一定要连续全天录音,为什么不在需要的时候才录音?因为很多时候,关键信息的出现是无法预料的,你发现要录音的时候,可能已经错过了,或者才发现没带录音笔,或者发现录音笔没电了。如果全天候录音成为一种习惯,意味着你无需担心错过任何重要的时刻。 另外,每天早上开机放进口袋,晚上充电关机,有助于形成习惯。而且全天不用管,实际更无感,也会更少地干扰日常生活。 关于法律问题:录音是否能当证据使用? 录音是否可以作为证据,在很大程度上取决于录音方式和内容。以下是一些基本的法律考量: 并非隐蔽的录音都是非法的:如果录音设备带在自己身上,且录音是在公共场所或允许录音的私人场合进行,通常不属于违法行为。所谓“窃听”,指的是你人不在现场,把录音笔放在别人的房间里或者车里,这肯定是违法的。 证明无罪:如果你面临的指控比侵犯隐私更严重,且录音能证明你的清白,那么这样的录音在法律上往往是被允许的,至少可以帮助减轻你的罪行。 法庭裁决:即便录音在法庭上被判定为非法获取,它的内容也可能作为判决的参考,因为我国司法实践在很多情况下更关心事实真相而非形式程序。 全天候录音的用处 当我开始实践全天候录音之后,我发现它的用途远不止于拿来当证据给自己辩护,它还有很多其他的用处: 强大的安全感:我甚至认为这点才是全天候录音真正最有用的地方,即使录完的音频文件一次都没打开播放过,“我录了音的”这件事儿本身就能无形中成功消除对生活中很多潜在风险的担忧。有了录音的保护,我在很大程度上不用担心陷害和抹黑,不用担心被骗被害,这实际上让我可以更有信心地去选择信任别人。 扩展短期记忆力: 我们每天接收大量信息,不可能记住每一件事。全天录音可以帮助我们回溯重要的对话,刚看过的电影的精彩台词、医生交待的用药方法、上司安排的临时任务,甚至是朋友间的争执,都能通过录音回溯。 长期备忘,如同数字日记: 通过录音,我们可以记录生活的点滴,这对于回顾生活事件有极大帮助。 人生数字化: 录音的数字化信息,在未来可以利用AI技术进行分析提取,甚至有可能用来训练AI虚拟人。 索尼 ICD-TX660 录音笔的使用体验 下面让我谈谈这款录音笔的具体表现: 便携性:它小巧轻便,非常适合长时间携带。我通常将它挂在衬衫口袋里,不穿衬衫的时候放在裤兜里,或甚至直接放在背包里都没有问题。 录音质量:大法品质,没得说,音质清晰,即使是在背包中录音,房间内的对话也能被清楚地捕捉到。 续航能力:我日常使用128kbps双声道录音,续航可以超过18小时。这个时间长度保证了我不需要在白天中途充电。一年使用下来,续航可能有些下降(没仔细测过),但还是稳稳地保证18小时录音。实际上我觉得这是一个非常“甜”的续航时间,正好白天录音睡觉的时候插上充电,假如续航加到2-3天,反而可能很容易忘记充电。 存储容量:16GB的内存略有点小,按我的使用方法(128kbps、每天16小时),每天生成的尺寸是1G左右,每半个月就会满,需要记得转存。每年的录音文件就是350G的样子,需要准备NAS或移动硬盘来备份。 注意事项:它不防水。有X友反馈一旦进水,可能会出现续航减少和按键失灵等问题。因此使用时要注意防水。 如果想买其他品牌的录音笔,也可以参考我这里提到的这些点来评估。当然了具体情况可能根据使用习惯有所不同,比如使用更高音质的录音模式会减少续航并增加存储空间占用,使用更低的音质同理。还有也可以选择晚上充电时不停止录音,可以记录下鼾声和梦话,这样存储空间也会消耗更快。 最后是广告时间,如果你觉得心动想购买我使用的同款录音笔的话,可以使用我的京东推广链接 https://u.jd.com/Ju6gcuo ,我会得到一点佣金,感谢支持。

写段子的窍门

2023-09-08 08:00:00

段子之所以成为段子,最显著的结构特点就是要有转折,也被称作“预期落空”,即通过误导等叙事技巧先给读者建立一个预期,随后安排转折使预期落空。这是一个段子的趣味性的最主要来源,毕竟人人都喜欢反差感。 段子的创作过程常常是跟阅读顺序是反着的,也就是说,段子创作的起点是往往是转折之后的部分。这可以是一个笑点,比如最常用的谐音、双关、或者生活中偶然发现的有趣或荒诞的场景,也可以是自己想表达某个观点,或者自己想抒发某种情绪。 然后我们需要从要表达的点开始逆向往前扩展。拿谐音和双关来说,可以构造一个由于谐音或双关产生误会的场景,引导读者误以为是这个意思,然后在结尾揭示另外一层含义。 如果是想表达某个观点,或者评说某个事物。《喜剧圣经》有一个经典方法来让观点变得生动有趣,即考虑四个问题:为什么困难?为什么愚蠢?为什么奇怪?为什么害怕?很多严肃的主题套入这四个问题都会得到荒诞或有趣的答案。 关于如何去建立预期和让预期落空,最核心的机制就是文本的可多重解读性。这有点像赵本山小品里常见的场景,两个角色之间存在误会,然后一个角色说的每一句话都会被另一个人解读成别的意思。段子也是类似的,只不过读者不是上帝视角,而是被设计误导的另一个角色。 从日常生活中发掘可多重解读的文本是需要一定天赋的,本质上是要能从多个(可能不相关的)主题中寻找连接,而且这种连接是多多益善的——连接点越多,误导效果就越强,而且这种加强不是相加而更像是相乘的效果。 现在有一个好消息就是ChatGPT的文本联想能力相当强悍,我就经常问它一些类似“运营一家公司和处理家庭关系有哪些相似之处”的问题来寻找写段子的灵感。 与单口喜剧(国内也叫脱口秀)不同,段子是文本形式的,很容易被读者重复阅读,因此段子更适合设置理解门槛、保留一定的解读空间,让读者有一种解谜的快感。例如可以使用反讽和夸张的手法,读者可能第一感觉是这说的也太扯了,然后再回头重看一遍就理解了你真正想表达的观点。 同样因为可以重复阅读,段子不像单口喜剧一样铺垫和包袱不能相隔太远(不然听到后面已经忘了前面),在铺垫部分不管有多少货都可以无限往上叠加,最后完成转折后读者自然会回过头去重新看。 下面是操练环节,我就恬不知耻地选择我写过的几条段子,从创作过程的角度分析一下。 1. 3D打印的难题 段子的来源是在家折腾3D打印,最近接连出现打印过程中模型坍塌的情况,十分苦恼之余想到这跟芯片生产过程中良品率过低的困境有相似之处,这是一个有趣的点。 怎么去构建误导也挺显然的:让读者看起来我在说芯片生产(或者广义上的工业生产),实际上我是在说自家的3D打印。为了加强误导的力度,需要找到两者更多的相似之处(主要是“为什么困难”,此处借助ChatGPT),然后就有了这样一个简单的段子: 生产线代际落后,操作复杂,产能低,原料成本高,买不起高端设计软件,缺少专业人才,研发周期漫长,良品率过低,污染环境,这些是我在家实践3D打印遇到的主要难题。 当然,某种程度上读者也可以解读成对国产芯片或者高端制造业前景的担忧,这其实超出了这个段子的原始写作构思,不过也无所谓。 2. 福岛排放核废水事件 我想表达观点:对核废水危害的恐怖渲染是另有用心的政治宣传。不过我要直接这么发也太过于严肃无趣。那么怎么让它有趣起来呢?可以用之前提到的四个问题。 比如说这事儿为什么愚蠢?那我就想,假如今后跟日本的关系修好了,那么是不是要反过来宣传核废水无害呢?嗯,这听上去很荒诞,而且中日关系确实一直在忽冷忽热,再加上核废水的预计排放周期长达30年,确实挺有这个可能的。 按这个思路,可以这么写: 降低福岛核废水毒性的最低成本方案:日本首相就侵华问题向中国下跪道歉。 也是不错的,不过误导效果不太强,我实际最终发布的版本是这样的: 日本向大海排放核污水这事的最大风险点在于30年的排放周期实在太长了,长到足够中日关系冷热交替好几轮。 在铺垫阶段向读者暗示自己对核污染的担忧(并且使用小粉红喜欢强调的”核污水“而不是”核废水“来加深错觉),读者会误以为我想说长时间排放的技术障碍或工程管理难题,然后在第二句话锋一转,担忧的实际是中日关系的冷热交替,这样就揭示了最初想表达的主题。产生误导效果的关键在于“风险点”,一开始会被理解成核污染的风险,回过头看又可以被解读成政治宣传的风险。 3. dance / 单测 偶然发现单测的拼音dance恰好是一个单词,这是挺有趣的,但是不构成一个段子。很显然,这个素材本身就有可多重解读性,那么可以构造一个产生误会的场景,比如: 曾经有一个同事总在代码里写注释 // TODO: dance,一直好奇他是不是很爱跳舞,后来才知道他是提醒自己加单测。 这个版本可以微调一下增加解谜趣味性,不直接把“单测”这层意思写出来,比如最后一句改成“后来才知道他写的是拼音”。 我实际发布的版本是套用了“大师对话模板”,顺便说一下,有很多众所周知的笑话模板,在英语里也有经典的 knock knock、walks into a bar 等模板,套用模板的作用是能快速让读者找到熟悉的感觉,并产生一种“让我看看你还能玩出什么花样”的期待。 初学者在微信上请教大师:有了Copilot写代码速度太快了,一周的任务我一上午就把代码撸完了,接下来干点啥好呢? 大师:dance 初学者:大师我悟了,您的意思是应该放下工作去享受生活吧。 大师:shurufa huaile, jia dance 里面的几个细节:“在微信上请教”是对后面“输入法坏了”场景的铺垫;没有提到“单测”,也没提到“拼音”,只有一串拼音,增加了解谜乐趣;Copilot在这个笑话里是不必要的,提Copilot是蹭热点为了让读者有兴趣读下去。 就讲这些吧,还有一些不错的段子有点反动,这里就不说了哈哈。欢迎关注我的推特一起整活儿找乐子!

热门推文合订本(1-50)

2023-03-15 08:00:00

上海封城一个多月,亲眼目睹一个身在上海的大学同学从“只谈风月,不谈国事”变成了彻彻底底的反贼,每天都在朋友圈和微博冲塔…… — 象牙山刘能 (@disksing) May 9, 2022 李永乐老师还是很强的,至少以我的观察,多次涉及到计算机相关话题,完全没露馅儿。大家还知道什么值得推荐的科普up主嘛? — 象牙山刘能 (@disksing) November 22, 2022 🌸每日大作战🌸 来吧,这个呼声太高了。 pic.twitter.com/7wk3g0ermM — 象牙山刘能 (@disksing) February 13, 2023 你以为的高层领导是:“河南怎么乱用健康码,赶紧查办”,实际的高层领导可能是:“原来健康码这么好用,赶紧推广”。 — 象牙山刘能 (@disksing) June 14, 2022 李世民14岁起兵反隋,孙策18岁称霸江东,项羽24岁破釜沉舟,我34岁晚上提交了3个PR,挂了2个。 — 象牙山刘能 (@disksing) October 10, 2022 每个远程会议软件都应该搞3个按钮,分别叫: 我听不到你们说话! 我能听到你们说话! 你们听得到我说话吗? — 象牙山刘能 (@disksing) March 28, 2022 淘宝网的推荐逻辑是你总看色图所以你一定想买女装,京东商城是你刚买了个冰箱所以一定想买更多冰箱,推特是你能翻墙上外网一定是个VPN爱好者。 — 象牙山刘能 (@disksing) September 28, 2022 我判断一个女性是不是人格独立,有一条黄金法则,就是看她会不会开车。 可能听上去有点扯,但我自认为还挺准,尤其是对于已婚的家里有车的。其中的道理是一个人连自己行动上的自由都不把握住的话,我就不太相信她有思想上的独立自由。 — 象牙山刘能 (@disksing) November 12, 2022 有两类程序员几乎不出多线程bug:一类是啥也不懂,只要涉及到多线程就直接上锁;另一类熟读内存模型、体系结构、缓存一致性协议、内存屏障、竞态条件、指令重排……然后决定只要涉及到多线程就直接上锁。 — 象牙山刘能 (@disksing) October 17, 2022 估值超百亿美元的Grammarly眼看着要被ChatGPT一波带走了。更可怕的是,这并非ChatGPT的本意,只是微不足道的意外斩获。

热门推文合订本(51-100)

2023-03-14 08:00:00

职业生涯见过的最脑洞大开的代码是在10多年前的一个C++网络游戏项目。 大致情况是在服务端new一结构体,设置好相关字段后把指针放在消息包里传给客户端。 刚毕业的我直接被惊掉下巴:指针是服务器的内存地址,发到客户端怎么能用呢?而且指针也没留副本,那个结构体不会内存泄漏吗? 👇评论区揭晓答案 — 象牙山刘能 (@disksing) August 5, 2022 更新一下离婚进展,抚养权诉讼一案,一审胜诉! 赢的特别艰难,我们前期准备不充分,而对方暗暗花了大量时间搜集对我不得的证据,加之法官也是4岁小孩的母亲,开庭前一天跟我说的是到时候肯定不会判给我。幸好我们稳扎稳打不放弃,认真对待每一步流程,光是给法庭的陈述意见我就写了好几份大几千字的。 — 象牙山刘能 (@disksing) December 16, 2022 朋友们,大结局要来了!悲剧还是喜剧就看我的嘴炮能力了。 pic.twitter.com/NV4ASgWACX — 象牙山刘能 (@disksing) February 23, 2023 天灭Kubernetes 退云原生保平安 人在做 天在看 声明式API留祸患 故障一出天地灭 格式化etcd保平安 诚信诚念裸机好 虚拟主机平安保 开源弟子说真相 教你脱险莫拒绝 网上搜 ⑨评Kubernetes 有 真 相 — 象牙山刘能 (@disksing) June 8, 2022 外卖定律:好吃,便宜,卫生这3项最多只能选2个。 — 象牙山刘能 (@disksing) October 11, 2022 王小波和习近平是同龄人,早年经历也颇为相似。 他们都在北京出生,年龄相差仅1岁,几乎同时在上山下乡运动中下放农村插队,后来都回到北京上大学,之后相隔一年先后结婚。 1982年,李银河赴美国留学,2年之后王也同往美国。 1982年,习选择放弃移民英国跟柯玲玲离婚,赴河北上任,从此正式走上仕途。 — 象牙山刘能 (@disksing) October 18, 2022 我这收藏了一篇很有意思的文章 https://t.co/LxZeb03tkA https://t.co/KC7dnNVjv9 — 象牙山刘能 (@disksing) October 9, 2022 在AI的智能终于超过人类的时候,人们发现AI模型并没有发展到之前想象的那般复杂,然后才意识到原来人类思维的本质也不过是机械的模仿、生成、变换、随机组合……

热门推文合订本(101-150)

2023-03-13 08:00:00

小朋友在我这,前妻在外面砸门。报警了。真刺激。 — 象牙山刘能 (@disksing) December 18, 2022 草,大半年没联系的好基友也离了,我这是要火速脱单啊。 pic.twitter.com/AhVyBHvI4m — 象牙山刘能 (@disksing) March 1, 2023 整理了离婚大战合订本,送给错过第一季的推友们。https://t.co/mDdaLLI3VS — 象牙山刘能 (@disksing) March 7, 2023 Rust语言经过多年的不懈努力终于找到自己最擅长的领域:重写命令行小工具。 之后再接再厉,进一步找到自己最擅长并可以实现降维打击的细分领域:重写前端开发命令行小工具。 — 象牙山刘能 (@disksing) January 12, 2023 微博上很多人都在痛骂两个脱口秀演员(黄西和池子)在美国演出时说了一些伤害中国人民感情的段子。 但是没有人看过视频,也没有文字资料,也没有一个人站出来介绍他们都说了些啥。 只有貌似知情的人语焉不详地说:恶劣到都没法发出来,发出来你们也看不到,懂了吗?直接开骂吧…… pic.twitter.com/ff7pFHTHKZ — 象牙山刘能 (@disksing) February 15, 2023 我们这几天流行把包子扔到屋顶上粘住。 pic.twitter.com/bR1rg0bmqb — 象牙山刘能 (@disksing) December 31, 2022 pic.twitter.com/8y0c8gS6HE — 象牙山刘能 (@disksing) September 20, 2022 aws就像一个大型游乐园,里面啥都有。买票进去了才发现啥都要收钱,还比外面贵。 — 象牙山刘能 (@disksing) October 12, 2022 平时上班干活的时候总想着做side project,真到了周末只想打游戏看剧…… — 象牙山刘能 (@disksing) September 25, 2022 我有一个朋友,曾经在北京补了颗牙,后续治疗的时候是在老家四线城市三甲医院,当地医生看到北京医生的操作后啧啧称奇,全科室都过去围观😂

热门推文合订本(151-200)

2023-03-12 08:00:00

跟推友讨论完提取公积金的问题,又琢磨出一个小技巧:因为用房贷提取公积金只看总额,之后提前还贷了也不影响每月发放,那么买房的时候即使可以全款,也可以考虑先办贷款,等办好公积金提取手续之后再全部提前还掉,这样不用给银行多交贷款利息,同时未来很多年公积金都直接发到自己卡里。 — 象牙山刘能 (@disksing) January 5, 2023 我就一直感觉我的on-call频率比别人高! 常常是跟一个人一起on-call,没过两周又要跟另一个人一起on-call。 我还以为是错觉! 直到这次,我发现我特么跟自己一起on-call! 谁又能想到,我竟然在on-call系统里有两个号。 — 象牙山刘能 (@disksing) October 28, 2022 代码看不懂了,就想找个理由重写……这是病得治。 — 象牙山刘能 (@disksing) October 17, 2022 法官跟我通了电话,说我老婆还逼孩子拍了视频说愿意跟妈妈一起生活。法官表示我老婆确实是个疯批,如果明天判给她,不是因为道义在她那边,只是因为她太疯批了,指不定后面能干出什么事来。 我是不是完了😢 — 象牙山刘能 (@disksing) November 14, 2022 我有跑一个监控推特好友的程序,发现最近有几个知名推油号没了😳 pic.twitter.com/xTBYFocpji — 象牙山刘能 (@disksing) September 28, 2022 前几个月当疯批女人忙着设计张罗我的黑料,锁定瓜分我的财产时,我还颇有闲情逸致地参加了hackathon和软考,还有大量的心思花在编段子给你们看,所以你们算不算吃人血馒头。 — 象牙山刘能 (@disksing) November 17, 2022 看到雄安的建设近况,就想到90年代全国各处大肆兴建的“开发区”,它们大多在10几年后短时间内快速陷入衰退和破败。 我觉得城市就应该是不断修修补补生长出来的,而不是从零开始的自上而下的设计。 甭管你往里面放多少高科技都没用,就算现在是先进,整齐划一的先进会导致未来某个时间整齐划一地过时。 — 象牙山刘能 (@disksing) January 28, 2023 https://t.co/xI6XuC11jT 这篇文章总结的很棒! https://t.co/aGq2M8SgZt — 象牙山刘能 (@disksing) January 23, 2023 刺激了。 pic.twitter.com/J2rmBcqyW7 — 象牙山刘能 (@disksing) December 7, 2022 昨天很多网友说k8s很简单,写配置文件,用就完了。你们一定想不到我们公司的大神都做了什么……

离婚推文合订本

2023-03-07 08:00:00

收到了终审判决,即日正式离婚,如释重负。 — 象牙山刘能 (@disksing) March 6, 2023 经历过离婚诉讼之后,我在生活习惯上最大的改进就是每天携带录音笔,早上一起床就打开录音,一直到晚上睡觉前摘下来充电,每天产生约1GB数据,我说过的每一句话都有据可查。 — 象牙山刘能 (@disksing) March 1, 2023 家人们,今天离婚大战迎来始料未及的转折。 我来到法庭踌躇满志准备大干一场,却发现我那不走寻常路的准前妻直接没来。 看着对面两个空座位,刘能恍惚间好像听到有一大群草泥马奔腾而过,满脑子骚话一句也说不出来。 PS:这个情况按撤诉处理,没有变数了,我胜! pic.twitter.com/0wuS87qZGC — 象牙山刘能 (@disksing) February 24, 2023 嘿嘿,一点都不慌,这次保守估计9成胜算,我有ChatGPT帮我写台词她怎么跟我斗! pic.twitter.com/5zUVQYInOB — 象牙山刘能 (@disksing) February 23, 2023 朋友们,大结局要来了!悲剧还是喜剧就看我的嘴炮能力了。 pic.twitter.com/NV4ASgWACX — 象牙山刘能 (@disksing) February 23, 2023 昨天我妈跟我商量,说准前妻一个人在北京,要不要叫她过来一起过元宵节。我说绝无可能。 到晚上睡觉的时候我一直在琢磨,是我太刻薄了呢,还是我妈太善良了。 早上起来突然想通了,是因为我妈没亲眼看到她在庭审的时候提交的材料。 — 象牙山刘能 (@disksing) February 4, 2023 我也算是熟读婚姻法的,从法律上讲,在性别问题上是相当平等的,男女有别的部分仅限于:法定年龄不一样;怀孕期间、小孩1岁以内,男方不能提离婚;哺乳期小孩一般判给女方。 某种意义上来说,很多人认为法律偏向男方或者女方,尤其是在财产方面有性别歧视,其实是出于各种偏见,比如男的一定赚钱多。 — 象牙山刘能 (@disksing) January 24, 2023 从8月开始一直入不敷出,直到12月发了双薪总算是苟住了😳 — 象牙山刘能 (@disksing) January 22, 2023 我的2022年财报整理出来了,得到的主要结论是离婚可真费钱🥲 — 象牙山刘能 (@disksing) January 22, 2023 😇准前妻自己回老家了,喜得2周安宁。在考虑明天要不要去趟办公室,已经快忘记公司地址了。

给TiDB(MySQL)写一个代理网关

2022-08-24 08:00:00

转到cloud团队(主要做TiDB Cloud DevTier)后,这几个月大部分时间都在tidb-gateway这么个项目上折腾。现在一期功能算是上线了,准备开始做二期,趁这个机会简单总结一下。 因为TiDB是兼容MySQL协议的,所以主要其实就是折腾MySQL协议,然后如果你想做一个MySQL Gateway,大部分内容应该也是兼容的。我把相关代码整理了一下放在 tidb-gateway项目。 项目背景 先简单说下为什么需要做网关。由于TiDB Cloud是没有多租户或者serverless支持的,这就是说,用户每创建一个集群(包括免费的DevTier),我们在后台就会真给创建一个独立的集群。 跟友商的serverless方案相比,我们这么做的好处大概就是开发速度快,不用为上云做特别的改动,然后缺点就是贵。 为了降低成本,我们在DevTier上做了一定的“体验降级”:当用户的集群在连续一段时间不使用之后,我们会保存数据并把集群休眠,下次用户再需要使用的时候,需要先进行一个手动唤醒操作。 这么做完了有一定效果,至少对于已经“跑路”的集群,我们不用无限期地付出成本了。但是要继续优化,我们遇到两个障碍: 由于MySQL协议的限制,客户端通过TCP连接到服务器后,是由服务器首先发送第一个消息,同时因为是裸TCP连接,不像HTTP有请求Header可以知道客户访问的域名来进行路由。这样我们不得不为每个用户集群创建独立公网LB——据说这个还挺贵的。 临时关停的集群需要在网站上手动开启,用户体验负分,这导致我们权衡之下只针对静默7天以上(基本判定是跑路了)的集群做休眠处理,这样对每个集群都额外付出了7天的成本。 解决这两个问题的方法自然就是在TiDB前端引入一个网关服务了。 网关负责接受客户端连接并与之交换消息,等拿到用户信息之后,以代理的方式去连接真正的用户集群。同时,如果用户集群处于休眠状态,网关可以把连接阻塞,然后通知K8s唤醒,这样一来用户在休眠后第一次连接时等待一段时间,不需要在网页端做额外操作了。 MySQL建立连接过程 我们先简单分析一下MySQL的连接建立流程。 客户端向服务端建立TCP连接。 服务端返回InitialHandshake消息,其中包括版本号和一些兼容性标记(比如是否支持TLS等) 客户端返回HandshakeResponse消息,其中包括兼容性标记、连接使用的用户名及数据库名。 服务端和客户端根据AuthMethod交换若干次消息,直到服务端返回Ok或者Err消息,说明连接成功建立或者失败。 TLS连接建立过程 如果需要启用安全连接,步骤3中,Client会先发送半个HandshakeResponse消息包,其中携带了ClientSSL标记,服务端读到此标记后,会发起将TCP连接升级为TLS连接,升级完成后,Client会再次发送HandshakeResponse消息回归到常规流程。 鉴权FastPath及AuthMethod磋商 为了减少建立连接过程种消息交换的次数,MySQL Protocol有一个鉴权的快速通道。 在服务端发送InitialHandshake消息时,会先默认猜一个AuthMethod,并随机生成8字节或者更长的challenge payload,放在InitialHandshake消息中一起发给客户端。(为什么说是“猜”呢,因为不同用户可能设置不同的AuthMethod,然而在这一阶段,服务端还不知道要连接的用户是哪一个,自然不知道正确的AuthMethod应该是什么了) 客户端根据AuthMethod定义的方法对密码+payload加以计算,计算结果连同AuthMethod一起放在HandshakeResponse里一起发给服务端。 如果服务端读取对应的用户表之后,发现AuthMethod跟猜测的一致,那么就可以直接验证客户端的计算结果了,成功后直接返回Ok,这样就完成连接建立了。否则,服务端需要发送AuthMethodSwitchRequest来重新进行鉴权。 tidb-gateway的实现 Gateway的实现基本上就是经典的man-in-the-middle,在客户端和后端TiDB之间相互转发消息,顺便在中间做一些手脚。不过,首先需要解决的问题是,怎么获得连接对应的是哪个用户集群来进行路由。 传递cluster id 对客户端来说,它仍然是以连接MySQL Server的方式在连接Gateway,所以我们需要想办法在协议中插入集群信息。 MySQL的HandshakeResponse中有个Attrs字段可以用来插入一些自定义信息,可惜不是所有的DB Driver都支持设置。权衡之下,我们最后决定直接把集群id跟用户id拼接在一起,比如默认的root用户改成{clusterid}.root,这样虽然看上去有点怪,但是能保证兼容所有的客户端。 连接建立过程 这个过程比较显然了: 客户端向Gateway建立TCP连接。 Gateway构造一个默认的InitialHandshake消息返回给客户端。 客户端发送HandshakeResponse消息给Gateway。 Gateway解开HandshakeResponse,如果设置了ClientSSL此处将连接升级成TLS连接。 Gateway根据UserName设置的clusterid找到用户集群发起TCP连接,此处如果集群处于休眠状态要先唤醒。 TiDB向Gateway发送InitialHandshake。 Gateway把从客户端收到的HandshakeResponse发送给TiDB。 Gateway把两个连接串连起来对拷数据。 AuthMethod的特殊处理 由于MySQL协议中鉴权FastPath的存在,这个过程是有问题的:客户端收到的challenge payload是一开始由Gateway生成的,它跟后端TiDB发给Gateway的显然不一致,这将导致后端TiDB在收到HandshakeResponse后校验失败报错。 不过,校验失败的前提条件是FastPath被成功激活,即TiDB初始猜测的AuthMethod是正确的,否则TiDB不会激活FastPath,而是发送AuthMethodSwitchRequest尝试重新鉴权。 解决这个问题的方法也很简单,我们把转发给TiDB的HandshakeResponse篡改一下,改成一个TiDB不认识的AuthMehod,这样FastPath就不会激活了。 TLS的特殊处理 因为Gatway和TiDB的连接是在足够安全的内网,从节约能源的角度考虑,我们希望避免在Gateway和TiDB使用安全连接。 这样就带来一些问题:在客户端看来,它跟服务器之间是安全连接,但是在TiDB看来,连接是非安全的,会产生一些不一致的现象。比如require_secure_transport功能(这个选项限制TiDB只接受安全连接)就不能用了,还有系统表中Ssl相关的信息显示也都不正常。 解决办法是利用了MySQL Protocol的那个可以在插入自定义Attrs的功能,由Gateway把客户端连接的TLS相关信息通过Attrs发送给TiDB,然后我们给TiDB打了个小补丁,让它可以把TLS信息解析出来,并设置上安全连接的标记。 数据压缩和sequence number MySQL协议支持设置数据压缩,可以在进行导入导出等场景下显著节约流量。与TLS类似的,我们也希望数据压缩只在客户端和Gateway之间启用,Gateway和TiDB之间保持关闭以减少TiDB的CPU消耗。 不过,MySQL Protocol中有一个sequence number的概念,它需要被携带在每个消息包中,并且在一次客户端服务器交互过程中保持+1递增。譬如,客户端向服务器发送一个查询,拆分成2个消息包,sequence number就分别是0、1,服务器返回2次result,拆分成3个消息外,sequence number分别是2、3、4,然后客户端发送下一轮查询,再从0开始重新计数。 当Gateway两端的压缩方式不一致时,拆分包的粒度不一样,会产生sequence number对不上的情况。所以这种情况下,就不能简单地做data stream拷贝了,而是要认认真真把每个消息包解出来,并在两端分别维护sequence number。

论怎么与基层干部打成一片

2022-04-01 08:00:00

下午发了条推特,讲与基层干部的斗争经验,看起来感兴趣的网友还不少。 谈一下与小地方基层干部的斗争经验。他们最忌惮的主要3点:怕上级,怕舆情,怕有背景的人。 所以我们遇事绝对不能怂,讲道理讲不明白就直接问对方哪个部门的,上级是谁,让他相信你有可能把事情往上捅,尽量说普通话,有单反相机的话可以挂身上,平时背几句党员的群众路线啥的备着,保准势如破竹。 — 象牙山刘能 (@disksing) April 1, 2022 干脆借着兴致简单讲两个小故事,就图一乐,大家别当真哈哈。 一 大约六七年前,休假在老家,一个不知道四线还是五线的中部小城。 起因是我姨妈拿着5万块去银行存钱,结果不知道怎么被忽悠了,现场拿钱买了一个什么理财性质的保险。 反应过来不干了,寻死觅活的,结果人家也不给退。 我接到电话后,顺手拿上单反就过去了。具体为啥要带上单反,我也没细想,可能是想万一起冲突了能拿来录个像啥的。 到场之后先安抚好姨妈的情绪,然后肯定是要找他们现场最大的领导,几个人进了一个会议室协商。 有个人沉不住气了,开始旁敲侧击地问我是干什么工作的,时不时还打量我的胸前的大照相机。 哈哈,这样我可就入戏了。 我也不说自己是干啥的,装作讳莫如深的样子,但是话里话外就当作自己是一个调查记者! 压根不提我姨妈的事儿,我就只关心为什么银行里会有人在卖保险、卖保险的人是谁给放进来的、顾客是不是能清楚地知道他们是两家机构、这种做法是不是一种普遍现象、像我姨妈这样的案例是不是有很多…… 我当时大概是一副过两天就准备把他们捅到《焦点访谈》的样子。 反正后来感觉那个大领导吓得够呛,我姨妈的事儿自然也就解决了。由于保险第二天才能退,他甚至主动拿自己的卡取了5万块先垫付给我姨妈。第二天我姨妈又过去了一趟,退了保险才把钱还给了他。 二 2020年初春,在我老婆娘家村里,疫情的原因封村了。 封了有大约一个月以后,因为家里有1岁的小朋友,当时纸尿裤也快用完了,也很久没吃上肉了,听人说可以去村委会开临时通行证出去采购,我就赶紧去了。 显然不可能那么顺利。 村干部趾高气昂地给我一顿教育。当然都是些老生常谈了,什么人人都过来开通行证工作没法开展啦,领导干部们也都很艰苦啦,还说为了防疫大局,只要饿不死就在家里好好呆着。 当时我也是上头了,掏出手机,开录! 镜头对着我们的大领导,我配画外音:“我现在在xx市xx村……”,然后渲染下条件艰苦生活困难,再引用一下中央说要保证人民生命安全和身体健康的最高指示,重点批判一下”只要饿不死就不管“的说法。 分分钟上微博热搜的姿势。 然后村干部明显怂了……只说让我别拍,给我发通行证就是了。 依稀记得我还补了下刀,漫不经心地问我们这村是属于哪个乡镇的,上面的领导是谁什么的。 实话说,这事儿的处理其实是冲动了,疫情笼罩之下情绪太大,不值得学习,毕竟我老婆他们家在那个村里,抬头不见低头见的,真闹僵了不好。 事情的后续是过了快一星期之后,我老丈人跟我说,他们村支书还在打听我在北京是在什么单位,干什么工作的……

怎么做一个匿名论坛

2022-03-21 08:00:00

支持使用匿名的方式表达对公司各项政策的意见,是我司的一项光荣传统,然而在具体操作过程中,也出了一些问题和波折。 最初很长一段时间我们使用的是Slido服务,这个网站的本意是用来在公开演讲的时候观众向主持人提问的,我们发现用它来做一个匿名论坛也是不错的。 随着公司发展,人数逐渐变多,slido的一些问题也暴露出来了。最为明显的是它是没有注册的,用户只需要自己填写一个id就可以穿上马甲进论坛了,因为id信息只记录在cookie中,我们可以简单地通过浏览隐身窗口给自己套上多个马甲,这样随便一个有心人就能搞出声势浩大的样子。显然,它保证不了“一人一票”这个最基本的民主诉求。另外还有一个巨大的风险:万一出现诽谤诬陷等涉及违法犯罪的消息,我们是没有任何兜底方法去把对应的人找出来的。 后来我们的办公套件用上了先进的飞书,然后匿名论坛也换成使用飞书自带的“公司圈”,它使用了比较经典的“前台匿名,后台实名”模式,即每个人的身份和马甲有一一对应的关系,只不过这个对应关系没有人有权查看,除非出现涉及违法等少数特殊情况。 不得不说,这种模式很好地解决了slido的两个主要缺点。但它也并非完美,抛开“我们是否能信任大厂和大厂员工的职业操守”这种根基性问题不谈,实践中因为实名与匿名的对应关系实际遍布在服务器进程的整个内存空间,需要通过精细的业务逻辑控制不让这层对应关系在前台泄漏,其实很容易一个bug就直接交待了。 这里以我自己发现的一个bug为例来试说明严格保持身份信息不暴露的难度:当用户给匿名论坛中发布的实名评论点赞,并且将评论点赞成热门评论,此时热门评论里会以实名信息显示点赞列表,同时实名评论的作者收到的点赞通知内的用户名是匿名的,于是整个点赞列表的身份信息就全暴露了。 上面的例子还隐含了一个相对隐晦的问题:不同用户所能看到的界面和掌握的信息不一样,身份已经暴露的用户可能完全不自知。这里可以展开再举个例子,所有人都知道即使是论坛管理员也看不到用户身份信息,但是大家不知道的是管理员是可以在后台看到所有的发贴和删贴记录的。实际上我隔三岔五就能在后台看到有人先是用实名发了一贴,然后意识到自己忘了切匿名,于是删帖并用匿名再重新发一次……只要我不主动说,他们不会意识到他们已经是纯裸奔状态了。 故事讲差不多了,我们来从头梳理一下做一个靠谱实用的匿名论坛到底应该怎么做。 1. 真匿名 相对于“前台匿名,后台实名”,真匿名即实名信息不存放在服务器或数据库中。假匿名的问题其实不只是出bug会泄密,还有比如被黑客手段拿到数据,或者DBA监守自盗,风险无处不在,最安全的就是直接没有实名信息,也就无从泄漏了。 2. 一人一账号 这个是民主的基本诉求。思考一下会发现“一人一账号”和“真匿名”是有些矛盾的,意味着至少在注册阶段,账号需要跟实名有一些联系(不能做成slido那样)。 一种比较简单直接的做法是“抓阄”:根据总人数提前创建好X个账号,打印成纸条塞到一个大布袋里,每人摸一个就完事了。 现实情况会更复杂一些,比如公司的员工列表不是一成不变的——不断有人加入有人离开。不管是入职当天发放账号,还是入职累积够一定人数后组织发放,账号的激活时间都泄漏了真实身份相关的部分信息。 可能的改进方法是每隔一段时间(比如半年),作废所有账号,来一次全员重新发放。这么做的缺点是用户在匿名状态下维护的“人设”没了延续性,体验不太好。 另一种办法是放弃严格的一人一账号,每半年所有人都可以重新申请领取账号。这么做老员工手上会有多个号,有效利用会有更大的话语权,这个看怎么理解了,可以认为是一种福利。这么做的另一个好处是,万一不小心人设崩塌了,总是有重新来过的机会。 此外要考虑“抓阄”的可操作性问题,尤其是我们公司是分布式办公的,不可能把所有人聚到一起,如果分办公室来也面临泄漏部分身份信息的问题。因此我利用所学不多的密码学,想了一种可以在网络上完成了方法,我愿称之为“赛博抓阄”。 赛博抓阄 参与抓阄的每个人自己用 rsa 生成密钥对,把公钥提交进系统。 组织方以直播的方式运行一个脚本:这个脚本在内存中生成X个rsa密钥对,公钥直接保存进匿名论坛账号数据库,私钥在内存中随机打乱顺序,然后分别使用步骤1中提供的1个公钥加密后保存进文件。因为打乱后私钥的顺序只在存在于内存中,脚本退出后就无迹可寻了。 每个人用自己的私钥解开步骤2中使用自己的公钥加密后的密钥,可以得到一个账户私钥,用于之后的匿名论坛登录。 为了提高第2步中的可信度,我们可以当场 review 代码(应该不会长),还可以现场去 aws 等平台申请一台服务器来排除环境污染的风险。 3. 特殊情况可以追查实名信息 这个是为了应对法律风险。这条规则看起来似乎跟“真匿名”的矛盾更显然,不过我们只要保证把实名信息(也就是“抓阄”记录)存放在匿名论坛系统之外就没问题了,而且为了安全,我们可以选出若干个民意代表,规定查看实名信息需要至少X人同意。 这个在密码学上也是可以做到的,使用秘密分享加密方法,把实名信息拆成N份,并且还可以设置到时候解开信息需要至少X人提供密钥。 4. 操作记录透明公开可追溯 匿名论坛可以允许有不同角色和权限,但是不同人所能观察到的信息应该是一致的,否则其根基性的身份安全将受到威胁,极端情况就是前面说过的裸奔而不自知。 另外,匿名论坛的帖子不能删除,不能修改(如果允许修改则应保存修改记录)。这个规则同样是为了保证不同人观察到的信息是一致的,不应该因为某个人在特定的时间打开了论坛就掌握了更多信息。 5. 紧急逃生通道 如果用户发现自己不小心身份暴露或者人设崩塌,可以使用一键逃生功能,停用账号并销毁自己的所有记录。这条乍看来跟上一条是有矛盾的,但是从更底层的逻辑上来说,第4条是为了避免用户身份暴露而不自知,这一条是为了用户身份暴露的情况下减少损失,两者都是为了用户能更有安全感地畅所欲言。 6. 信道安全 为了打消用户对公司内网(或远程VPN)网络监听的顾虑,匿名论坛应该部署在公开网络。这样可能会涉及到离职员工账号的问题,可以考虑给论坛多设置一个定期更新的全局密码,或者干脆定期更新地址。 总结 感觉其实不怎么难,有时间可以考虑做个原型,先挖个坑。

适合程序员的桌面窗口管理方案

2022-03-15 08:00:00

介绍下我在办公室使用的桌面窗口管理方案。 先说下硬件:我的工作电脑是一台 13 英寸的 Macbook Pro,外接了一个 27 英寸的显示器,使用了一个电脑支架把笔记本架起来了,这样两个显示器差不多是并排的样子。 然后看下我的窗口布局规划,可能会比较特殊一点,不过是经过精心考虑的。 桌面布局示意 右边的大显示器我按 1:2 分成两列,左边这一列是最大的显示空间,我把它当作“主空间”来使用,一般我在编码状态下会把编辑器放在这个位置,非编码状态下这里通常就是浏览器了。因为本来两个显示器的大小是不一样的,这样进行划分,主空间两侧的空间反而是比较均衡的状态了。显示器和电脑屏幕在桌子上的摆放也是非对称的,当我坐下时,正对着的是这个“主空间”的正中央,这样也避免一个常见问题:两个一样大的显示器对称排布时,正对着的位置恰好是两个显示器中间的缝,于是工作中几乎时刻是扭着头的,时间一长脖子就受不了了。 左边笔记本的屏幕没有做切分,这块空间一般在编码的时候放浏览器看文档资料,或者放个 Terminal 调试,也可以是另一份代码,使用完整的屏幕保证它总是够用的,不至于不得不把窗口拉大然后频繁切换窗口。 大显示器右边的 1/3 被一分为二,这两块空间主要用来放IM软件,包括飞书、Telegram、微信、QQ、Twitter桌面版……IM软件也平铺出来也是为了减少切换窗口,我只需要在干正事的时候时不时瞟一眼就行了,有需要关注的消息时再去处理。必要的时候这个小格也可以临时放一下 Terminal 之类的小窗口。 再说窗口管理软件方面,可能我的搞法比较变态,我也没找到合适的软件,最后使用的方案是 HammerSpoon 一点脚本,HammerSpoon 大体上就是 Mac 版的 AHK,功能是弱了很多,不过在窗口管理这一块还是完全够用的。我的脚本很简单,使用 4 个快捷键,分别把窗口移动到 4 个格子: 1hs.hotkey.bind("cmd", "1", function() 2 local sf = hs.screen.primaryScreen():frame() 3 hs.window.focusedWindow():setFrame(hs.geometry.new(sf.x, sf.y, sf.w*2/3, sf.h)) 4end) 5 6hs.hotkey.bind("cmd", "2", function() 7 hs.window.focusedWindow():setFrame(hs.screen.allScreens()[2]:frame()) 8end) 9 10hs.hotkey.bind("cmd", "3", function() 11 local sf = hs.screen.primaryScreen():frame() 12 hs.window.focusedWindow():setFrame(hs.geometry.new(sf.x+sf.w*2/3, sf.y, sf.w/3, sf.h/2)) 13end) 14 15hs.hotkey.bind("cmd", "4", function() 16 local sf = hs.

Go语言泛型初体验

2022-03-11 08:00:00

Go1.18rc1 放出来也有一段时间了,我们期待了多年了泛型的支持终于是要实装了,毕竟已经是RC,后面语法应该不会再大动了,所以决定提前来学习一下。 前几年曾经用Go语言移植了C++ STL的迭代器和算法库(disksing/iter),因为当时没有泛型,所以基本上是 interface{} 和 type assertion 满天飞的状态。这次我就用它来学习泛型,试着改个泛型版本出来。在C++里面,迭代器和算法这块可以说是泛型应用的典中典,所以我觉得要是能把它给改完,应该能说明实用程度是足够的了。 先说结论吧,我觉得这一版至少可以打85分。中间确实也遇到一些障碍和小的体验问题,但是瑕不掩瑜,它在“保持简洁”和“提供更完善的功能”间保持了非常好的平衡。几乎不需要了解什么额外的概念和实现原理,就凭着自己对泛型朴素的理解,就能比较顺利地上手了。 最简单的基础用法这里就不多说了,有兴趣的话可以参考下官方blog的那篇文章。这里仅挑我遇到的几个问题分享一下。 自指 有时候我们需要在 interface 中定义与具体类型相关的方法,比如 Copy() 用于复制一个同类型的对象,或者 Next() 用于返回指向下一个位置的迭代器,又或者 Equal() 用来和同类型的对象进行比较。 在 Rust 里面有一个 Self 来解决这个种问题。在 impl 的时候,你的具体类型是啥,就返回啥。 1trait Copyable { 2 fn copy(&self) -> Self 3} 在 Go 里面,没有泛型之前,我们一般是这么干的: 1type Copyable interface { 2 Copy() Copyable 3} 不过这不是泛型,只是一个常规的 interface。我们在实现具体 struct 的时候,Copy() 只能返回 Copyable 而不能用具体类型,在使用的时候还需要强转一下。 1type myType struct{} 2 3func (t myType) Copy() Copyable { 4 return myType{} 5} 6 7func main() { 8 x := myType{} 9 y := x.

双中心主从模式

2021-09-11 08:00:00

在之前的Paxos从入门到学会Raft一文中,为了引入paxos/raft共识算法,简单地讨论了一下主从模式以及为什么主从模式不能最大限度地同时保证高可用和一致性。不过在现实场景中,常常因为基础设施不足,网络成本控制等原因,无法使用需要三中心的paxos/raft,所以我想再详细讨论下只有两中心的场景下的妥协方案。 简单回顾下上次的讨论:在两中心主从模式下,我们如果想要主从切换时不丢数据,就必须使用同步模式,即主中心写入的数据,需要同步到从中心落盘,再给客户端返回写入成功。 同步模式的困境在于,从任何一个中心的视角来看,都无法区分出“另一个中心故障”和“两中心网络断连”这两种异常情况。这导致主从模式下的failover是一定无法由程序自动进行的: 如果主中心在发现从中心故障(或断连)时自动切换至独立运行(异步)模式,那么当主中心发生故障时,从中心无法切换至独立运行模式,因为从中心无从判断主中心是真故障了,还是网络断连了(这种情况下主中心可能已切换至独立运行模式)。 反过来如果我们让从中心在发现主中心故障(或断连)时自动切换至独立运行模式,同样的道理,我们也无法处理从中心故障的情况。 这里我们面对的是一个经典的CA抉择问题,大方向上有两个选择。 第一个方向是优先保证一致性,一旦出现故障或者网络断连了就主动停止服务,由运维来选择一个中心来恢复服务。我们都知道,一旦需要人工介入,高可用性这块基本上就免谈了。还有一个可能产生麻烦的点在于在发生故障的前提下(且可能是网络故障),或许会给运维人员接入生产环境带来一定的困难,这也会进一步增加故障恢复时间。 另一个方向就是优先保证高可用。典型的做法是主中心在发现从中心故障(或断连)时,自动切换成异步模式提供服务。如前所述,一旦主中心故障,就需要人工干预来进行主备切换了。要特别注意这种情况下主备切换不仅比较tricky还有丢数据(不一致)的可能,以下两段划重点: 主备切换之前,需要先把主中心的服务给“掐掉”,因为主中心是有自动切换异步模式单独服务的机制的,如果在主备切换之后假性故障的主中心死灰复燃,两个中心同时提供服务,会产生非常严重的后果!那么怎么把主中心的服务掐掉呢?如果此时能接入主中心,可以直接停掉所有进程或者通过配置开关禁用自动切异步模式的功能;还可以通过网关、防火墙等配置断开应用和主中心数据服务的连接;另一个选项是在应用层做主备切换,保证所有应用都只连接从中心的服务。如果这些都做不到,此时做主备切换就要承担很大的风险了,建议上报给老板做决策。 主从数据可能不同步。理论上讲在同步模式下主中心发生故障,从中心一定有全量数据。但是实际上如果此时不能接入主中心检查状态,我们单看从中心无法排除这种可能性:主中心在完全故障之前,先跟从中心发生网络断连,随后自动切换异步模式并写入了一些数据。因此,做主备切换之前,除非能接入主中心并确认其没有切换过异步模式,还要承担丢数据的风险,这里同样建议您先上报老板。 工程实践中,C和A并不是非此即彼的选择题,常常有权衡的空间。在双中心主备切换的场景中,我们可以牺牲一些可用性来换一些一致性。 做法也很简单,就是给主中心切换异步模式设置一个比较大的超时时间,比如30分钟。这样当从中心故障时,主中心需要等待30分钟才能独立提供服务,牺牲了可用性。换来的一致性保证是,当主中心故障(或断连)时,如果我们在30分钟之内做主备切换,就能确定一定不丢数据。 具体的超时时间可以根据需要进行调整,很大的值其实就是一致性模式,很小的值对应的是高可用模式。看到这里熟悉Oracle的朋友们应该都会心一笑了,这其实就是DataGuard的maximize protection模式和maximize availability模式嘛。 接下来简单聊一下架构层面改进的两种思路。 第一个思路是向三中心架构推进一步。开头也说了使用paxos/raft三中心的主要问题是成本太高了,然而实际上不需要完整的三中心三副本也能达到比较好的效果。主备模式的主要缺陷在于两个数据中心的地位是完全对等的,出现网络隔离的时候无法判断对面是不是真挂了。 我们可以在第三个数据中心部署一个简单的etcd服务来扮演“仲裁者”的角色,在主从中心正常工作的时候,不需要与etcd作任何消息交换,发生故障时,哪边能连上etcd,哪边就有权切换成独立服务模式。假如主从网络断连,同时它们又同时能连接到etcd,那么主中心切换成异步模式并把状态信息通过etcd传递到从中心。 由于跟第三个数据中心之间只需要传递简单的状态信息,可以考虑使用移动网络、无线电或者卫星通信(如北斗短报文)来进一步减少成本。 另一个思路成本更低一些,不使用第三个数据中心,直接在主从中心之间建立低成本旁路通信同步状态。这时因为没有“仲裁者”了,在出现整个数据中心故障时仍然会陷入“两难”的境地,不过在发生网络故障时,主从中心可以通过旁路进行状态交换然后迅速进行异步模式切换。 最后来点主题升华哈。权衡是软件工程架构设计的最经典命题之一,绝大部分情况下都没有完美的设计,只有特定约束条件下最平衡的设计。诚然,一个又一个“不可能三角”告诉我们完美的系统是不存在的,但换个角度来看,不可逾越的鸿沟也是可以去不断逼近的极限,这就是工程师的浪漫呀!

TrueTime和原子钟

2021-02-10 08:00:00

如果你关注分布式数据库,相信多少听说过Google的分布式数据库Spanner,以及Spanner使用原子钟搞了一套TrueTime来实现跨数据中心的分布式事务。 而Spanner的后继者们,却都采用了不使用原子钟替代方案,比如TiDB的TSO,CockroachDB的HLC。对此很多人的印象就是Google财大气粗,所以有能力搞原子钟这种精密高端设备。这个说法不能说全错,但至少不是完全准确的。 网络时钟同步 上面提到的3种取时间戳的方式的底层逻辑是迥然不同的。TiDB的TSO是中心授时,每一个时间戳都要从中心服务器获取;CockroachDB的HLC本质上是逻辑时钟,依赖于消息交换时去推进时钟计数器;Spanner的TrueTime是时钟同步,通过定期交换消息,把本地时钟与源时钟进行同步。 时钟同步的模式跟我们日常用手表的方法是类似的,我们隔一段时间把手表跟新闻联播同步一下,期间的时间直接从手表上读出来。 计算机里面最常见的时钟同步就是NTP了,通过网络同步时钟有个问题就是延迟导致的误差。 网络同步时钟 比如客户端在12:00:00发起查询请求,2秒钟后收到服务器的消息,返回的时间也是12:00:00。这时并不意味着本地时钟是准确的,因为消息发到服务器要花费时间,本地时钟实际上是快了一点。但是具体快了多少是没法知道的,我们只知道消息一来一回花了2秒,却不知道来回分别花了多长时间。因此只能大概估摸着取个中间值,把时间往回拨1秒,这时误差范围就是±1秒了。 Marzullo算法 只从单一时间源同步时间是不够靠谱的。除了有可能发生故障或者网络中断,更可怕的是时间源本身就出了问题。Marzullo算法就是用来从多个时间源来估算准确时间的算法。 Marzullo算法 如图,我们通过向ABCD四个时间源查询时间分别得到时钟偏差及误差范围,算法的大体思路就是选被尽可能多时间源所覆盖的区间(缩小误差范围),并排除掉有问题的区间(如A)。 不过,在对时序有严格要求的场景(比如分布式事务),Marzullo算法还要进行一些改良。例如比较明显的缺陷是,当有问题的时间源offset区间与正常的区间有交叠时,可能导致误差范围被估算得过小。如果想了解相关细节,可以去研究下相关资料,这里不展开了。 时钟漂移 跟服务器对上时间了还没完,通常对时的过程都要周期性地触发。正如我们的手表用着用着就不准了,CPU的晶振周期也不是完全精确的,会受温度和电压的影响,时间一长也会“跑偏”。 Spanner假设他家服务器的误差不超过每秒钟200μs。按最大值去计算,30秒不同步,误差最多会累计到6ms,如果1天不同步,最大误差达到约为17s。要注意这里的误差范围是非常非常保守的,实际情况CPU远不可能这么糟糕,举个例子对比一下,我国石英电子表的行业标准是,一类月差10-15秒,二类月差20-30秒。 原子钟 原子钟,是一种利用原子、分子能级差为基准信号来校准晶体振荡器或激光器频率,以使其输出标准频率信号的一种装置。它的工作原理是:利用原子吸收或释放能量时发出的电磁波来计时的。由于这种电磁波非常稳定,再加上利用一系列精密的仪器进行控制,原子钟的计时就可以非常准确了,可以达到千万年仅差一秒或者更好的水平。 —— 时间频率:5G 叠加自主可控, 被忽视的高精尖领域 看上去确实很高端,那么假如想买这样一个原子钟要多少钱呢?实际情况是原子钟比听上去亲民的多,我们直接在东哥的网站上就能搜到: 京东商城售卖的原子钟 售价大约是几万到十几万不等,并非承受不起的昂贵,和一台高端点的服务器是差不多的价位,如果降低精度的要求还能更便宜。 说白了原子钟和计算机上面随处可见的晶振就是同一类东西,只不过精度高了好几个数量级。 不同硬件的计时精确度 需要注意有些同学误认为TrueTime需要每台机器都要给配一个原子钟,其实不用,一个数据中心有几个就完全足够了,具体先按下不表后面再说。 GPS授时 GPS不仅提供定位服务,还可以授时。每个GPS卫星都携带了数个高精度原子钟,并不断广播星历(运行轨迹)和时间。地面装置从至少4颗卫星接收到信号后,解开以三维空间+一维时间为变量的四元方程组,就能同时拿到时间空间信息了。 GPS的精度非常之高,可以把误差控制在数纳秒以内。这是因为电磁波信号基本上是直线传播,路径上受到的干扰很小,根据距离可以很准确地计算出信号传递延时。而网络消息会受中继和多层网络层层封包的影响,而且即便在光纤中,信号也不是沿直线传播的。 TrueTime 背景知识介绍完毕,下面我们就来看看TrueTime到底是怎么做的。 机房内的TrueTime组件部署 TrueTime组件按角色分成 time master 和 time daemon。time master 可以认为是 TrueTime 的服务端,部署在一些独立的机器上,time daemon 是客户端,以进程的形式部署在每个实际运行业务的主机上。 time master 又分成两类。一类安装 GPS 模块,分散在机房的不同位置,每个GPS节点都使用独立的天线,避免因为信号干扰的原因一起失效了。另一类安装的是原子钟,原子钟也是多台来防止故障产生不可用。 各种 time master 周期性地使用Marzullo算法相互对时,每个 time daemon 也会以 30 秒为周期跟多个 time master 进行对时(同样使用Marzullo算法)。 之前介绍过,GPS 的精度是纳秒级别的,这个误差跟机房内的网络延迟比起来都可以忽略不计了,直接计作0ms。这样time daemon进行时钟同步之后的误差就仅仅取决于网络延迟了,一般机房内不超过1ms。 我们还要考虑到完成时钟同步之后,到下一次同步期间time daemon的时钟漂移,也就是前面计算过的,30秒内最大误差可能累计到6ms。于是,time daemon上的时钟误差范围就在1ms到7ms之间不断涨落,画出来是这样的锯齿状: time daemon误差范围变化示意 那么问题来了,原子钟是干啥用的?