LeeYzero的博客

自强不息,厚德载物

0%

简介

并发是Go语言最重要的语言特性之一,是Go语言区别于其它语言的重要特征。Go语言原生支持并发,可以充分发挥多核CPU的机器性能,同时在语言层面上,Go以十分简洁的语法提供丰富的并发能力,让并发编程并得简单。本文总结Go语言并发编程的常用模式,模式也就是我们说的套路,先学会模仿,再学会融汇贯通,最后才能创造出新的模式,这就是所谓的无招胜有招吧。

Go对并发的支持

对于桌面客户端应用程序,为了提升客户端的运行效率和简化多线程编程,通常的做法是在客户端启动时,启动三个常驻线程,分别是UI线程,逻辑线程和IO线程。每个线程维护一个事件循环,线程之间通信(数据传输)只能通过消息队列进行传递,消息队列是线程安全。

这么做主要有两个好处,一是常驻线程避免创建和销毁线程的开销,多核情况下,通常没有线程上下文切换,线程运行效率高。二是通过消息队列传递数据,各个线程对数据进行操作时不用所以资源竞争问题,这极大降低了多线程编程的难度,并且设计出的程序也更简单,更容易理解。

接触到Go之后,才知道这种编程模型其实就是C. A. R. Hoare的Communicating Sequential Processes, CSP。Go语言原生支持并发(goroutine)和通道(channel),并且还提供了select对多路通道进行控制,极大简化了并发编程的难度。

接下来,本文将介绍Go并发编程的常用模式。本文并不适合没有Go语言基础的读者,在阅读以下内容前,请先查阅以下内容:

Read more »

最近又看了一遍 End-To-End Argument In System Design,有一些新的思考,但都集中在一些点上,不够系统,在此先记录下来,后续有新的想法再做补充和整理。

核心观点

这篇论文在由MIT计算机科学实验室发表于1984年,是一篇非常经典的关于系统设计的论文。论文论证了分布式系统设计的一个事实:端到端的可靠通信只能由通信的两端(End-Point)来保证,而中间的媒介(如消息中间件、网关、路由器以及TCP协议栈等)只能提高通信效率,但无法保证通信两端的可靠性。

在一个系统设计中,系统设计师的主要工作是对功能进行合理抽象,明确定义功能边界。将功能职责进行合理划分的设计原则是系统设计师最重要的工具之一,端到端设计原则便是这样的工具,它在分布式系统设计中,对功能职责的划分起了一定的指导作用。

Read more »

文件同步是利用网络将多个电脑或移动设备之间的文件进行同步的网络服务。文件同步的本质是对比网络上两台设备之间的文件变更,然后将文件的不同部分通过网络进行传输,以达到文件同步的目的。本文介绍dropbox的文件同步实现原理。

基本概念

文件系统

在本地电脑上,一个文件可以用文件路径来标识。但对于dropbox需要支持共享目录,定义了名字空间(namespace)的概念,用于对传统文件系统的抽象。每一个共享目录有一个惟一的名字空间,每个用户有一个根名字空间,每个共享目录可以挂载(mount)到不同的用户根名字空间下。即对于dropbox的文件可以通过名字空间和相对路径<namespace,relative path>惟一标识。

文件格式

rsync算法的启发,dropbox把每个文件被分割成4MB的块(最后一个块小于等于4MB)。每个块通过计算出的SHA-256进行标识,对于每个文件内容,可以通过一个块列表blocklist引用。比如,文件video.avi大小了14MB,可以分割成4个块h1, h2, h3, h4,我们说文件video.avi的块列表blocklist是[h1, h2, h3, h4],如下图:

image

Read more »

最近关于B站在北邮校园招聘时,面试官对候选人打压的事件在知乎上讨论的很激烈。我并不想讨论这些言论的真假,但从这件事件反映出了B站面试官的不专业性。本文结合自身的一些招聘经验,从面试官角度谈谈应该如何面试候选人。

人才标准

每个公司或团队都有一个正式的或非正式的人才要求,即你想要雇用什么样的人?这是招聘的总体准则,这个准则因公司或团队而异,但可简单的概括为:聪明且会做事情的人

聪明和会做事情的人并不能划等号。有的人的确很聪明,但并没有将其聪明才智用到正确的地方,容易分散团队的精力;只会做事情的人往往缺乏自己的思考,容易人云亦云,很难有培养空间。

在面试的时候是可以区分出这两种类别的人的。聪明的人在沟通过程中比较顺畅,逻辑思维清晰,语言组织有条理,反映比较敏捷,对开放性的问题有自己独到的见解;会做事情的人通常需要从其过往学习、工作经验中进行考察,会做事情的人通常有始有终,对待工作认真尽责,有较强的团队合作能力。

Read more »

之前排查了一个服务hang死的线上故障,觉得这个问题比较有代表性,本文记录故障排查的经过,并做一些总结和思考。

现象

周末线上一个比较核心的服务(以下称为X服务)出现大量5xx报警。从客户端看到的现象是客户端请求X服务时,出现大量的链接被重置(connection reset by peer)的错误。

分析

从经验来看,90%以上的问题都是上线引入的。故障出现在周末,按规范来说,非特殊情况下,周末是不允许上线,跟相关角色确认后,本次故障不是上线引入。

