极客时间已完结课程限时免费阅读

36 | 业务状态与存储中间件

36 | 业务状态与存储中间件-极客时间

36 | 业务状态与存储中间件

讲述:丁伟

时长10:56大小9.99M

你好,我是七牛云许式伟。
相比桌面程序而言,服务端程序依赖的基础软件不只是操作系统和编程语言,还多了两类:
负载均衡(Load Balance);
数据库或其他形式的存储(DB/Storage)。
存储在服务端开发中是什么样的一个地位?今天我们就聊一下有关于存储中间件的那些事情。

业务状态

让我们从头开始。
首先我们思考一个问题:桌面程序和服务端程序的相似之处在哪里,不同之处又在哪里?对于这样一个开放性的问题,我们不同人可能有非常不同的答案。
今天让我们从数据的视角来看这个问题。
我们知道,一个桌面程序基本上是由一系列的 “用户交互事件” 所驱动。你可以把它理解为一个状态机:假设在 i 时刻,该桌面程序的状态为业务状态i ,它收到用户交互事件i 后,状态变化为业务状态i+1 。这个过程示意如下:
业务状态i+1 = F( 用户交互事件i ,业务状态i )
用状态转换图表示如下:
那么,服务端呢?
仔细考虑你会发现,其实服务端程序可以用一模一样的模型来看待。只不过它不是由 “用户交互事件” 来驱动,而是由 “网络 API 请求” 所驱动。
你同样可以把它理解为一个状态机:假设在 i 时刻,该服务端程序的状态为业务状态i ,它收到网络 API 请求i 后,状态变化为业务状态i+1 。这个过程示意如下:
业务状态i+1 = F( 网络 API 请求i ,业务状态i )
用状态转换图表示如下:
那么,桌面程序和服务端程序的差别在哪?
它们最大的差别是业务状态的表示不同。
桌面程序的业务状态是如何表示的?内存中的数据结构。我们在上一章中提到,桌面程序的 Model 层是一棵 DOM 树,根结点通常叫 Document。这棵 DOM 树其实就是桌面程序的业务状态。
服务端程序的业务状态如何表示?用内存中的数据结构可以吗?
答案当然是不能。如果业务状态在内存中,服务端程序一挂,数据就丢了。
前面我们在 “34 | 服务端开发的宏观视角” 提到过:
服务端的领域特征是大规模的用户请求,以及 24 小时不间断的服务。
这句话是理解服务端体系架构的核心,至关重要。但某种意义上来说更重要的原则是:
坚决不能丢失用户的数据,即他认为已经完成的业务状态。
服务端对用户来说是个黑盒,既然用户收到某个 “网络 API 请求” 成功的反馈,那么他会认为这个成功是确认的。
所以,服务端必须保证其业务状态的可靠性。这与桌面程序不同,桌面程序往往需要明确的用户交互事件,比如 Ctrl+S 命令,来完成数据的存盘操作,这时业务状态才持久化写入到外存。而且对于大部分桌面程序来说,它并不需要支持持久化。

存储中间件与容灾级别

