美文网首页
当我们在说扩展性时,我们在说什么

当我们在说扩展性时,我们在说什么

作者: 饭真香 | 来源:发表于2020-05-25 16:11 被阅读0次

    一个小小的前言

    这个专栏的所有目的就是,我们只说大白话。争取周更,每周覆盖一个有趣的点 :D

    开头声明本文的所有知识知识源自 Mullie大神的"How to make your code scale”

    How to make your code scale· Matthias

    5000字,大概10分钟能看完(翻译的不累但是打字贼累) 大概要我下面会夹带私活,用自己的话加工翻译,一起来聊一聊这个绕不过去的话题,scale。

    Scale scale scale,当我们写一个网站,平台,或者各种服务,我们都会说到这个。特别是在如今大数据,云已经普及了快10年的2020年。记得在大学的时候,连个小朋友去面试或者展示随便个自己的twitter clone 项目的时候都会抖一些什么,高并发,大吞吐,故障冗余什么的。

    所以,到底啥是scalability,可扩展性呢?

    1. 一个开头

    所有的可拓展性,都来源于这个哲学两问:

    1. 你进来的数据越来越多,你怎么读?

    2. 你要处理的数据越来越多,你怎么存?

    你看,一进一出,一个很大的问题抽象下来,这就是我们要全部考虑的。如果你觉得太哲学了,我们把知乎程序员们天天挂在嘴边的关键字举个例子。进来的数据怎么读:这是不是均衡负载,缓存,读取分布优化,网关等等现实的例子?处理的数据怎么存,这更加直观了,我们分布式系统,云就是用来堆机器去存所谓的“大数据的”。这些经常装逼用的词语,一个个都是为了回答这两个关键疑问的。

    2. 纵向拓展/横向拓展 horizontal & vertical

    明白了问题,我们用一个现实的故事去把这个问题铺开来。毕竟这些伟大的工程发明,都是源自于我们现实的需求。

    有个村子,村子有个老发电站,是十年前村长带着十个壮汉建的。结果这几年村子经济搞得不错,村里现在又1000口人了,电不够了,怎么办?

    纵向拓展:我们在原来的这个发电站里面,换更加牛逼的发电机,从法国买,或者加大功率。这样我们的电就够用了。(一个发电站,更大能力)

    横向拓展:我们去村东边,在建一个一样的发电站。(多个发电站,能力不变)

    这两种方法区别是什么呢?纵向拓展看起来很简单,我们不用去铺新的线,也不用雇佣那么多壮汉。而横向拓展,我们还要重新铺线,弄卡车运东西,雇人等等,这就开销大了。

    可是可是,这是三次元的世界。反直觉的是,在程序的世界中,横向拓展(加发电站)是比纵向拓展更加便宜的!这也是大数据能够火起来的原因。做一个超算,堆CPU堆内存,堆到后面就非常昂贵的,而且收益递减。但是我们如果用很多超级便宜的破机器做横向拓展,不仅便宜,而且效果还不错!

    有人说问了,那你如果这样,建了新发电站,你的不得重新铺线,雇人修,弄变压器,重新弄很多一样别的东西?这就是程序世界和现实世界不一样的地方,这些东西全部都在代码逻辑里面,这届复杂的逻辑费的是程序员的青春,而不是真的铜铁铝。大厂可不缺程序员,而且代码复制的成本是可以忽略不记的。

    这一段解释了我们为什么会用横向拓展(云),而不是纵向拓展(超算)

    3. 大量的读/写 Read/Write Heavy

    我们知道为什么多加机器就会让你的程序更加厉害了。话题更加细一些,关于我们的哲学第一问,怎么读海量的数据呢。

    重读(read heavy) 的扩展自然是从优化负载(load balance)开始的。我们要让读的这个入口更加牛逼。其实最终的思路都会变成如下俩:

    1. 加更多机器去读海量的网络请求,每个机器处理一部分

    2. 加更多机器去做网关,告诉请求应该去哪里

    然后就开始套娃。一个请求来了,一个工具人小明把包裹均匀的丢给后面的工人abcd来处理。然后请求太多太多,连分发的工具人小明都处理不了了,就加好多的小明来发包裹。然后双十一来了,请求更加更加多了,就再加一层小明在小明们的前面,负责分发要再分发的这些包裹,无限套娃。

    重写(write heavy),这个就更加复杂了,因为重写一般都是包括了重读的。除了以上的问题,我们还面临一个新问题。

    储存

    加更多的储存,要不然爆炸了

    现在你看,我们引入了一个新的问题,这个储存可是一个瓶颈呀。你数据多了,写这些储存的速度跟得上吗?

    4. 海量的存储 Storage

    单独聊储存是因为,一个是我们已经把问题自然而然的的引到这里了,这是一个难点,还有一个原因是,这真的真的很难。

    程序的扩展是不难的。你的代码在各个机子里面是不太会变的,每个机器处理请求的样子也是一样的。你加了10台机子,你同一个代码在10个机器里面跑,你就真的能处理10倍的请求,ok搞定了。

    但是储存就是一个完全不一样的问题了,你要非常仔细的想一想,你会用什么结构去存你的数据呢?那么多数据你写下以后,读一次会不会很久呢?如果数据没了怎么办?你写的太密集太快了会不会卡?要是很多个机器在写一个地方怎么避免冲突?

    意识到这个难题以后,我们就明白,我们这个行业为什么叫大数据,不会叫大程序,大请求,大机器了,大程序员了。毕竟,一切的难点,还是在怎么对付数据中。

    5. CPU

    在聊怎么处理数据之前,我们需要理解一些计算机的基础知识,这是我们是否可以拓展的要害。首先是cpu,作为大脑,cpu是怎么和大数据相互制约的呢?下面我们要快速讨论一下这个分类。

    程序呢,可以分为两种:

    1. IO(input/output) 密集

    2. 计算密集

    Io密集的程序:瓶颈在硬盘读写,内存,网卡等。CPU没有满载,但是你的出入口都堵住了,比如你下个葫芦娃。

    计算密集的程序:要占用大量CPU计算,开线程等,比如你算个圆周率。

    那通常大家的业务,就是网站,我们这个网站请求要是多了,这个是IO密集,还是计算密集?是的,网络软件是典型的IO密集场景,那我们为什么还要讲CPU呢?问题来了,通常我们说的是请求特别多,不是请求数据量多(比如下个蓝光电影),而是请求本身的数量多(比如一秒群发一万个微信)。双十一虽然有百万级别的请求来到阿里的服务器,但是这个流量大么?还成,现在随便一个机器的网卡都是可以上1000mbps的,可以应付了。最大的问题反而是来自于CPU。这么多请求数量,一个请求都可以看做开了一个单独的线程。意味着我们要机器可怜的CPU要处理同一时间非常多个线程。网卡可以做大,CPU再厉害,也就几十个核。线程池很容易就爆炸了。所以莫种意义上,网站乍一看确实是IO密集型,但是在真的业务处理上,反而是CPU密集型。通过这一段的讨论,我们知道了CPU处理能力不足,是逼得我们多加机器的一个重大原因。

    另外一个常见的需要注意的点,就是编程的时候,一定要清楚一个请求会等待/运行多久。而且一定要吧程序写成非阻塞的,要不然任何一个长时间的请求,都会堵住后面所有的请求,一个个请求堵在你的机器里面,然后你的机器就爆线程了,爆线程的后果就是,之后所有的请求机器自动会丢弃或者直接失败。用户就看到500或者404,然后一个程序员半夜就被值班电话叫醒修电脑去了。

    6. 内存 Memory

    CPU密集一定伴随着内存密集,当然内存密集这个词是我自己造的。当你的CPU在开足马力大力干的时候,内存工作的频率,比起CPU,简直是龟速。如果你大脑的反应速度和CPU一样快,你看内存就像看疯狂动物城里面那个树赖一样。CPU经常要等内存半天。编程的时候一定要注意到你的代码是怎么和内存协调的,下面是几个重要的点:

    永远要清楚,你请求拿到数据后,你要大概知道要用多少内存,你要是写的时候盲写,乱搞。。。这以后是一定会出大事儿的。

    永远不要放超过内存的东西(废话),尤其尤其是在你读一个你根本不知道有多少行的数据库的时候。

    永远不要读的时候用顺序读取,异步!异步!不然读一个数据的时候,会挡住后面所有的代码。我们边上有个组曾经有个做机器学习的,写了个网络应用,每次一上来启动,整个网页都是冻住的。一看逻辑,居然后来每次都会等着去读一个3GB的训练用数据集txt。

    我们看一下下面整个例子吧:

    垃圾例子:

    SELECT *

    FROM tablename

    ORDER BY RAND()

    LIMIT 1;

    这个简直爆炸,整个table被读了进来,你的table长了多大,你的内存就被占多少

    好一点点:

    SELECT @rand := ROUND((RAND() * MAX(id)))

    FROM tablename;

    完美

    SELECT *

    FROM tablename

    WHERE id >= @rand

    LIMIT 1;

    这就是个好例子,不管你的数据量怎么变大,你的程序都是可以适应变化,快速给出结果的。

    7. 储存 Storage

    终于我们讲到这个重要的点了,储存

    我们经常存的有视频,图片。我们一般都知道这些东西很大,所以都会小心一些。那么那么真的到工作里,最大的问题就是存表格(Table)了。

    一般普遍的做法,就是把这些数据打散拆开,放到不同的机子上去。然后我们用一个机子再去开一个新表格,新表格记录这些数据在哪个机子上。当数据越来越多,这个表格长的越来越大的时候,这个表格在软件逻辑上是一个完整的表格,但是物理上可能是在几百台不同的机子上散落着。问题来了,当我们对这个表做一个join的时候,woc,酸爽了,不加个进度条,客户还以为自己电脑死机了。

    那么有没有更加强大的方法呢?

    Sharding 分片

    数据特别多的时候,我们怎么存呢?随便一次query都要查看几百万行。那么我们自然想到的是,把数据分到多个机器来存取。那么问题来了,一个巨大的表格,我们怎么分?怎么合理快速的找到我散落的各种数据?

    Sharding 分片技术,就是为了解决这个问题提出来的。一个表格,我们是横着分还是竖着分?分片技术就是我们把一个表分开,但是表的Schema不变,schema翻译叫做模式,但是这么说太反人类了。举个栗子吧。

    原本表格长这样

    我们用不好的方法

    分成了上面两个列,这个的问题就是我们之前说的,遇到一个join,就爆炸了。

    用sharding的话,每个表都是不变的,只是数据分割了

    这个的好处就是,每个机器都拥有schema完整的表,每个列都是齐全的。

    一个简单例子,你有个博客网站。用一个机器是服务一个有几万列博客数据表,机器是吃不消的,但是我们用sharding的话,我们可以把每个人的博客放到每个机器上。一个机器上存有一个用户完整的blog。这样每次读取的时候很快,不会有join的问题。

    在举一个复杂的例子,比如facebook这种社交网络,好多好多用户,每个用户又有好多好多数据,什么照片id,兴趣,文章,转发等等。我们怎么分配呢?和blog一样,我们是按照用户 id来分,每个user id下的所有数据都分在一个机器里面。

    但是,上面的例子都是简单的场景,当我们请求一个用户的数据的时候,我们们只会访问一个服务器。如果我们比如打开微信朋友圈,那怎么办?我们要同时查好多服务器,一个个问每个人的状态吗?

    我们就不进一步讨论了,如何分片,是一个业界很火热的话题。但是我们知道,所有的分段的方法,都是跟着业务场景来的。由于摩尔定律,硬件的增长速度甚至比业务需求还要快,对于大多数公司来说,不用去烦恼这种问题。

    更多的细节可以去看 Jurriaan Persyn 的一篇特别好的文章。这文章写了他们公司是怎么分段Netlog的数据库。(争取以后翻译这个!)

    https://planet.mysql.com/entry/?id=17499​planet.mysql.com

    8. 数据库的复制和备份 replication

    看到这,我们讨论的问题其实已经讨论完了,剩下的这些是对scale这个知识的补全。

    数据库的备份说白了其实就是,建立一个主数据,然后在建立几个小数据库。

    数据永远都只会往主数据库里面写,然后主数据库会自动往小数据库备份。

    用户读的时候,会从小数据库里面读取。

    这个的好处是,如果你的数据好多好多,怎么去应付这么多流量,增加小数据库就可以了。

    如果有很多写入呢?我们把问题就都集中在了这个主服务器了。不继续讨论

    9. 缓存 cache

    缓存!就是内个魔法子弹(就类似咱们说的锦囊妙计)。

    缓存就是存取那些,经常会重复读取的内容。或者存取一些读起来非常昂贵的内容。

    缓存可以是各种的形式:内存中的缓存,redis服务器,硬盘缓存等等。一切的出发点都是,让读取数据比执行一遍请求更快。

    使用缓存后,你的代码也会变得很复杂。你不仅要从不同的地方去读取你的数据,你还得去保持你的缓存里面的数据是正确,同步的。我记得我上班的时候就出过一次事故,我们数据库里面的数据都是用户的,但是用户往数据库里面更新了自己的新的app后台数据后,显示出来缺永远是旧的。结果一查,北美地区一个服务器的缓存不同步,不会更新。然后就爆炸了,我们最后人为的帮内个弄出问题的team擦屁股,去azure上手动清缓存。

    10. 网络 network

    终于到最后了,拓展的各个点我们都聊过了,现在是网络。网络一般都不是最大的问题。如果你不去刻意限制,网络一般都是够用的。

    网络的延迟,一般不是传输的时候产生,而是当你做出,连,这个动作的时候。当你和你的数据库建立了连接,当你和远程主机建立连接。这是醉花时间的。所以要小心,不要随意的去建立大量无需的一个个单独连接请求,而是去一块数据一块数据的做请求,bulk request。而且写代码的时候,预见你的数据。提前规划,你要什么数据,一次就拿到。

    11. 后记

    以上就是我们所有和拓展性有关的点了!洋洋洒洒,范略的走过了一遍。

    希望这个能让大家有个大概的概念,明白如果你要拓展你的服务,你大概脑子中会有哪些方方面面。有些朋友觉得这个文章很隔靴搔痒,确实这里聊得很浅,希望借助这个文章提到的方面,大家进一步根据自己的兴趣,去这些知识点里面进一步探索。

    我个人入行很短,也是大数据的火热赏了我一口饭吃,scale这个事儿并不是一个知识,而是一个世界。10亿人数据,百亿的并发,这是已经是人类工程学的世界难题了。

    我记得我曾经参加过一次事故,半夜我们看到网关在加拿大服务器挂了,我们第一个反应当然先灭火,加一倍网关的数量去应付流量。可以还是不够,于是问题来了,是继续加倍,还是关掉网关后面运行的这个有问题的服务?这可不是斗地主,赌一赌加倍单车变摩托的。

    我们仔细一查,看到我们网关后面有个视频app客户的流量是别人服务的500倍,这视频网站也不是p站,怎么会突然有这么多流量??怎么办?继续翻倍?还是直接对这个视频app客户限流?因为不限流的话,这个视频app服务器的流量会直接爆掉我们所有别的客户的流量。最后我们决定加大一倍网关,然后开启部分限流,让所有新的请求直接失败,只保留现有的流量。采取措施以后,服务都健康了。两天以后一问原因,是加拿大突然有很多小学那一天用内个视频软件网络直播教学,所以突然爆掉了。而我们这个视频team根本没有遇见到这个。

    所以,如何服务更多的人?这可能是一个永远的问题。计算机让一个人解放了双手,而分布式系统让几亿人解放了双手。第一篇文章,感谢你的阅读。

    引用:

    封面图,来自wlop

    相关文章

      网友评论

          本文标题:当我们在说扩展性时,我们在说什么

          本文链接:https://www.haomeiwen.com/subject/fljyahtx.html