Xargin

If you don't keep moving, you'll quickly fall behind

righting software 读书笔记

《righting software》是 Pearson 出版社 2020 年出版的一本书,作者是 Juval Löwy,今年国内也引进了这本书,中文名是《架构之道》。 中秋期间读完了这本书里我比较关心的部分,本文将其中的一些核心观点进行摘录。 作者首先总结自己几十年的经验(先表达一下羡慕),提出了靠谱软件的设计方法,称为 The Method(中文译成了元方法): The Method = System Design + Project Design 这本书也就被分成了这两部分,System Design 和 Project

关于复杂度的一些想法

之前陶师傅推荐过这么一篇文章,Complexity has to live somewhere,大致意思是系统的复杂度是没法凭空消失的,只能从一个地方转移到另一个地方,因为现实世界的逻辑就是那么多,边边角角的 case 就是那么多,你必须要处理,这必然会给系统引入复杂度。 尽管这些复杂度你可以转移给你的同事,或者外包给第三方系统,但复杂度是不灭的。 设计系统时,我们要注意到这一点,同时要管理好复杂度问题。 在《a philosophy of software design》这本书中,作者也提出了一个不一样的,比较有意思的系统复杂度理论, 可以和上面那篇文章结合在一起来看。 C 代表 Complexity,

云原生如何使我们失业

本人现在暂时是无业状态,所以本文不代表任何雇主观点。 到了 2021 这个时间点,大多数公司都决定拥抱云原生,但不少程序员对云原生的理解局限于“原生基于 k8s 的应用”。公司只要上云(k8s)了,就是拥抱云原生了。稍微理解多一点的人觉得除了 k8s,我们只要上了 service mesh,就是拥抱云原生了。 cncf 给云原生的定义其实非常地庞杂: 云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,

简单看看 Go 1.17 的新调用规约