观察线上流量,在出现故障时间点,流量的确有大幅上涨,从宏观分析来看,有可能流量突然上涨是一个诱因。

任意找了一台有问题的机器,发现了一个比较有意思的现象:服务X出现了大量CLOSE_WAIT状态的连接。从TCP的状态转换可知,CLOSE_WAIT是被动关闭一方在收到FIN并返回ACK后进入的状态。TCP状态机如下:

img

也就是说X服务在收到客户端请求后,客户端关闭连接,还服务端进程并没有关闭连接,分析了web server的框架代码,正常情况下,一个请求处理完后会关闭这个连接,出现这种情况可能是业务逻辑出现阻塞,导致服务端请求的连接一直不能关闭

查看了一下X服务打开的socket句柄数:

1
2
$ lsof | grep `ps -ef | grep x-service | grep -v 'grep' | awk '{print $2}'` | grep sock | wc -l
10231

发现X服务打开的连接数非常多,达到10231个,看下实例的句柄数上限:

1
2
$ unlimit -n
10240

句柄数像是已经被耗尽了,用strace看了下X服务的系统调用:

1
$ strace -p `ps -ef | grep x-service | grep -v 'grep' | awk '{print $2}'`

从系统调用日志中发现了一些关键信息:

发现大量accept调用报错,从日志信息可以看出,的确是系统的文件句柄数(FD)耗尽了,导致连接被reset掉,这也能说明为什么客户端侧看到了大量connection reset by peer错误了。

X服务打开了大量socket文件句柄,且绝大多数连接状态都是CLOSE_WAIT,如果业务逻辑有阻塞的确可能会出现把句柄数数打满。

分析了一下业务逻辑,业务逻辑本身不复杂,只有一次IO网络请求,是从数据库查询数据,从日志中发现了一些端倪:

Read more »

最近排查一个线上接口耗时上涨的问题,其中用到排查思路和相关工具有一定借鉴作用,在此做个记录,同时供网友参考。由于涉及到一些敏感信息,所以本文会对一些名称进行模糊化。

现象

监控发现对外接口的整体耗时上涨了近100ms,涨了近50%,甚至有少部分接口出现超时现象,已经影响到部分业务的用户体验。

分析

宏观分析

对比故障发生的时候点,检查对应时间结点是否内部服务有上线,通常情况下,90%以上的故障都是由上线引起的。但排查后,业务侧并未上过线,排除是业务上线引入的故障。

对比不同机房,服务部署在三个机房,记为机房A,机房B和机房C,发现耗时主要发生在机房A,机房B和机房C并不存在这个问题,怀疑是机房的网络链路问题。

联系负责机房的同学一起排查,未发现网络链路问题。将某个接口所有的流量从机房A切到机房B,发该接口的耗时恢复到之前的水平,看起来的确像是出现机房A网络存在问题。但OP同学再三确认,未发现异常。

Read more »

Code Review是保障代码和产品质量的重要手段,但却被绝大部分公司所忽略。本文主要基于Google对Code Review的实践,结合自身的经验谈谈团队中该如何做Code Review。

1. 什么是Code Review

Code Review是代码评审人(Code Reviewer)对代码提交者(Code Committer)做审查(Review)的过程。

2. 为什么要做Code Review

  • 提升代码/产品质量
  • 团队工程师文化传承
  • 团队成员间知识/经验分享
Read more »

搭建环境是一件很无聊的事情,最近换了一个较新的系统,少了很多系统级的依赖环境问题。本文简单记录搭建hexo环境的步骤,以便后续查阅。

系统环境

CentOS 8.x

安装依赖环境

至少10.13,建议12.0或更高版本。建议使用二进制方式安装

1
$ sudo yum install git-core

安装Hexo

  • 使用npm安装hexo
1
$ npm install hexo
  • 添加环境变量
1
$ echo 'PATH="$PATH:/path/to/node_modules/.bin"' >> ~/.profile
  • 测试
1
$ hexo version

参考资料

[1] hexo官方文档
[2] Nodejs官方文档

周末大清早就被报警短信吵醒,故障表现为离线存储集群流量突增,集中在热点分片,而且流量越来越大,系统吞吐、稳定性均在降低。最终发现是因为实例间时区不一致触发一个隐藏的BUG导致。这个问题在分布式系统中很具有代表性,在此做个记录以备忘。

症状

  • 离线存储集群流量突增,集中在热点分片;
  • 消息系统中消息在持续积压;
  • 消息系统收到大量重复ACK;
  • 业务worker消费到大量重复的消息;
Read more »

RAII作为C++资源管理的一种惯用法,是每一位C++程序员都应该掌握的基本技能。在google上搜索关键字RAII, 有二百多万条搜索结果。说明这个话题在网上已经被讨论过无数次,也发现了一些好文章给我不少启发,这篇文章主要是做个总结并谈谈自己的理解。

什么是RAII

资源获取即初始化(Resource Acquisition Is Initialization),即RAII。RAII是一种C++编程技术。它利用栈对象在离开作用域后自动析构的语言特点,将受限资源的生命周期绑定到该对象上,当对象析构时以达到自动释放资源的目的。 这里说的资源都是指的受限资源,比如堆上分配的内存、文件句柄、线程、数据库连接、网络连接等。

Read more »