写点什么

《分布式系统设计》(1) 从程序思维到系统思维

用户头像
陈皓07
关注
发布于: 2021 年 04 月 13 日

1.课程介绍

内容

思维方式,设计方法

基本概念

基本问题,解决的基本思路

分布式系统的关注点

目的

能看懂一些论文、开源软件。它为什么要这么设计。

如果自己设计一个分布式系统,有章可循。

特点

思考 &编程

知识密集型


2.微服务


坏消息

近几年如果说关于软件架构最火的一个名词,非微服务莫属。

 

也有很多文章,书籍,培训也好,最多谈到的问题是如何拆分微服务

 

可真正的问题是啥呢? --- 灾难的开始

把一个单体系统,不管用什么方法,把它拆好之后,才是问题真正的开始。因为,你进入了分布式系统的领域,这是一个完全不同的领域。我们之前的某些设计,在这个领域里完全失效,因为它们的假设是不一样的。

 

如果没有深刻的理解和掌握分布式系统领域的关键问题和解决方法的前提下,拆分之后可能更痛苦。原来你觉得单体应用很复杂很麻烦,但是一旦分布式系统领域出问题之后带来的后果可能更严重。

 

微服务,部署快,升级快,这是它的优点。但是它的缺点也同样明显,如果没有深刻的认识,将会是一场更大的灾难。

《goodbye-microservices》

https://segment.com/blog/goodbye-microservices/


这个公司很有意思,之前写了一篇文章,专门说它们微服务系统维护的很好,还专门讲了怎么把一个单体系统演变成一个微服务的系统。

 

然后去年就写了这个。

 

文章大意:

微服务是一种面向服务的架构风格,在服务端,是由很多个有单一目的(职责),低(资源)占用,的网络服务组合而成。其被吹嘘的优势包括,模块化,容易测试,更好的功能组合,环境隔离,团队自治。。。。相反地,单体架构,巨多的功能集中在一起,开发,测试,维护,度量。。。。


2017,做一个微服务的项目,团队陷入了日渐爆发的复杂性中。缺陷暴增,开发效率骤降。

3 个全职的开发人员投入,是的系统可以正常运行。这种情况必须做出改变。


要点:

1. 故障隔离是非常困难的。

2. 内存内的缓存基本上是无效的。现在缓存在海量的进程中,很难被击中。

3. 更新版本会引发依赖者连锁反应。


总结

不能说微服务好还是不好,它只是一个架构风格。而且首先它是一个分布式系统。如果想把一个微服务做好的话,首先把分布式系统设计好。

 

首先是一个好的分布式系统。

 

我们可以取学习微服务的拆分方法,怎么部署之类的。但首先要学习怎么设计分布式系统。如果能把分布式系统做好的话,甚至不用去在意是不是微服务。


3.从程序思维到系统思维


其实就是我们在工作当中的一种思维模式,可能没有察觉。

程序思维

函数不要太长,怎么命名,数据结构怎么定义呢,用哪种编程语言呢,是不是面向对象。。。。

系统思维

并不是说一个人没有系统思维,一个人你一定有系统思维。只是说你没有察觉和故意关注这方面。

 

什么时候会切换到系统思维呢?

出故障的时候,你就有系统思维了。和其他系统对接的时候,重启的时候。。。

 

这个时候你考虑什么问题呢?

  1. 重启的时候启动是快是慢。

  2. 对接的时候协作是否是正确。

  3. debug 的时候。你不关心是不是面向对象。我关心这个状态是不是对,这个状态序列是不是满足我的预期。

 

这些事情我们平时工作可能也在做,但是没有凸显出来。我们要想提升能力,一定要把系统思维把它显示化出来。


提升能力

一定要把系统思维显示化出来。即我们系统有哪些重要的点,我们需要考虑的问题要罗列出来。

如何提高系统思维、系统设计能力。

我们有很多知识,现在是最不缺知识的一个时代。问题是不是看了之后就有提升呢?怎么能把我看过的东西变成能力?

怎么样对我个体来讲把知识变成能力。

实践,解决问题。-----这其实是个尝试。

当我碰到这个问题,我是不是解决了这个问题,解决的更好。再去看这些东西,你的感受就会不一样,这个东西我思考过。而不是我看了一个方法,就说这个方法很好,那样还不如我不知道这个方法,按部就班的解决问题。

所以,我们在工作中会遇到很多问题,我们解决问题的态度是什么。是不是有更深层次的思考。这个方法为什么好为什么不好。


工作中,最怕的问题是什么

仅局限于开发领域。

 

  • 故障不能复现,其实并不是让你害怕,但是会让你烦躁;

  • 性能问题;

 

不符合预期

肯定是跟系统的表现有关系,不符合预期,而且是在线上(Context),让用户感知到了。


如何解决这种问题?

很多设计方法,并不是你看了什么书才掌握的,一定是碰到了问题。假设我们在测试过程中发现死机,或者在线上,行为和我预期不一致了。我们怎么解决?当然,分析代码是根本解决这个问题的关键。但是现在系统已经在运行了。

 

重启。

 

其实你打电话到微软的客服,然后给你说了一二三,其实那都是障眼法,告诉你重启一下试试,一试就好了。前面不说的话显得不专业。为什么会这样。


这样的解决方法为什么有效

这种方式背后最核心的原因是什么。重启为什么会好了?

 

把系统恢复到一个已知的状态。

l 首先有一个已知的状态,我可以掌控的,

l 然后我能恢复到这个状态。

 