在没有存储中间件的情况下,服务端需要自己在响应完每一个网络 API 请求之后,对业务状态进行持久化。
听起来这好像不复杂?
其实不然,服务端程序的业务状态持久化难度,比桌面程序要高很多。还是同样的原因,桌面程序是单用户使用的,持久化的时候什么别的事情也不干,看起来用户体验也可以接受。
但是对服务端程序而言,如果我们在某个 API 请求完成并持久化的时候,其他 API 请求如果只能排队等着的话,往轻了说服务的吞吐能力太差了;往严重里说,在持久化执行的那个时段,服务端在用户眼里就停止服务了。所以持久化的时间必须要足够短,短到让人感知不到服务停顿。
服务端程序的业务状态并不简单。这是一个多租户的持久化状态。就算一个用户的业务状态数据只有 100K,有个 100 万用户,那么需要持久化的数据也有 100G。这显然不能用“常规桌面程序每次完全重新生成一个新文件”的持久化思路做到,它需要被设计为一种增量式的存储系统。
如果每一个做服务端程序的开发人员需要自己考虑如何持久化业务状态,这个代价显然过高了。
于是,存储中间件就应运而生了。
从历史上来看,第一个存储中间件是数据库,出现在 1974 年,它就是 IBM System R。
这一年 Internet 刚刚被发明出来。所以数据库的诞生背景,很可能是为工作站服务的,也算网络服务的范畴。
桌面程序很少用数据库。只有一些需要增量持久化业务状态的场景会被采用,比较典型的是微信。微信的本地聊天纪录应该是基于数据库存储的,只不过用的是嵌入式数据库,比如 SQLite。
最早期人们对存储中间件的容灾级别要求并不高。数据库都是单机版本,没有主从。人们对存储中间件的诉求是高性能的、稳定的、经过验证的。数据的可靠性如何保证?晚上选个服务的低峰时期对数据库做个离线备份就完事了。
对服务端开发来说,数据库的出现是革命性的,它大大提升了开发效率。
但在容灾级别这个事情上,随着互联网的普及,我们对它的要求越来越高。
首先,单机数据库是不够的,需要多机相互热备,这就是数据库主从结构的来由。这样我们就不需要担心数据库单机故障会导致服务临时不可访问,甚至出现更严重的数据丢失。
其次,单机数据库是不够的,单机存储量终归有上限,这样我们服务的用户数就有上限。在分布式数据库出现之前,人们的解决方案是手工的分库分表。总之,业务上我们需要做到规模可伸缩,不必担心单机物理存储容量的限制。
最后,单机房的可靠性也是不够的,机房可能会出现网络中断,极端情况下还可能因为自然灾害,比如地震,导致整个机房的数据丢失。于是就出现了“两地三中心”,跨机房容灾的数据灾备方案。

存储即数据结构

那么问题来了,数据库能够解决所有服务端程序的业务状态持久化需求吗?
答案当然是不能。
对比桌面程序我们能够知道,业务状态其实就是数据结构。虽然数据库这个数据结构的确通用性很强,但是它不是银弹,在很多场合下它并不适用。
存储即数据结构。
存储中间件是什么?存储中间件就是 “元数据结构”。
这个结论的逻辑在于下面几个方面。
首先,和桌面开发不同,桌面端的数据结构基本上都是基于内存的,实现难度较低。但是在服务端不同。我们每一次的业务状态改变都需要考虑持久化,所以服务端的核心数据结构都是基于外存的。
其次,服务端的数据结构对稳定性要求、并发性能(IOPS)要求极高。简单分析就可以知道,服务端程序的伸缩能力完全取决于存储的伸缩能力。
业务服务器往往是无状态的,压力大了新增加一台业务服务器非常容易。但是存储压力大了,并不能简单加一台机器了事,可能涉及数据的重新划分和搬迁工作。
这意味着,在服务端实现一个数据结构是非常困难的。我们举一个很简单的例子,在内存中我们实现一个 KV 存储非常容易,很多语言都有 Dictionary 或者 Map 这样的数据结构来做这事。就算不用库,我们自己花上几十分钟或一个小时来实现,也是非常轻松的一件事情。
但是,一个服务端的 KV 存储非常非常复杂,绝非一个人花上一天两天就可以干出来。就算干出来了,也没人敢立刻投入使用,需要经过非常庞大的测试案例进行方方面面的验证,才敢投入生产环境。并且,即使敢投入生产环境了,为了以策万全,刚开始往往也是采用“双写”的方式:同时使用一个成熟存储系统和我们新上线的存储。
存储系统的品控,至关重要。
正因为服务端的数据结构实现如此之难,所以对于服务端来说,所有业务需要涉及的数据结构都需要抽象出来,成为一个存储中间件。
存储中间件会有多少?
这与服务端开发的模型抽象有关。今天没有比较系统性的理论告诉大家,有了这样一些数据结构就完备了。但是从更长远发展的角度来看,我们很可能需要回答这个问题。
所以,存储中间件是 “元数据结构”。
这里说的 “元数据结构”,是我自己发明的一个词。它表达的含义是,数据结构的种类是非常有限的,并且最好理论可被证明,有了这样一些基本的数据结构,所有的业务需求都可以高效地实现。这些基本的数据结构,就是我说的 “元数据结构”。
今天我们接触的存储中间件有哪些?不完整的列表如下:
键值存储(KV-Storage);
对象存储(Object Storage);
数据库(Database);
消息队列(MQ);
倒排索引(SearchEngine);
等等。
目前看,存储中间件的种类是不可枚举的。但它很可能只是受限于我自己的认知,也许有一天我们能够在这个问题上找到更加完美的答案。

