待整理的阅读笔记

2019-02-11 ~ 2019-02-17

历时三年,美图全面容器化踩过的坑

https://mp.weixin.qq.com/s/lfN9O7qwWQZCx_iqiAqP0g

  1. 讲了容器化的背景,以前存在哪些问题(大家的问题似乎是大同小异
  2. 搞容器嘛,选择了当时口碑好地 Kubernetes(基本是跟着开源社区、业界走嘛,一般不自己造轮子
  3. 容器平台主要会涉及到这些方面(似乎都是干货)
    1. 网络
    2. Load Balance
    3. 日志
    4. 调度
    5. 弹性伸缩容
    6. 监控
  4. 业务落地
  5. 展望未来:ServiceMesh, Serverless, 边缘计算

收获

对容器平台有一个整体的认识,知道这个大饼里面有哪些东西。 文章对几个容器化种遇到的几个重点问题也有描述,如果以后自己遇到,感觉也是可以参考的。

另外,感觉基础设施都会涉及网络、LB、日志、调度、伸缩容、监控这些主题, 似乎主要也就这些主题把。不知道这个方面有没有类似 12 factor 的总结。

Kubernetes monitoring architecture

https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/monitoring_architecture.md

Kubernetes 监控分为两个方面(官方描述为 Pipeline):

  1. core metrics pipeline: 个人理解为指标 采集 , Kubernetes 会提供 API 供外部访问,Kubernetes 内部也会基于这个数据确认一些调度策略等
  2. monitoring pipeline: 指标存储、展示、报警

文章后面还描述了这两个 pipeline 涉及的工具链以及一些预期的使用场景。 比如 core metrics 涉及到 kubelet, metrics server; monitoring 与 Prometheus, InfluxDB, Grafana 这些概念紧密相关。 (自己对监控这部分也不是特别理解,所以暂时只能理解到这个程度)。

Monitoring Kubernetes with Prometheus | Prometheus Docker Monitoring

https://coreos.com/blog/monitoring-kubernetes-with-prometheus.html

  • 监控很重要

Monitoring is one of the pillars of successful infrastructure. It has been called the https://www.infoq.com/news/2015/06/too-big-to-fail

这两张图挺有意思的

Mikey Dickerson’s “hierarchy of reliability” Maslow's hierarchy of needs

  • 现代基础设施监控与以往不同(监控层级不一样了)

Effective use of Kubernetes requires architects to think about applications and workloads rather than machines and processes.

  • 文章后面讲的是一些具体的安装使用姿势

2019-05-06

分布式系统测试那些事儿

原文:PingCAP 博客

开头说:

我们是觉得做好分布式系统测试比做一个分布式系统更难

然后分几点来论述:

A simple “Hello world” is a miracle

批注:hello world 程序要成功的跑起来,那 OS/VM/Compiler 等底层部件都得没有 bug。

我觉得这么说也不是很准确(或者说这样表达很容易有误导性),只能说明这些组件用于运行 hello world 是没有 bug 的。在正确的 path 上没有问题。

A RPC “Hello world” is a miracle

批注:RPC 的 hello world 涉及组件更多,序列化/反序列化,网络协议栈,服务发现等

就是一个真正完善的系统,最终的错误处理代码实际上通常会比你写正常逻辑代码还要多的,但是我们的测试通常 cover 的是正确的逻辑,就是实际上我们测试的 cover 是一小部分。

中间开始说:

那先纠正几个观念,关于测试的。就是到底怎么样才能得到一个好的、高质量的程序,或者说得到一个高质量的系统?

Who is the tester ? 批注:测试是一种文化,团队人人都应该是测试

  • Quality comes from solid engineering.
  • Stop talking and go build things.
  • Don’t hire too many testers.
    • Testing is owned by the entire team. It is a culture, not a process.
  • Are testers software engineers? Yes.
  • Hiring good people is the first step. And then keep them challenged.

Stop talking and go build things. 有点像 Talk is cheap, show me the code.

Test automation

  • Allow developers to get a unit test results immediately. 批注:快
  • Allow developers to run all unit tests in one go. 批注:简单(和 CI 的那本书里面说的一样)
  • Allow code coverage calculations.
  • Show the testing evolution on the dashboards. 批注:可视化测试结果,包括覆盖率
  • Automate everything. 批注:自动化

Well… still not enough ? 批注:似乎是讲一些测试思路

  • Each layer can be tested independently.
  • Make sure you are building the right tests.
  • Don’t bother great people unless the testing fails.
  • Write unit tests for every bug

里面提到一个事情:修复的 bug 一定要有单元测试。

Code review 批注:这里讲的应该是一个持续集成的思想

  • At least two LGTMs (Looks good to me) from the maintainers.
  • Address comments.
  • Squash commit logs.
  • Travis CI/Circle CI for PRs.

Who to blame in case of bugs? - The entire team.

Profiling

  • Profile everything, even on production
    • once-in-a-lifetime chance 批注:这个不应该是针对 bug 来讲的么?
  • Bench testing

Embed testing to your design

  • Design for testing or Die without good tests
  • Tests may make your code less beautiful

这个点似乎相对比较新颖,据文章说,K8s 的某个类的某些代码专门是为测试准备的。

文章这部分还讲了如果做测试:测试用例从哪来?如果方便的运行这些测试用例? 文章举了一个例子:TiDB 的很多测试是从一些 ORM 框架中收集过来的。如果方便的跑 ORM 的测试用例呢,record and replay。不错呦,我当时以为是固定成一个脚本,但没想到可以这样抽象。

好,文章这里有一个转折:

那么刚刚说了那么多,实际上做的是什么?实际上做的都是正确路径的测试,那几百万个 test 也都是做的正确的路径测试,但是错误的路径怎么办?很典型的一个例子就是怎么做 Fault injection。

批注:之前讲的内容比较偏方法论,后面来些干货?

Fault injection

  • Hardware
    • disk error
    • network card
    • cpu
    • clock
  • Software
    • file system
    • network & protocol SImulate everything

如果没有做错误路径的测试,那很简单的一个问题,现在假设走到其中一条错误路径了,整个系统行为是什么?这一点不知道是很吓人的。

批注:Fault injection 在 SRE 团队似乎是个热门话题。

一些 Fault injection 工具

libfiu - Fault injection in userspace It can be used to perform fault injection in the POSIX API without having to modify the application’s source code, that can help to test failure handling in an easy and reproducible way.

OpenStack fault-injection library: https://pypi.org/project/os-faults/

Jepsen Jepsen: Distributed Systems Safety Analysis

然后文章中举了 FoundationDB 的例子,说 FoundationDB 为了解决错误注入的问题,或者说怎么去让它重现的这个问题,做了很多事情,很重要的一个事情就是 deterministic

批注:我感觉似乎跑题了…

2019-05-10

软件测试工程师的核心竞争力是什么?

https://www.infoq.cn/article/pUeQtGSXwDh28deki*gU

文章 TOC:

  1. 功能测试、测试开发、性能测试工程师等核心竞争力
  2. 为什么会讲到“软件测试开发者的核心竞争力”
  3. 当测试人想往高处走时,是追求测试的深度,还是测试广度?
  4. 测试想去转测试开发,他需要积累哪些经验?
  5. 测试用例的力度怎么去把控?

文章中说了三种类型的工程师:功能测试、测试开发、性能测试工程师。 对于性能测试工程师(类似的也有安全测试工程师):

这类人的知识是需要经过很长时间才能积累起来,而不是一蹴而就,也不是通过一个简单培训就能够把这类人培养起来。这种人,他看到的业务场景越多,看到过的问题越多,他能很快地根据这个问题的现象,去决定进一步做怎么样的测试,或者去拿哪些指标。有了这些指标之后,他可以快速缩小问题的范围。

测试开发又分为两类:

  1. 一类是专门做测试基础架构,做平台,做工具开发的
  2. 还有一类是专门去这些平台去做测试用例的,自动化测试用例开发的

文章提到一个很有趣的问题:当测试人想往高处走时,是追求测试的深度,还是测试广度?不禁让我想到了 DevOps 人。

那你是怎么去做权衡、去做取舍?因为大家的时间、精力总是有限的。从我个人的经历来讲,一定是从深度再到广度。

UPDATE 2019-05-14: 今天又来读了一下这篇文章(采访),发现这是个标题党,文章里面并没有给出标题的答案。

2019-05-14

软件测试工程师的核心竞争力是什么?

https://time.geekbang.org/column/article/11325

传统测试工程师师应该具备的核心竞争力

  1. 第一项核心竞争力,测试策略设计能力
  2. 第二项核心竞争力,测试用例设计能力
  3. 第三项核心竞争力,快速学习能力
  4. 第四项核心竞争力,探索性测试思维
  5. 第五项核心竞争力,缺陷分析能力
  6. 第六项核心竞争力,自动化测试技术
  7. 第七项核心竞争力,良好的沟通能力

2019-08-05 ~ 2019-08-11

Python 相关

一个 Python markdown parser 项目

推荐阅读项目代码 https://github.com/lepture/mistune

  1. 代码结构简单,只有一个文件,大概 1.2k 行,可读性比较好
  2. 可以了解怎样解析 markdown(了解之后,就可以放飞自己了,比如自己做一些 markdown 语法定制,做个 cosven-flavoured markdown 啥的,也不在话下 ?)

Emacs 相关

Snails 超级快的模糊搜索框架

看到 Snails 的截图,马上就想到了前几天在知乎上看到的另外一篇文章:VSCode 的精华只在于一个快捷键。Snails 作者说了,这个框架很好扩展!30 行可以撸一个 backend,值得一试。

描述链接:https://emacs-china.org/t/snails/10029 个人对 Snails 的期待与看法:https://emacs-china.org/t/snails/10029/178?u=cosven

elisp 文件中的 lexical-binding 是个啥?

https://kuanyui.github.io/2016/02/24/dynamic-scoping-and-lexical-scoping/

这个文章解释的比较清楚。看完个人的理解就是:lexical-scoping 使得 elisp 具备了闭包功能。 这里面似乎有点蹊跷,又搜了搜 lexical-scoping 和 dynamic scoping 的一些问题: 动态作用域和词法域的区别是什么? - Guannan Wei的回答 - 知乎

闲杂

在 Docker 中访问 https 地址遇到 X509 Error

https://blog.cloud66.com/x509-error-when-using-https-inside-a-docker-container/

The magic behind configure, make, make install

https://thoughtbot.com/blog/the-magic-behind-configure-make-make-install

带新人了解 configure/make 背后做的事情,比如 Makefile.in configure.ac 都是些啥。

测试相关

SQLsmith: Randomized SQL Testing in CockroachDB

https://www.cockroachlabs.com/blog/sqlsmith-randomized-sql-testing/

个人小结:它帮助发现了若干 bug,是一个新颖且有效的方式。坏消息是:这些 bug 大部分都是些 corner case,价值还值得商榷。但 cockroach labs 仍然在探索它的其他价值。

2019-08-12 ~ 2019-08-25

最近似乎没怎么系统的学习新东西,播放器的代码也加的比较慢。

买了一本「软件测试艺术」,看了个序。操作系统啥时候继续学习下…

蓝天白云的日子不少,但缺少出去浪的催化剂。

迁户口、约饭、读书、写播放器、玩游戏、看电影电视剧、TODO 好多。

这这两周看了一篇质量比较高的文章,另外还有几篇 tutorial 类的文章

Static Analysis at Scale: An Instagram Story

https://instagram-engineering.com/static-analysis-at-scale-an-instagram-story-8f498ab71a0c?gi=68a0c09f9d35

文章读后梳理

文章先说了 Instagram 是个 Python 大厂,所以项目在一个大仓库里面,而且 Instagram 每天要发布好几十次,维持代码质量是一件非常有挑战的事情,那 Instagram 是怎样解决这个问题的呢?

Instangram 从几个方面下手(维持代码质量),Linting 就是一个方面。

接着说了为什么需要 Linting?

  1. 开发者遭遇问题的时候,自己可能并没有意识到,Linting 可以帮助开发者发现并且诊断问题
  2. 在成百上千的开发者中普及优秀思想变得越来越难

Linting 如果有用,那有哪些常见方法呢?

  1. 基于正则 -> easy, but dumb
  2. AST-based Lints(Pyre + Mypy)-> powerful, but complex

谈 AST 的时候,不免要谈 CST,毕竟这是 Instagran 的主角:它说本来的 CST 会有点复杂,而 AST 又损失了比较多的信息。Instagram 就弄了个 LibCST,综合了两者的优点。 LibCST 提供了一个类似 CST 这样的无损表示(lossless representation)(注:AST 是一种 IR intermediate representation),但是它也可以像 AST 一样,比较容易的解析出语义信息。

举个了例子,LibCST 如果优雅的检测重复判断,示例代码:

# value imports
from typing import TYPE_CHECKING
from util import helper_fn

# type-only imports
if TYPE_CHECKING:
    from circular_dependency import CircularType

if TYPE_CHECKING:  # Whoops! Duplicate type guard!
    from other_package import OtherType

对于这个例子,它们可以基于 LibCST 非常容易了写一个 linting 规则,它给了例子(这里不贴上来了)。

这里才是文章的一半,这文章有点长呀…

接着讲它们是怎样用 LibCST 来实现 Linting Rules,在这个实践过程中,它们又经历了几个阶段

  1. 初期:简单粗暴,使用 single visitor 模式。但是随着 rule 变多,这种模式很难维护
  2. 解决初期遇到的困难:参考 ESLint 的设计,它们开发了一个中心化的 visitor registry (这个部分没看太懂)

Lint 太吵(想想大家都诟病的 Pylint),它们一方面把严重的问题给高亮;另外,开发了 auto-fixer 功能。

Codemods: 自动修复代码,比如自动给代码加 type hint;修改差的函数名。

最后说基于 scope analysis 可以做更高级的代码修改。

最后总结:

Finding the code we want to modify is often more important than the modification itself.

文章读后感

非常硬核的文章:背景 -> 方案对比 -> 确认方案 -> 方案应用 -> 应用遇到问题 -> 调整 -> 未来展望

收获:

  1. 了解大厂 Linting 实践
  2. 好奇 AST/CST 都能干些啥?

API 分页

关于分页,以前脑袋里面有几个疑问:

  • offset + limit 和 page + pageSize 两种方式有什么区别? 目前来看,没啥区别,最多是便利性的问题
  • 以前听说 MySQL 的 offset + limit 方式会有性能问题? 对,当 offset 较大时会,因为它实际上需要读取 offset + limit 行数据,改进办法是使用游标。

注:上面两种接口都可以基于 MySQL 的 offset + limit 来实现。

Database 相关

SQL prepare 是啥?

前几天看到有个回答说 SQL prepare 可以做一些安全方面的事情,而我之前连 prepare 是啥都没听说过。今天在看 golang sql/database 库的接口也有 prepare,想着学习下这到底是是啥。

这个回答很清晰的解释了什么是 prepare。

如何从根本上防止 SQL 注入? - 余天升的回答 - 知乎 https://www.zhihu.com/question/22953267/answer/23192081

其它

cat hello.txt > hello.txt 之后,hello.txt 变成空了?

https://unix.stackexchange.com/questions/41207/why-does-cating-a-file-into-itself-erase-it

2019-10-14 ~ 2019-10-30

这个时刻的我其实是特别浮躁的,我看了下自己的阅读记录,上次写这个已经是 9 月初了。

最近一个月,周一到周五都在疯狂工作;周六周末都在疯狂玩游戏,缺少一些总结和思考,自己心里多少也是有点慌的。 最慌的是工作内容,要不趁此机会梳理一下吧,这一个月疯狂工作的成果有些啥?

哎,公司这个 Confluence 是真的破,每次打开都要几十秒…

成果(搬了哪些砖):

  1. bug review -> 结论是 bug 各式各样,无明显共同点。啊,心痛
  2. 梳理 bug 字段 + 梳理模块 -> 这个可能还是有一些沉淀把
  3. 跟进 longroad 系统发现的 bug -> 说实话,没啥太多收获,主要也是苦力
  4. 写回归测试用例和 review 用例 -> 这个部分真的太苦了,唯一让我欣慰的是对整个系统功能有了一个大概的了解
  5. OKR 思考 -> 质量体系、bug 发现与重现等主题的思考

哎,自己得加紧学习才行。下面几个技术主题还是挺有意思的,都是自己一直想搞懂的东西。

dayname 计算方法

今天在 review TiDB bug 的时候,看到一个 dayname 相关的问题,正好看看 TiDB dayname 的实现。 后来发现这个计算能力可能是由语言提供的,于是就去看了下 Python 的实现,感觉挺好玩的。

def _ymd2ord(year, month, day):
    "year, month, day -> ordinal, considering 01-Jan-0001 as day 1."
    assert 1 <= month <= 12, 'month must be in 1..12'
    dim = _days_in_month(year, month)
    assert 1 <= day <= dim, ('day must be in 1..%d' % dim)
    return (_days_before_year(year) +
            _days_before_month(year, month) +
            day)

(_ymd2ord(year, month, day) + 6) % 7  #  可以算出星期几

仔细看代码还可以发现一些有趣的东西:比如 100 年要减一天;400 年要多加一天。知乎上有个相应的问题 能被4整除的就是闰年吗,为什么? - TungHsu的回答 - 知乎

比较并交换(CAS)

参考资料:https://zh.wikipedia.org/wiki/%E6%AF%94%E8%BE%83%E5%B9%B6%E4%BA%A4%E6%8D%A2

CAS 底层原理是怎样的?

CAS操作基于CPU提供的原子操作指令实现。对于Intel X86处理器,可通过在汇编指令前增加LOCK前缀来锁定系统总线,使系统总线在汇编指令执行时无法访问相应的内存地址。

Nginx 的 CAS 实现(参考博客):

static ngx_inline ngx_atomic_uint_t
ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
    ngx_atomic_uint_t set)
{
    u_char  res;
    __asm__ volatile (
         NGX_SMP_LOCK
    "    cmpxchgl  %3, %1;   "
    "    sete      %0;       "
    : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory");
    return res;
}

NGX_SMP_LOCK 是指 LOCK 指令,个人不准确的理解:大概意思就是说 LOCK 指令可以保证某一个 CPU 进行这个操作时,其它 CPU 不会干涉它。

LOCK is not an instruction itself: it is an instruction prefix, which applies to the following instruction. That instruction must be something that does a read-modify-write on memory (INC, XCHG, CMPXCHG etc.) — in this case it is the incl (%ecx) instruction which increments the long word at the address held in the ecx register.

The LOCK prefix ensures that the CPU has exclusive ownership of the appropriate cache line for the duration of the operation, and provides certain additional ordering guarantees. This may be achieved by asserting a bus lock, but the CPU will avoid this where possible. If the bus is locked then it is only for the duration of the locked instruction.

--- https://stackoverflow.com/questions/8891067/what-does-the-lock-instruction-mean-in-x86-assembly

cmpxchgl 指令资料太少,博客 讲的似乎是比较清楚地了。

sete xx 指令:将标志位 ZF 的值放到 xx 中。在上面这段代码里面,相当于是 sete res 将 cmpxchql 的结果放到 res 中,表示是否成功。

CAS 应用?

在应用中CAS可以用于实现无锁数据结构,常见的有无锁队列(先入先出)[3] 以及无锁堆(先入后出)。

Updated:

Comments