切换 fiber coredump ? 你需要理解异步与并发

作者: | 更新日期:

异步与并发是两个概念,但是很容易混淆。

本文首发于公众号:天空的代码世界,微信号:tiankonguse

一、背景

A 服务

很早之前,我负责的 A服务 从 spp 异步框架切换为 fiber 并发框架。
切换之前,我查看了大量的 fiber 资料。
最终得出的结论是,A服务只修改服务配置,重启服务就完成了切换。

当然,这并不代表所有的服务都只需要修改配置即可完成切换。
A服务 可以这样做,是因为我当初设计代码架构时,进行了简单的分层与解耦,从而使得切换没有问题。

PS:当然,也由于我这个服务比较简单,只有一层网络。

B 服务

前段时间,线上遇到一个故障,团队的B服务 CPU 暴涨,但是 cpu 跑到 50% 左右就开始大量失败,最终扩容了很多机器才缓解。
当时我告诉大家一个信息:A服务在 spp 框架下也有 cpu 跑不起来的问题,这个是 spp 框架导致的。后来 A服务在只修改配置就切换到 fiber 框架后,CPU 就可以压的很高了。
于是,同事决定也尝试通过修改 B 服务的配置来切换框架,结果还成功切换过去了,CPU 也可以跑到 100% ,节省不少机器。
只是后来,同事发现 B服务切换到 fiber 后,偶尔数据会不符合预期,最终又回滚到 spp 了。

C 服务

最近,团队新加入了一个小伙伴,领导打算让他来把 C 服务从 spp 切换到 fiber。
领导的信息有限,即看到了 A 服务和 B服务直接修改配置就切换了,虽然 B 服务有点小问题,花点时间去解决就好了。
而我的信息则稍微多一些,我了解 spp 框架与 fiber 框架的运行原理,还了解这两个框架之间的差异,以及不同场景切换的成本。

正文开始

具体来说就是,spp 是异步框架,fiber 是并发框架,而 C 服务代码逻辑非常复杂,存在大量的并发逻辑。

在异步框架中,“并发”逻辑实际上是异步执行的,并没有真正的并发执行。
而在并发框架中,并发逻辑真的是并发执行的,那就会存在并发问题。

异步与并发的关系可能有些人忘记了,后面我稍微展开介绍一下。

二、同步、异步、并发

如下图,假设我们的服务没有依赖的同时向下游拉取两个数据。

伪代码如下:

Net net;
Data data;
net.Add([&data](A& a){ a.PreCpu(data); a.Net(); a.AfterCpu(data); });
net.Add([&data](B& b){ b.PreCpu(data); b.Net(); b.AfterCpu(data); });
net.run();

同步

在同步框架服务中, CPU 的运行时间线是串行的,在网络等待的时候,CPU 是空闲的。

异步

在异步框架中,在网络等待的时候,去做其他事情其他消耗 CPU 的事情。
即网络等待时 CPU 可以分时复用,从而提升 CPU 的利用效率。

多核异步

异步框架利用多核时,就需要开多个线程或者多个进程了。
此时对于同一个请求来说,依旧只能在一个核上运行,即使其他核是空闲的。

例如下图,CPU 2 已经处理完请求2 而空闲了,但是依旧不能处理请求 1的 CPU 逻辑。

并发同步

对于并发同步,其实就是大家熟悉的多线程跑任务,由于和此文关系不大,这里就不展开了。

并发异步

在只有一个核时,异步框架与并发框架区别不大。
但是有多个核时,这种区别就很明显了。

并发的时候,同一个请求的逻辑可以真正的同时运行了。

三、问题所在

其实看了上面关于同步与并发的介绍,大家就可以发现问题了。

在异步框架中,对于同一个请求的代码逻辑,是不存在并发的。
而在并发框架汇总,同一个请求的代码随时都可能运行。

如果并发的时候同时操作同一个数据结构,就会产生所谓的并发问题,从而造成未知的结果。

这就是问题所在。

四、系统的复杂性

如果只是简单的系统,存在并发时,稍加注意就可以解决。

比如通过代码架构设计,避免并发同时读写同一数据。
或者并发读写同一数据之前,先加一个锁也是可以的。

但是对于团队的这个 C 服务,解决这个问题就变得困难了,因为系统的并发关系非常复杂。

下图是系统的一个抽象的简化图。

对于一个请求来说,会创建一个结构体来储存当前请求相关的临时数据,我们一般称为 context。
当然为了和框架自带的 context 做区分,这里我称为 myContext 。

如果代码没有进行分层设计,在一个请求的整个过程中,任何一个环节都可能来读写这个 context 。
如上图,任何一个环节都有一个红色虚线指向 myContext,代表会读写这个 myContext。

更复杂的是,存在并发的数据结构并不仅只有 myContext。
每个环节也是一个对象,而对象内部也可能存在并发来操作自己,以及操作 myContext。

更更复杂的时,这种对象可能是嵌套的。
当然,有没有我也不清楚,这就需要更深入的梳理全局的代码逻辑才知道。

五、最后

其实内部问答系统上经常遇到有人反馈使用 fiber coredump 的问题。

其中几乎所有问题,都是并发问题导致的。

因为以前的框架是异步框架,大家用了很多年了,那样写代码一直没有问题。

而如今时代变了,框架支持真正的并发了。

《完》

-EOF-

本文公众号:天空的代码世界
个人微信号:tiankonguse
公众号ID:tiankonguse-code

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

关注公众号,接收最新消息

tiankonguse +
穿越