Go 1.17 修改了用了很久的基于栈的调用规约,在了解 Go 的调用规约之前,我们得知道什么是调用规约。 x86 calling convention,简单概括一下,其实就是语言对于函数之间传参的一种约定。调用方要知道我要把参数按照什么形式,什么顺序传给被调用函数,被调用函数也遵守该规范去相应的位置找到传入的参数内容。 老版本的 Go 的参数传递图我们已经在很多很多地方见过了,这里贴一个我之前画的: 可以看到入参和返回值都在栈上,按顺序,从低地址,到高地址排列。 这种基于栈的传参在设计和实现上确实要简单,但栈上传参会导致函数调用过程中数次发生从寄存器和内存之间的参数搬运操作。比如 call 的时候,要把参数全搬到 SP 的位置(这里从寄存器

Google 的 “行星级” cron 系统设计

最近翻看了一些 Google 的老文章/论文,发现 Google 有不少系统的设计文上都写着 planet scale,行星级,口气那是真的大。仔细想想,FAANG 这样能把生意做到全球的互联网公司,除了这五家,也没几家其它的了,人家确实有吹行星级的资本。着实羡慕。 Google 的员工出来创业,公司名也是 TailScale(似乎是做 vpn 的),PlanetScale(这家似乎是拿着 vitess 出来创业的) 这样,说明 ex-googler 也是比较喜欢这家公司的文化的。

《Go 语言高级编程》的故事

截止 2021 年,《Go 语言高级编程》在国内已售出超过 1.6w 册,从技术图书的角度来讲,这本书已经算是成功了,这离不开各位读者的支持,感谢大家~ 2016 年的时候,golang-china 的柴树杉找到我,想要一起写一本书,那时候 Go 在国内已经有了一些起色,Gopher 的活动越来越多了,比如后来每年都在办的 GopherChina,和线下很多 Go 语言的 meetup。 国内不少大公司的业务部门还在犹豫要不要把主语言切换到 Go。 我还在某公司写 PHP,

GraphQL 的限流难题

在 这篇总结 的结尾,提到了 GraphQL 的问题。 之前在某公司落地查询 API 方案时,我们没有选择 GraphQL,是因为: GraphQL 对于数据用户来说有一定的学习成本GraphQL 的稳定性很难做,难以限流学习成本倒也不是特别大的问题,程序员们本能上还是喜欢接触新东西的,这会让他们有一种虚假的获得感。 关键是这个限流问题,是真的很难做,开放 GraphQL 的 API,就像你在 MySQL 上直接开了一个 SQL 接口一样,用 SQL 可以一次只查一条数据,也可以一次查一亿条数据。

微服务架构模式的一点总结

经常翻阅微服务材料的话,总会碰到 microservices.io 这个网站,总结了微服务方方面面的设计模式。网站的作者是 Chris Richardson。 这些相关的经验在 2018 年成为了《Microservices Patterns》这本书,并且 2019 年引进国内。当时我第一时间购入了这本书,不过那时候很懒,所以没看完。最近在准备分享内容的时候又翻到了这本书,这次完整地读完了一遍。感觉应该是目前微服务领域最好的一本书了。另一本《Building Microservices》也不错,不过内容还是稍微单薄了一些。 这本书为我们提供了宏观上俯瞰微服务整个生态的大图,比如: 当然,18

非协作式抢占详解

抢占抢占 # 从 Go 1.14 开始,通过使用信号,Go 语言实现了调度和 GC 过程中的真“抢占“。抢占流程由抢占的发起方向被抢占线程发送 SIGURG 信号。当被抢占线程收到信号后,进入 SIGURG 的处理流程,将 asyncPreempt 的调用强制插入到用户当前执行的代码位置。本节会对该过程进行详尽分析。抢占发起的时机 # 抢占会在下列时机发生: STW 期间 在 P 上执行 safe point 函数期间

关于静态分析的科普

看了看日历,现在已经是 2021 年了,偶尔还是能看到有人在发诸如 《http body 未关闭导致线上事故》,或者 《sql.Rows 未关闭半夜惊魂》类的文章,令人有一种梦回 2015 的感觉。 在这个 Go 的静态分析工具已经强到烂大街的时代,写这些文章除了暴露这些人所在的公司基础设施比较差,代码质量低以外,并不能体现出什么其它的意思了。毕竟哪怕是不懂怎么读源码,这样的问题你 Google 搜一下也知道是怎么回事了。 特别是有些人还挂着大公司的 title,让人更加不能理解。下面是简单的静态分析工具的科普,希望给那些还在水深火热的 Gopher 们送点解药。

换掉 gitalk

为了能和读者互动,之前 blog 一直是有 gitalk 的。 不过 gitalk 似乎是用了 github deprecated 的 API,现在频繁地往我邮箱发邮件,还是很烦的: 之前想换 gitalk 的时候发现并没有什么好的竞品,不过毕竟已经 2021 了,让我发现了这个东西:https://utteranc.es/,还有这个东西:https://giscus.app/。 utterances 和 gitlak 差不多,

为什么大公司里的垃圾系统也能保持稳定

从毕业至今,已经待过四家公司,算上实习期间三月游的公司差不多已经快十家了,时常会碰到一些有意思的言论。 在某司的时候就经常听到人说,“我们在 T 姓巨头的时候”,“我们在 A 姓巨头的时候”,“我们在 B 姓巨头的时候”,以任意一家巨头公司作为观点的前缀,显得观点就特别有分量。仔细想想,实习期间我也是在这些所谓的巨头公司待过的,我怎么就没有想到可以在自己编的故事前面加上这是 X 家的事情,所以还是他们比较机智。 大公司里的平均水平高,牛人多,并不代表进去的就一定是牛人,还有不少认不清是自己强还是公司机制强的混子。 即使是在大公司,也会有很多垃圾系统,他们内部没有限流,没有熔断,没有降级,也没有过载保护。但是他们却不会崩溃,

Go 语言中的一些非常规优化

这次去 Gopher China 和不少老朋友见了个面,还有不少在微信上认识已久,一直没见过面的网友。同时也和各个公司的一线开发们聊了聊,互相交流了彼此使用 Go 时的一些心得和痛点。 综合近期了解的一些相关分享,我把到目前为止见到的,不那么常见的,各方对 Go 的优化和 hack 集中在这篇文章里。因为考虑到一些公司情况比较特殊,所以本文中列出的点就不标记是哪个公司做的了。未来他们觉得时机成熟应该也会自己出来做一些分享。 网络方面 当前 Go 的网络抽象在效率上有些低,每一个连接至少要有一个 goroutine 来维护,有些协议实现可能有两个。因此 goroutine 总数 = 连接数

用 litmus 验证 x86 内存序

前置知识在这里。 在 stackoverflow 上有这么一个问题,问题的答案中有这么几段: At the same time, x86 defines quite a strict memory model, which bans most possible reorderings, roughly summarized as follows: Stores have a single global order of visibility,

用 MQ 解耦其实是骗你的

有一个观点已经被说烂了:使用 MQ 可以帮助业务系统解耦。 想法很简单,在业务状态流转时,如果没有 MQ,那么其它系统想要知道状态变了,那就需要核心流程系统去主动做通知。 比如电商系统里订单从创建到处理中状态切换了,客服系统需要知道,风控系统需要知道,用户系统也需要知道。 这里的通知通过 RPC 来进行,下游系统需要的数据可以在这次 RPC 里携带上,也可以在请求的时候让下游系统自己去查。 下游系统增加的时候,核心业务的代码也需要修改,比如新做了一个积分系统,现在订单状态流转积分系统也想知道。 核心系统需要不停地增加调用关系来迎合下游新增的业务方需求。这些边边角角的计算逻辑和订单系统本身没啥关系,但是因为下游需要拿到这些数据,我们就需要自己用 RPC 去调用下游的接口。这确实不太合理。 当下游系统发生事故时,

nocode 和 lowcode

今年不少业务开发像突然被开了光一样开始讲 nocode 和 lowcode,可以看出现今的互联网可能真的是编不出什么好故事了。 在之前的文章里,我们已经讲过自动化、平台化和中台化了,不管业务模式怎么变,企业内总还是有一些局部系统最终能够把开发模式沉淀下来,变成拖拖拽拽就可以进行变更的“网页制作大师”系统。 像阿里这样的公司,中台落地并迭代多年以后,核心业务的流程变化其实并不会有太多的编码任务,从内部资料来看,套用以往的业务模式,改改配置或者上上活动,基本不需要程序员去做开发了。 不管我们在哪个公司,只要我们按照《在业务系统中寻找技术含量》这篇文章的思路去做系统,最终一定能够将大部分繁琐的重复劳动做到自动化。二八定律,就是可以将那 80% 的重复劳动用界面化、系统化、流程化的手段完全消灭掉。剩下的 20%

Fail at Scale

Fail at Scale 是 Facebook 2015 年在 acm queue 上发表的一篇文章。主要写了常见的线上故障和应对方法,内容还是比较实在的。 "What Would You Do If You Weren't Afraid?" 和 "Fortune Favors the Bold." 是 FB 公司信条,挂墙上那种。

The Tail at Scale

The Tail at Scale,是 Google 2013 年发表的一篇论文,大规模在线服务的长尾延迟问题。 要知道怎么解决长尾问题,先要理解长尾延迟是个什么问题,在开发在线服务的时候,我们都知道要关注服务的 p99/p999 延迟,要让大部分用户都能够在预期的时间范围内获得响应。 下面是一个不同响应时间的请求数分布图: 大部分系统也都遵循这种分布规律,现在互联网的系统规模比较大,一个服务依赖几十上百个服务的情况都是有可能的。单一模块的长尾延迟会在有大量依赖的情况下,在服务粒度被放大,《The Tail at Scale》论文里给出了这样的例子。 考虑一个系统,大部分服务调用在 10ms 内响应,但

那些画图工具们

偶尔讲讲工具,放松一下。 现在写技术文章不但要写技术细节,图还得画的好看。对于表达思路和架构来说,图确实挺直观的,这篇文章介绍一下常见的绘图工具。大家可以看自己的喜好自行选择。 在早期写 golang-notes 的时候,想要向那些写 RFC 文档和早期的 unix 大神们致敬,所以比较喜欢 ascii 图,这种图的好处是你可以直接将图表内嵌在文档内部,不需要有附件。有利于单文件传播。 用来画 ascii 的图工具有不少。 textik textik 是一个在线项目:https://textik.com,可以直接在线绘制 ascii

《写作的逻辑》简单读书笔记

写作是单向沟通,读者读不懂,说明是作者没有写好。 作者自认为的前置知识,可能在读者角度是不懂的。 文章易懂,需要对读者的心智模型有一点了解。 用总分或总分总的结构去写文章和做演讲;因为大家时间有限,可以根据你的总论判断是否要读下去,工作汇报演讲结论先行。 观点不宜太多,如果太多,尽量划分到 3 类里。 用段落组织文章,而不是句子(一些娱乐性的文章,可以用句子来组织。 每段只写一个主题。 每段开头是一句概要描述,后面段落补充细节,每段大约 4 - 8 个句子,不要太长。这样读者可以跳跃阅读你的文章。 概要还要负责段落之间的承接功能,比如政府财政紧张,第二段是要提高效率,

大型系统在线问题诊断与定位

本文是武汉 gopher meetup 的分享内容整理而成,分享内容在“无人值守”的两篇和其它社区分享中亦有提及。(也就是说你看过那两篇,这个可以不用看了) 先来看看苦逼的开发人员 老板说: 队友说: 外组同事说: 底层团队说: 你: 业界的思路? 混口饭吃也是不容易,既然有问题了,我们还是要解决的。要先看看有没有现成的思路可以借鉴? Google 在这篇论文里提到过其内部的线上 profile 流程: 架构图已经比较简单了,线上应用暴露 profile 接口,collector 定时将 profile 信息采集到二进制存储,由统一的在线平台展示。

随便说说 living documentation

几年前在 oreilly 看到一本叫 《living documentation》的书,可惜当时烂尾了。 最近图灵出版了该书的中文翻译版,才想起来有这么回事。。。正好最近有时间,把这个坑了几年的东西给填上了。 简单来说,这本书基本可以叫 living java doc(误。我们可以先看看日常开发中会涉及到哪些文档: 需求文档 接口文档 业务词汇表文档 模块业务流程文档 系统间交互文档 系统架构文档 系统依赖文档 发布文档 示例文档(tutorial) 项目进度文档 案例文档 汇报文档 要写的类型文档还是不少的,无论哪种文档,

一种持锁被调度的情况

在给某个项目做长时间极限压测的时候,经常会出现压几小时不出问题,突然就崩了的情况。 查看监控发现崩的时候 goroutine 突然涨起来了,那么可以用我之前开发的问题诊断工具了,配置下面的策略:若 goroutine 突然开始暴涨,则将 goroutine 文本 dump 下来。对这个诊断工具不了解的,可以看看我之前写的 无人值守的自动 dump-2 和 无人值守的自动 dump。 代码集成好之后再压,发现崩溃时,总是有很多卡在锁上的 goroutine: 10760 @ 0x42f81f 0x4401d9 0x4401af 0x43ff4d 0x474df9

Go 应用的性能优化

为什么要做优化 这是一个速度决定一切的年代,只要我们的生活还在继续数字化,线下的流程与系统就在持续向线上转移,在这个转移过程中,我们会碰到持续的性能问题。 互联网公司本质是将用户共通的行为流程进行了集中化管理,通过中心化的信息交换达到效率提升的目的,同时用规模效应降低了数据交换的成本。 用人话来讲,公司希望的是用尽量少的机器成本来赚取尽量多的利润。利润的提升与业务逻辑本身相关,与技术关系不大。而降低成本则是与业务无关,纯粹的技术话题。这里面最重要的主题就是“性能优化”。 如果业务的后端服务规模足够大,那么一个程序员通过优化帮公司节省的成本,或许就可以负担他十年的工资了。 优化的前置知识 从资源视角出发来对一台服务器进行审视的话,CPU、内存、磁盘与网络是后端服务最需要关注的四种资源类型。 对于计算密集型的程序来说,优化的主要精力会放在 CPU 上,要知道 CPU 基本的流水线概念,知道怎么样在使用少的

在业务系统中寻找技术含量

从进入互联网公司开始工作起,每个人都在问自己,CRUD 到底有什么技术含量? 别觉得 CRUD 只是业务工程师的问题,无论你在写什么程序,基本上都是在和数据打交道,除了读就是写。只不过读写的时候还会附带一些领域相关的行为。比如: 编译器:读文本,做 parse 网络程序:读连接,decode,encode,写连接 数据库:从磁盘上读,从内存里读,向磁盘里写,向内存里写 工程上,谁也没有权力鄙视谁,你觉得领域的技术含量高,只不过是领域内的工作做的人少罢了。不管门槛多么高的工程领域,只要工程师红利们蜂拥而至,总有一款内卷适合你。

一些 eink 设备

工程师是一个需要大量阅读的岗位,读书、读文档、读论文、读技术新闻,现在大部分电子设备都是 LCD 或 OLED 屏幕,对眼睛的伤害非常大。 因为行业的特殊原因,有时我们会一天花 13-15 小时使用各种电子设备,工作时间长的人很容易眼睛疲劳,严重的可能还会患上干眼症。 能够缓解这个问题的是市面上用户比较少的 eink 设备,比如 kindle: 目前 kindle 最新的设备是 oasis 3,7 寸屏幕 300 PPI,如果只做纯文字阅读,kindle

go mod 之痛

从 rsc 力排众议设计并将 go mod 集成在 Go 语言中,已经两年过去了,时至今日,广大 Gopher 还是经常被 go mod 相关的问题折磨。 本文会列举一些我和我的同事使用 go mod 时碰到的问题,有些问题是 go mod 本身的问题,有些可能是第三方 goproxy 实现的问题。 如果你做过比较大型的 go 项目开发,相信总会有那么几个让你会心一笑。 Go 命令的副作用

why do we need generics?

Go 社区之父早期提到过 less is more 的哲学,可惜社区里有不少人被带偏了。 每次 Go 增加语法上的新特性、新功能,就会有原教旨主义者跳出来扔出一句 less is more(或者也可能是大道至简),扬长而去,留下风中凌乱的你。 即使到了官方已经确定要增加泛型功能的 2020 年,依然有人煞有介事地写文章说为什么 go doesn't need generics,作为理智的 Gopher,最好不要对别人的结论尽信,至少要看看其它语言社区怎么看待这件事情。 Java 社区是怎么理解泛型的必要性的呢? 简而言之,

开源说线上分享

当前互联网公司的后端架构都是微服务化的,服务彼此使用 RPC 通信,与业务无关的功能部分会从业务代码中抽离为框架。 框架提供了基础的 RPC 功能,同时需要对稳定性负责,一个微服务框架包含但不限于以下功能: 路由 限流 熔断 负载均衡 服务注册与发现 tracing 链路加密 这些功能看起来也是通用且稳定,所以我们对一个框架的印象往往是成型了之后便很少再升级了。但是云原生时代将我们的假设击得粉碎。底层基础设施也开始迅速发生变化,例如: 物理机集群 -> k8s 集群,破坏了我们的服务实例 ip 不会变的假设 基础设施给服务的资源分配方式发生变化,超卖使以往未经审慎设计的代码在恶劣环境下更易崩溃 服务数量的爆炸式增长使每个内部的微服务都要面对
京ICP备15065353号-1