我的目标就是恢复到一个已知的状态。不是重启。重启是一个常规的方式。

 

所有高可靠的方法的思想都是来源于此!

所有高可靠的方法的思想都是来源于此!

所有高可靠的方法的思想都是来源于此!


发现产品中 bug 的难易程度


我们先排除硬件问题。是不是我所有问题都重启一下就解决了,随便编了。肯定是不行的。所以,继续深究一下:


--------------------------------------------------------------

可复现 偶现

核心功能 容易 难

附属功能 容易,但常被忽略 难

--------------------------------------------------------------


核心功能:系统存在的意义。

附属功能:锦上添花,可有可无。

 

核心功能一定是测试的重点,很容易被发现。附属功能测的少,出现了也容易被忽略。


产品中 Bug 出现的频率


可复现 偶现

核心功能 决不允许出现 总是出现

附属功能 经常 总是出现


重启能否解决


可复现 偶现

核心功能 不能 能

附属功能 看情况 能


可复现核心功能一定要解决掉。因为重启也没有用。

附属功能可能个别用户关注,看情况是否解决。看用户是不是投诉。

 

重启能解决问题的前提是,重启能恢复到一个我能掌控的状态。

第一点就是要保护好你的核心状态数据。


为什么出 BUG?

 


代码很庞大,不可能一个人全清楚。而且 BUG 肯定是在代码里。

  • 自己知道的 bugs 就好解决。

  • 我自己认为我自己知道的,也还好解决。

  • 不知道存在这种东西,就没有办法了。

 

其实即使这样我们也还是要编代码,要交付。对于这种问题我们如何去解决呢?或者说即使出了问题,也在我控制之内呢?


  • 让我知道的更多 ----- 学习

  • 对我的设计进行探索。测试,或者类似于 TLA+的工具,拓展我行为的空间。

  • 最差的情况。即使做了这些,还是有 BUG。这个时候怎么办呢? 其实重启是最后一步。

 

我们把范围变小,并且可以应对。把系统恢复到我能控制的状态。

否则重启也没有用。

 

要想让重启有效,

第一步,你要知道系统在一个正常运行的情况,需要什么样的状态。

第二步,保护好你的核心数据。

 

其实这个就是系统思维。


例子



一部分数据是我核心数据,一定要保护好了。

系统出问题了,一般是我 Derived 数据出问题了。

 

我们在做系统思维的时候,我们考虑的是数据。哪些是我核心的数据,哪些是我 Derived 数据。否则重启都没有用。重启都没有用就很难受了。


我们发现人干这个重启的事情太慢。

 

例子:看门狗

发现系统不好,重启掉。

保护这个系统。

 

看门狗不干业务的事情,他就保护这个东西。我们其实十年二十年前就是这么干的。

问题是我们的粒度很大,整个设备,或者整个主控板。


可用性

你的服务是不是一直有。我们就探讨一下,如何让你的系统,对外一直能够提供服务。

 

电信产品至少要 5 个 9

所以要重启的快。

 

怎么样重启的快?

  • 检测要及时。这是个双刃剑,否则总是重启。

  • 数据加载更容易。

  • 重启的部分变小。而不是重启整个系统。

 

思路:把大的系统划分为小的系统。

 

我们现在其实幸福多了,容器等各种技术解决的什么问题?本质上就是这个问题。

 

服务拆分原则

拆分微服务一定也是这个原则,一个 crash 掉了另一个能不能工作,能工作就分开,不能工作就放在一起。服务重启需要的最小数据是什么。这样思考的出来的方案一定是可行的。

否则,按照业务来拆分,拆出来的一定是不可行。


思考的要素

我们就不再考虑编程语言了。



• 数据的分类、分层(Essential vs. Derived)

• 隔离、自治

• 无共享(copy 一切)

• 异步消息

• 崩溃、重启

• 健康性监控

 

这些问题我们无时无刻在考虑,只是我们要可视化出来。

其实我们的网络也是这个思路,整个电信网看成一个系统的话,就是这个设计思路。



泰坦尼克号为什么沉了?

因为顶上没封闭。

 

所以在隔离上,不能打折扣。

 

硬件坏了怎么办?


要想做一个容错的系统,至少可以在两个硬件上面运行

 

两个需要数据复制。

我们系统里面主备问题是最难解决的问题。一旦进入数据复制,就进入了分布式系统里了。

 

你要知道我需要哪些特性,哪些特性我是一定要舍弃的。

 

两个数据中心


其实思路是一样的,只是粒度的不同。

自相似的结构。从一个节点,到集群都是这个结构和设计思路。

 

其实我们的 docker,K8S 不都是干这个事情么。


总结:程序思维和系统思维

系统容错的范围越大,代价越大,成本越高。一定要选择一个合理的粒度。

程序思维

• 应用库

• 运行时和核心库

• 语言原语

系统思维

• 应用服务

• 基础系统服务

• 协议和格式

 

服务就是一个小框,可以自治运行的部件。

粒度的大小也并不是越小越好。


基础系统系统服务

我们写代码其实也考虑这些问题。

 

• 通信(message queue)

• 协调(ZooKeeper)

• 控制流(ASW simple workflow,storm)

• 内存(memcache,redis)

• 硬盘(S3,K/V store)

 

这个领域是一个分布式领域,它的很多假设完全是不一样的。


用户头像

陈皓07

关注

还未添加个人签名 2019.04.11 加入

还未添加个人简介

评论

发布
暂无评论
《分布式系统设计》(1) 从程序思维到系统思维