结语

今天我们从桌面端程序和服务端程序的业务状态开始,探讨了存储中间件的由来。
前面我们在 “34 | 服务端开发的宏观视角” 提到过:
服务端的领域特征是大规模的用户请求,以及 24 小时不间断的服务。
这句话是理解服务端体系架构的核心,至关重要。但某种意义上来说更重要的原则是:
坚决不能丢失用户的数据,即他认为已经完成的业务状态。
存储即数据结构。存储中间件就是 “元数据结构”。
对于服务端来说,存储中间件至关重要。它不只是极大地解放了生产效率,也是服务端的性能瓶颈所在。几乎所有服务端程序扛不住压力,往往都是因为存储没有扛住压力。
如果你对今天的内容有什么思考与解读,欢迎给我留言,我们一起讨论。下一讲我们将聊聊数据库。
如果你觉得有所收获,也欢迎把文章分享给你的朋友。感谢你的收听,我们下期再见。
分享给需要的人,Ta购买本课程,你将得20
生成海报并分享

赞 15

提建议

上一篇
35 | 流量调度与负载均衡
下一篇
37 | 键值存储与数据库
unpreview
 写留言

精选留言(27)

  • 有铭
    2019-08-27
    补充一下:第一个数据库的头衔并不能戴在IBM System R上,它只是第一个广为人知的关系数据库模型。在关系模型之前,也会有其他的模型。1966年IBM就开启了一个数据库项目:IBM Information Management System,简称IMS。IMS用的是一个层次模型。和关系模型里面完全摊平的表结构不一样,层次模型里面的数据有层次的概念。某种程度上来说,你可以理解为比较像类似今天MongoDB这样的文档数据库,或者某种形态的图数据库。这个简称为IMS的系统1968年发行了第一个版本。大企业蜂拥而至。卖的不是一般的好。而且奇迹一般的,到今天还有很多的客户跑在IMS上,这个古董堪称生命力顽强。 然后此时要提到一个关键人物:Edgar Frank Codd,英格兰人,早年学习数学和化学。二战时候是飞行员。二战后来到美国给IBM服务。后来因为美国麦卡锡风潮辗转去了加拿大。之后又回美国IBM工作,顺便去密西根大学拿了一个PhD。Edgar Codd的PhD做的是冯诺依曼架构计算模型的扩展,非常的理论。1970年在加州圣何塞硅谷实验室里工作的他公开发表了一篇论文:A Relational Model of Data for Large Shared Data Banks。翻译成中文就是一个为大容量共享数据银行设计的数据的关系模型,提出了数据的关系模型,也就是著名的关系代数。 Edgar Codd最初提出关系模型的时候,他以为好日子很快就要到来了。但是IBM并不是很愿意去实现这个模型,IBM对Edgar Frank Codd的关系模型的态度很暧昧:不拒绝,不反对,但是也不给钱做系统。现在回头去看究其原因是怕影响了自己已经有的IMS这个层次模型数据库的钱。 但是,Codd也是一个非常顽强的人,他就去找IBM的大客户,给大客户们洗脑说关系数据库才是未来,层次是过去。大客户们被洗的都信了关系代数神教以后就回头找IBM,说赶紧给爸爸们做一个关系数据库出来。IBM不怕Codd,但是经不住客户金主爸爸们反复要求,就在自己的Future System里加了一个新的研究对象:System R。Future System项目是IBM1970年前后开展的一个大型研究项目,为的是开发出革命性的新软件和硬件——从名字就可以看出这东西本质是想做一个“系统”,而不是现在意义上的“数据库软件”。当时如日中天的IBM可谓浩浩荡荡的撒钱。System R团队成立于1973年。里面包括了后来很多在数据库圈里声名显赫的人,包括后来的图灵奖获得者Jim Gray。当然,也不知道IBM怎么想的,IBM把System R团队和Codd给隔离开来了。 可以看出直到现在IBM还是看关系模型不顺眼,但是很快的,加州伯克利大学的Ingres(这就是后来著名的PostgreSQL的前身),以及甲骨文在1978年开始入场。IBM这才发现大势所(不)趋(妙),加快研发速度搞出了DB2,随后Ingres商业化,甲骨文发布oracle加入竞争。关系数据库至此广泛的出现在大众视野面前
    展开

    作者回复: 多谢补充

    共 3 条评论
    31
  • 诗泽
    2019-08-27
    老师今天讲的存储即数据结构可以这样理解:类比于桌面程序,服务端的系统状态也是存储于某些数据结构中,通过持久化这些数据结构来持久化服务的状态,这样服务重启或者扩容的时候可以利用这些数据来恢复服务状态,而存放持久化数据的存储系统即可被认为是内存外的数据结构。内存类型的数据结构有list map set 等,对应的内存外的数据结构类型有kv数据库,关系型数据库,对象储存,倒排索引等即“元数据结构”

    作者回复: 👍

    18
  • skye
    2019-10-26
    老师,为啥数据库叫中间件?数据最后才存数据库里的呀

    作者回复: 我自己是习惯把所有操作系统之上应用程序之下的都叫中间件。

    共 2 条评论
    17
  • Eternal
    2019-11-10
    存储中间件是抽象的存储接口,是稳定点; 同的存储元数据是具体的实现,是变化点; 比如:MYSQL的元数据是一棵 B+树,MongDB的元数据是一个Docment文档,Redis的元数据是 key-value 分布式场景下,最大的瓶颈是存储中间件的压力,因为服务端程序依赖存储中间件来持久化多用户的的状态变化数据, 当用户量非常大的时候,服务实例可以容易伸缩,但是数据的伸缩却不是那么容易,老师讲的这个点印象很深
    展开
    5
  • 小文同学
    2019-08-29
    老师对抽象架构的讲解真是让人醍醐灌顶!
    5
  • williamcai
    2019-08-29
    老师,消息队列不是消息中间件里么,为啥属于存储中间件

    作者回复: 消息中间件是从功能来说的,存储中间件是从分类来说。

    4
  • 靠人品去赢
    2019-08-27
    老师,这个把存储中间件看成一个元数据结构,举个例子:数据库是不是我可以看成是一个B+树结构的元数据结构,是不是这意思?

    作者回复: 不需要看实现,我们看使用界面(接口)。接口是什么数据结构,就认为是什么数据结构。

    5
  • 逆流的鱼
    2019-09-05
    不明白服务端为什么比桌面程序实现kv更难,我理解桌面端能在内存那是因为服务端帮他实现了吧,区别不应该在一个是单用户的数据量级和全量数据的区别吗?

    作者回复: 是质量要求的差别

    2
  • leslie
    2019-08-27
    老师今天的课回答了之前的之前上堂课问老师的问题:其实均衡是各个存储中间件的平衡;老师提到了持久化,可是目前业界大量的不落地或者为了数据的一致性定期落地。 存储中间件对于硬件所在的位置不同:MQ主要是基于PageCache、内存库主要其实访问的是内存、传统数据库其实不少时候还是在硬盘;几者之间的平衡性把握如何把握。 目前就是生产碰到困惑:关系型数据库无法满足现状,追加了内存库可是效果不是很好,目前在极客时间学习《消息队列高手课》,希望跟着老师学完后能找到一些思路;希望老师在下节课讲数据库时能把消息队列、内存库、关系型数据库同时结合分享一下老师的经验。
    展开

    作者回复: 多谢建议

    1
  • sam
    2019-08-27
    “存储中间件”从名字看来,我的理解是对数据库读写的公共层API封装,为何是 “元数据结构”不是很了解

    作者回复: 数据库只是一种存储中间件

    1
  • tradeoff
    2021-09-18
    所有事情,状态一定是复杂的,相当于有了时空的属性,复杂的事情常需要抽象和扩展。所以业务系统,可理解为业务逻辑在有业务状态数据的应用,而瓶颈就是业务状态数据的存储可用、可靠性,IO高效性。算是一种能力下沉。又是分层设计
  • 木木
    2021-08-25
    倒是对后端开发提供了另一种思维
  • 不温暖啊不纯良
    2021-04-22
    服务端程序对数据库的依赖为什么那么大?主要是因服务端的数据规模大,和用户对数据可靠性的需求。 其实就像是CPU根据时间片执行不同线程的程序一样,当CPU要切换时间片的时候,需要把当前没有执行完的任务状态保存起来,等下次再轮到这个任务的时候,可以接着上次的进度继续执行。 这就像用户在操作不同业务对象的时候,比如我在这里留言,写着写着写着写不下去了,然后就切换到文章页面再看看,可是当我再回到留言页面的时候,我刚才所写的内容是依然存在的,也就是说这个APP系统将我没有执行完的业务状态和数据保存了起来,方便我再次使用的时候能够接着上次的进度。 在服务端我们操作业务的时候,其实是在操作一个个数据结构,需要持久化的时候,将这些数据持久化到外存中,外部那些用来存储数据结构的存储中间件,叫做元数据结构。是因为这些数据库,不管是关系型数据库还是对象存储数据库,本质上都是定义了一系列元数据,比如库名、表名、字段名、索引、文档等来存储这些数据结构,所以这些数据库其实就是由一个一个的元数据组成,统称为元数据结构。
    展开
  • Run
    2021-03-01
    看了这些,我就很清晰的上道了
  • dovefi
    2020-06-21
    为什么叫做存储中间件,是元数据结构,首先,存储中间件的概念是什么? 数据最终存储的地方是哪里,外存,从这个角度看,文件系统就是存储中间件,因为,文件系统本身只是存储了元数据(比如数据存储在哪个扇区,偏移是多少等等)所以从这个角度上讲,他就是元数据结构,所以像数据库,s3等也算是存储中间键,不同的是,这个时候文件系统就是最终的存储地方了,这个就是分层的概念呀~~~
  • 喆里
    2020-04-25
    几乎所有服务端程序扛不住压力,往往都是因为存储没有扛住压力。----这个怎么理解? 实际中,有很多情况是cpu打满了,但是memory和io都正常;还有对于机器学习的模型训练来说,瓶颈也在cpu啊

    作者回复: 嗯,我是的是IT型业务,新兴的DT型业务不在此列

  • 糊李糊涂
    2020-03-08
    讲的太好了,工科生能把大家都平时知道一点都东西说的这么如心如理也是让人佩服。
  • Geek_04e22a
    2020-02-22
    关于服务端和桌面的存储的不同点。我思考了一下,桌面直接把kv放到内存,而且量也不大,稳定性要求不高。但是服务端需要把元数据落盘,并且当用户量很大的时候,对于服务端提出了很大挑战,所以有了中间价的出现,帮助服务端更快速的处理元数据。
  • 猫头鹰波波
    2020-02-01
    希望老师多增加一些实际案例,比如哪些场景使用哪个中间件,没有完美的架构,只有适合的场景
  • prader26
    2020-01-18
    原来应用程序之下,操作系统之上的都可以叫做中间件啊。