Xargin

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

生于非阻塞,死于日志

metrics 上报在高并发时会带来性能问题,为了解决问题,有时反而又会带来别的问题。 举个例子,一般的 metrics 上报代码可能是下面这样: // when request in metrics.Req(caller, count, latency) 内部实现一般也就是个 UDP 调用,可能碰到的是 fd 锁的问题,在 这篇 里已经写过了。 为了优化这个锁带来的阻塞问题,有些系统会把 metrics 上报改为非阻塞逻辑: func Req(caller string,

map 并发崩溃一例

某系统中有类似下面这样的代码: package main import ( "sync" "time" ) type resp struct { k string v string } func main() { res := fetchData() log.Print(res) } func rpcwork() resp { // do some rpc work return resp{

一个空 struct 的“坑”

https://www.zhihu.com/question/364687707 在知乎上已经说了原因,不过只是讲官方的 spec,我们再来看看实现上具体为什么会是这样的。 package main import "fmt" func main() { a := new(struct{}) b := new(struct{}) println(a, b, a == b) c := new(struct{}) d

MQ 正在变成臭水沟

MQ 对于业务系统建模非常重要,是解决分离关注点、依赖反转、CQRS、最终一致等业务问题的重要法宝。 然而企业对于 MQ 中的数据管理却并不重视。从互联网企业发展的历程来看这个问题,最初 MQ 不是很可靠,大家不会把让特别重要的业务依赖 MQ,所以接入到 MQ 的业务事件并不多。总共也就两三个 topic,开发相应的系统对这些内容进行管理看起来没什么必要,甚至可能连详尽的业务信息都要从生产者的代码注释中去寻找。公司规模不大,这些都是可以接受的。 经历过 1Mb 小水管的朋友大概还记得当初火爆的 Flashget 的 Slogan: 下载的最大问题是什么——速度,其次是什么—

ACL 和俄罗斯套娃

逻辑复杂的系统中,我们经常能看到“规则引擎”和“决策树”之类的东西。 在数据准备好的前提下,规则引擎和决策树都可以理解成在大宽表上进行决策的过程,两者进行逻辑运算需要较为统一的数据格式,即需要对不同来源的数据内容进行统一抽象。 在之前的文章中,我写过 一劳永逸接入所有下游数据系统,讲的便是复杂系统中对准备数据过程的一种抽象。这种抽象在方法论大湿们发明的概念中早有总结:Anti Corruption Layer。你可以把它叫做 adapter,也可以把它称为 facade,或者把它贯名 anti corruption layer,你的听众听不懂哪一个名词,你就尽量用那种叫法,可以显得自己博学多才出世高人。 数据准备过程是典型的对外部系统进行适配的过程,在一个中大型规模的公司,没有进行过数据治理的前提下,必然会产生大量的像下图架构的技术产品:

依赖反转相关

依赖反转即 OOP 中的 SOLID 原则中的 D(Dependency Inversion Principle),最早么,是 Uncle Bob 提出的: The dependency inversion principle was postulated by Robert C. Martin and described in several publications including the paper Object

从 nginx 切换到 caddy

几个月前网友建议我切换到 https,当时比较懒,假期给各种烂尾楼扫尾想起来这件事情,看了看 caddy,确实非常简单。 caddy 的宣传口号是 “Caddy is the HTTP/2 web server with automatic HTTPS.”,会使用 Let's Encrypt 的服务自动帮你把 https 相关的证书流程自动搞定。颇有各种“一键干坏事脚本”风范。 个人用户用起来确实方便不少。 ghost blog 切换 ghost

为什么 Go 模块在下游服务抖动恢复后,CPU 占用无法恢复

某团圆节日公司服务到达历史峰值 10w+ QPS,而之前没有预料到营销系统又在峰值期间搞事情,雪上加霜,流量增长到 11w+ QPS,本组服务差点被打挂(汗 所幸命大虽然 CPU idle 一度跌至 30 以下,最终还是幸存下来,没有背上过节大锅。与我们的服务代码写的好不无关系(拍飞 事后回顾现场,发现服务恢复之后整体的 CPU idle 和正常情况下比多消耗了几个百分点,感觉十分惊诧。恰好又祸不单行,工作日午后碰到下游系统抖动,虽然短时间恢复,我们的系统相比恢复前还是多消耗了两个百分点。如下图: 确实不太符合直觉,cpu

查看 Go 的代码优化过程

之前有人在某群里询问 Go 的编译器是怎么识别下面的代码始终为 false,并进行优化的: package main func main() { var a = 1 if a != 1 { println("oh no") } } 先说是不是,再说为什么。先看看他的结论对不对: TEXT main.main(SB) /Users/xargin/test/com.go com.

Go 1.13 defer 的变化

1.13 正式发布了,Release notes 上说 defer 现在大多数情况下可以提升 30% 的性能。这 30% 的性能怎么来的呢? 我们知道,以前的 defer func 会被翻译成 deferproc 和 deferreturn 两个过程,这里 现在 deferproc 这一步增加了 deferprocStack 这个新过程,由编译器来选择使用 deferproc 还是 deferprocStack,当然了,

一劳永逸接入所有下游数据系统

虽然公司内的存储和数据系统名目繁多,但一般难以满足领域(就是 DDD 里说的那个 domain)内或子域(subdomain)内的所有需求,在业务部门内部还有着花样繁多的各种数据系统。这样的现状会导致业务接入数据服务的开发成本非常高。 这么说可能比较抽象,举个例子,如果你们公司有 LBS 相关的业务,一般一定会有一个坐标相关的服务,可以使用用户 id 获取瞬时坐标信息。也可能用一个订单或者配送 id 获得某件事情的发生轨迹。坐标轨迹相关的服务和地图类的数据强相关,所以这种服务一般是由单独的部门提供。 再比如说,公司内有公共的订单服务,但主服务不可能为各种相对独立的支撑域(supporting domain)的业务需求,无穷无尽地加字段,这种时候一般支持域会在其内部构建自己业务强相关的业务数据服务。

talent-plan tidb 部分个人题解-week 2

Week 2 的问题是 map reduce 优化,说实话,这周的示例代码写的不怎么样,不知道为什么都是同一个人的代码,同一个参数的名字还换来换去,读起来会浪费一些时间。一些缩写也让人比较困惑,比如 fs,bs,别人要稍微思考一下才能看懂这是什么东西,用 fileList 或者 bufferList 显然更好啊,可能样例代码的人是写 acm 出身,比较喜欢赶时间。虽然 Go 的 runtime 代码里也经常这么干,汗。 吐槽就到这里。题目是想让你先把

talent-plan tidb 部分个人题解-week 1

第一周是给定了函数签名实现多路归并排序。这里。 为啥要考这个问题呢?个人认为多路归并在分布式数据库、分布式搜索引擎领域是挺常见的算法。用我相对熟悉的 es 来举例,在搜索数据时,我们会指定 bool 表达式来对数据进行筛选,同时需要指定每个查询 sort by 字段以及 size,但分布式环境下,我们没有办法确定这 size 个元素要在每个 shard 里取几个元素。所以最基本的思路: 每个 shard 里都取出 size 个元素 拉到中心节点来进行多路归并,输出前 size 个元素

一些问题的答案

知乎上有一个问题,有哪些优秀的 Go 面试题,其中有一个高赞答案很[敏感词],从大多数问题上可以看出作者想要问别人什么,对其它应聘者的要求是对常见的性能指标要敏感。 不过我觉得,即使是做优化,很多时候也应该是去做整体优化,而不是在所有地方全部抠细节,那我们程序全用汇编+优化指令写得了。 当然这么说也很空洞,我简单整理一下这些问题的答案,可能其中有些疏漏,如果读到这篇文章的你在某些问题的答案上有不同的见解,欢迎在评论里讨论和补充~ 1.9/1.10中,time.Now()返回的是什么时间?这样做的决定因素是什么? 是想考 monotonic time 和 wall time

微服务的灾难-康威定律和 KPI 冲突

架构师们常讲的设计定律之中最为重要的是康威定律,康威定律的定义: Conway's law is an adage named after computer programmer Melvin Conway, who introduced the idea in 1967. It states that. organizations which design systems ... are constrained to produce designs which are

微服务的灾难-最终一致

现在的架构师总喜欢把最终一致挂在嘴上,好像最终一致是解决分布式场景下数据一致问题的金科玉律。事实上又怎么样呢? 事实上的这些人嘴里的最终一致,往往都是最终不一致。在多个系统之间进行数据传递时,无非通过 RPC 或者异步消息。RPC 能保证一致性么?当 B 系统需要 A 系统提供数据时,想要达到一致的效果,那么在 A call B 时发生失败,那么必须让 A 中的逻辑终止。这样才能够使 B 中的状态或数据与 A 中的完全一致。这样实际上需要让 A 和

微服务的灾难-依赖地狱

微服务模式下,我们的系统中往往需要集成进各种各样的 SDK,这些 SDK 部分来自于非功能性的业务需求,例如 bool 表达式解析,http router,日期时间解析;一部分来自于对公司内基础设施的绑定,如 MQ Client,配置下发 Client,其它服务的调用 SDK 等等。 一般的观点会认为公司内的 SDK 是较为可靠的,而开源库的稳定性不可控,所以人们在升级公司内部库时往往较为激进,开源库版本升级较为保守。具体到 Go 语言,公司内的库,我们可能会直接指定依赖的版本为 master(

微服务的灾难-拆分

在之前写事故驱动开发的时候,提到过,在企业中的项目进行开发时,只要是自己方便,一个人可以用拆分和收敛同时作为自己的标准。所以大家都是双标狗。 目前业界的微服务方法论一般也没有固定的套路,比如在 《Building Microservice》 一书中,作者也讲到了服务之间协作的时候,可以选择编排(orchestration)和协同(choreography)这两种方式来对服务进行架构。所以在拆分阶段,就没有什么硬性的标准了,每个公司可能风格都有差别,并且都可以阐述出自己的条条以支持自己的架构是“正确”的。 显然,这件事情没有绝对正确的解法。无论哪种拆分方式,都会遇到业务边界的问题。在大企业中,顶着“架构师”头衔的这些架构师们根本就不会管任何实现上的细节。相对较大的业务需求,一般也是一线的

微服务的灾难-技术栈

微服务的布道师们特别喜欢鼓吹一个观点:拆分微服务之后,我们可以随意地对小模块进行重构,选择最合适的技术栈,并且如果写失败了随时对这个模块拿其它语言进行重写。这一点被大多数布道师当作微服务的重点优势。 但是布道师们有意地把这样做所带来的问题忽略了,或者更恶意的是,他们明知道有问题,但是不说?啊哈哈。 一个公司业务上有多种语言的话,理论上可以吸引到各种“语言的人才”。这确实不假,并且可以提供给各种语言大佬一个互相掐架的优秀竞技场,只要干掉对手(其它语言的大佬)了,我就可以扩张团队,让团队把所有其它语言的模块用我们擅长的语言重写一遍,善哉善哉。小伙子们一年的事情就都安排上了。 但是显然这种说辞是有问题的。在现行的微服务架构下,除了业务本身的研发人力投入之外,在业务之外的支持系统的研发工作也有很大的工作量,比如典型的,服务发现,熔断,优雅重启,存储系统 client,

微服务的灾难-通用语言

在架构师们很喜欢的 Domain Driven Design,即 DDD 中,第一课就是教导团队形成自己独有的通用语言(Ubiquitous Language),作为业务概念沉淀下来。 作为非英语母语的国家,我们在日常交流中使用的是中文,在公司业务战略描述上使用的是中文,在高层进行任务拆分的时候使用的是中文,在领导安排工作的时候使用的是中文。唯独到了具体实现,即代码这一环节便变成了英文。当然这里我们不考虑有些公司会有汉语拼音这种尴尬的情况。 两种语言天生便有难以填平的鸿沟,在业务人员编写代码时,从中文到英文的转换,往往丢失一部分业务信息,产生一部分信息噪音,或者发生概念上的偏移。 英文语系的人对业务进行建模时,与业务方(领域专家)交流时,产生的概念和反馈可以直接落实到代码上,他们所使用的词汇不会发生变化。而其它语系的人就会在编写代码的时候发生概念偏移,比如我司是做打车业务,

流式计算中的分布式快照

流式计算系统是近些年发展较快的领域,虽然发展迅速,但实际上直到现在都没有能让所有人都满意的系统出现,哪怕是 flink/blink。 流式计算的理论基石是 leslie lamport 在 1985 年发表的论文《Distributed Snapshots: Determining Global States of a Distributed System》。首先将分布式系统中的进程定义为 process,然后将进程间的连接定义为 channel。当需要计算全局状态时,因为没有能够全局同步的时钟,所以需要有别的办法能够记录整个计算集群的状态值。 process 及连接 process 的 channel

一套实时特征系统的迭代过程

Gopher China 讲师尘埃落定,可惜今年没有获得去讲的机会,把之前的内容总结在 Blog 里吧~ 由于 MySQL 类带 Schema 类存储系统的设计问题,不支持快速的列扩充,实际业务中,一个业务实体的属性随着业务的发展是一定会膨胀的。这样持续在 MySQL 上加列往往就会捉襟见肘。比如我的历史业务订单表有 50 个字段,虽然会对历史数据进行归档,但在线上还是会有千万甚至亿级的数据,这时候在 MySQL 上加列一般使用 PTOSC 或者 Ghost 来改表,两者设计有区别,但缺点都一样:慢。

基于 Go 的内置 Parser 打造轻量级规则引擎

在公司内见到无数的人在前仆后继地造规则引擎,起因比较简单,drools 之类的东西是 Java 生态的东西,与 Go 血缘不合,商业规则引擎又大多超重量级,从零开始建设的系统使用起来有很高的学习成本。刚好可能也不是很想写 CRUD,几个人一拍即合,所以就又有了造轮子的师出之名。 要造一个规则引擎,说难实际上也不难。程序员们这时候捡起了学生时代的编译原理书,抄起递归下降、 lex/yacc 或者再先进一点的 antlr 之类的 parser generator 就搞了起来。造的时候说不定还发现噢噢,大多数 parser generator 还有不支持左递归的问题,然后按照它支持的文法写出的

2018 总结 && 2019 目标

2018 已经过去了,在 2018 年中的时候给自己定了 11 个目标:2018 目标,最优先的目标大部分也完成的差不多了,对 Go 源码的阅读工作量稍微有点低估(剩下一些查漏补缺的东西了)。。后来发现有位国外的兄弟也在干类似的事情,不过比我包装的更好:go-under-the-hood。虽有冲动把我的 Go 语言总结也慢慢向这种开源书的形式靠拢,不过想想,好像也没什么特别大的收益,暂时作罢。 18 年初阅读 Go 源码的时候,总算是把 Go 的反人类的 Plan9 汇编啃下来了,如果有条件的话,

在 ghost 中支持 mermaid

之前一直以为 ghost 支持不了 mermaid。。 最近看到某博主在 ghost 中加入了 mermaid 支持,研究了一下步骤,看起来和之前我加讨饭链接的方法差不多: code injection 在管理界面的 code injection 中增加 <script src="https://unpkg.com/mermaid@8.0.0/dist/mermaid.min.js"

几个 Go 系统可能遇到的锁问题

之前统一特征系统在 QA 同学的帮助下进行了一些压测,发现了一些问题,这些问题是较为通用的问题,发出来给其他同学参考一下,避免踩同样的坑。 底层依赖 sync.Pool 的场景 有一些开源库,为了优化性能,使用了官方提供的 sync.Pool,比如我们使用的 https://github.com/valyala/fasttemplate 这个库,每当你执行下面这样的代码的时候: template := "http://{{host}}/?q={{query}}&foo={{bar}

中台的末路

从 15 年开始,到 19 年现在为止。各大公司都在吹捧中台理念。仿佛中台是业务复杂性的救世主。是某些架构师和 PM 的新出路。各种割韭菜的讲中台的课程层出不穷。 当然,吹牛逼的时候大家都是拣好的说;苦逼的东西就只有内部人士知道,中台是靠谱还是不靠谱。只凭各路英雄的演讲内容,那看起来是靠谱的。 先来看看这些公开的观点: 中台是什么 阿里巴巴集团前端业务中公共、通用的业务沉淀到了这个事业部,包含了用户中心、商品中心、交易中心、评价等十几个中心,而共享业务事业部正是“厚平台”的真实体现,为阿里巴巴各种前端业务提供着相应服务中心领域内最为专业、稳定的业务服务。 钟华. 企业IT架构转型之道:

Go 系列文章 11: semaphore

后续更新和修正: https://github.com/cch123/golang-notes/blob/master/semaphore.md 数据结构 // Go 语言中暴露的 semaphore 实现 // 具体的用法是提供 sleep 和 wakeup 原语 // 以使其能够在其它同步原语中的竞争情况下使用 // 因此这里的 semaphore 和 Linux 中的 futex 目标是一致的 // 只不过语义上更简单一些 // // 也就是说,不要认为这些是信号量 // 把这里的东西看作 sleep

Go 系列文章 10: sync

原文和后续更新: https://github.com/cch123/golang-notes/blob/master/sync.md 线性一致性模型 从原理上来讲,atomic 操作和非 atomic 操作之间不满足线性一致性模型。这和现代计算机的 CPU 乱序执行,以及 compiler 为优化而进行的指令重排有关。在 C++ 中针对各种场景和性能需求提供了各种 memory order 选项: memory_order_relaxed Relaxed operation:
京ICP备15065353号-1