传统行业向互联网行业的转型
背景
2012年以后,因为移动互联网的兴起,随着网名数量的增多,需求变化大,用户群体大。导致已有的应用程序无法抗住大规模的并发,且版本迭代麻烦,扩展不够灵活,应对外界环境能力薄弱,所以微服务思想就应运而生了。
2014年微服务的概念传入中国,2015年左右国内大厂开始进行项目升级,转战微服务。2018年中小型企业也开始进行微服务架构升级。
传统行业的产品是必然要向互联网行业进行转型的,马云爸爸曾经说过:如果说传统制造业不拥抱互联网的话,那注定是死路一条。而转型的过程当中,底层的架构模式也不再是传统的单体架构了,而是全新的微服务架构模式。
马云曾说道:十五年以前,我在全国各地,至少两三年内讲过两三百次这样的演讲,提醒大家互联网、电子商务对各行各业会有冲击,但是没有人把这个话当回事情,那个时候我是Nobody,讲话等于白讲。但是今天,既然我已经有这样的资源,我还是要告诉大家,未来二三十年,这个世界的变化超过所有人的想象力,而且绝大部分人是很倒霉的。今天的传统企业如果依然固步自封,不接受新时代和新的商业模式,势必会被淘汰。
传统行业与互联网行业的区别
互联网发展史
web 1.0
用户只能搜索和阅读网络信息。比如中国的几大门户网站:搜狐、新浪、网易、腾讯,平台提供内容和数据,用户被动接受,和用户缺乏交互。
web 2.0
用户能够创造内容,并分享在网路平台上跟大家进行互动,而不再只是单纯的访问者;这种范式的发展重新定义了市场和商业模式。比如QQ、天涯、微博、淘宝、美团、滴滴,提供一个平台,用户你们自己玩。用户需要注册,用户和平台交互变得很强,用户和用户之间可以交流,数据几乎由用户产生。
web 3.0
网络在接受信息的同时,通过数据分析,能够根据用户的喜好产生出新的数据和信息并推送给用户。比如网易云音乐的推荐,搜索引擎的推荐,淘宝的商品推荐,地图应用的出行规划,堵车预测等等。其特征是使用 web 2.0 时代所产生的大量数据,更加精准、实时和深入的为用户提供服务。一个简单的例子:当你在淘宝上买了某件商品后,订单下方会出现很多类似商品推送。
总结
比如:你家楼下餐馆代表互联网,你饰演互联网用户。
WEB1.0时代:你晚上一进餐馆,老板给你上了一桌子菜,说兄弟都是你的吃吧!(不分析)你自己挨个尝试,因为你不知道哪个菜好吃。(缺乏交互)WEB2.0时代:你晚上一进餐馆,你说:老板来斤饺子。老板说:没有饺子有面条。你说来碗面条,老板给你上了一碗面条。(被动分析)或者,你不知道吃什么好,但是坐在你旁边的食客会告诉你哪个好吃。(用户交互)WEB3.0时代:你晚上一进餐馆,一进门老板就说:客官,来碗面条吧!你问为啥,老板说,你连续吃一礼拜面条了。(主动分析)WEB 3.0 是微服务、大数据、云计算、人工智能的时代。
技术架构演变
下图表示从单体应用逐渐转变为微服务应用。
单一应用架构
通俗地讲,“单体应用(monolith application)”就是将应用程序的所有功能都打包成一个独立的单元。当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。
特点
所有的功能集成在一个项目工程中;所有的功能打一个 war 包部署到服务器;应用与数据库分开部署;通过部署应用集群和数据库集群来提高系统的性能。
优点:
「开发简单」:一个 IDE 就可以快速构建单体应用;「便于共享」:单个归档文件包含所有功能,便于在团队之间以及不同的部署阶段之间共享;「易于测试」:单体应用一旦部署,所有的服务或特性就都可以使用了,这简化了测试过程,因为没有额外的依赖,每项测试都可以在部署完成后立刻开始;「容易部署」:整个项目就一个 war 包,Tomcat 安装好之后,应用扔上去就行了。群化部署也很容易,多个 Tomcat + 一个 Nginx 分分钟搞定。
缺点:
「妨碍持续交付」:随着时间的推移,单体应用可能会变得比较大,构建和部署时间也相应地延长,不利于频繁部署,阻碍持续交付。在移动应用开发中,这个问题会显得尤为严重;「不够灵活」:随着项目的逐渐变大,整个开发流程的时间也会变得很长,即使在仅仅更改了一行代码的情况下,软件开发人员需要花费几十分钟甚至超过一个小时的时间对所有代码进行编译,并接下来花费大量的时间重新部署刚刚生成的产品,以验证自己的更改是否正确。如果多个开发人员共同开发一个应用程序,那么还要等待其他开发人员完成了各自的开发。这降低了团队的灵活性和功能交付频率;「受技术栈限制」:项目变得越来越大的同时,我们的应用所使用的技术也会变得越来越多。这些技术有些是不兼容的,就比如在一个项目中大范围地混合使用 C++ 和 Java 几乎是不可能的事情。在这种情况下,我们就需要抛弃对某些不兼容技术的使用,而选择一种不是那么适合的技术来实现特定的功能。「可靠性差」:某个环节出现了死循环,导致内存溢出,会影响整个项目挂掉。**伸缩性差:**系统的扩容只能针对应用进行扩容,不能做到对某个功能进行扩容,扩容后必然带来资源浪费的问题。「技术债务」:假设我的代码库中有一个混乱的模块结构。此时,我需要添加一个新功能。如果这个模块结构清晰,可能我只需要2天时间就可以添加好这个功能,但是如今这个模块的结构很混乱,所以我需要4天时间。多出来的这两天就是债务利息。随着时间推移、人员变动,技术债务必然也会随之增多。
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。
特点
以单体结构规模的项目为单位进行垂直划分,就是将一个大项目拆分成一个一个单体结构项目。项目与项目之间存在数据冗余,耦合性较大,比如上图中三个项目都存在用户信息。项目之间的接口多为数据同步功能,如:数据库之间的数据库,通过网络接口进行数据库同步。
优点
开发成本低,架构简单;避免单体应用的无限扩大;系统拆分实现了流量分担,解决了并发问题;可以针对不同系统进行扩容、优化;方便水平扩展,负载均衡,容错率提高;不同的项目可采用不同的技术;系统间相互独立。
缺点
系统之间相互调用,如果某个系统的端口或者 IP 地址发生改变,调用系统需要手动变更;垂直架构中相同逻辑代码需要不断的复制,不能复用。系统性能扩展只能通过扩展集群结点,成本高、有瓶颈。
SOA 面向服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心。当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。
❝
P.S. 从软件设计的角度上来说,ESB 是一个抽象的间接层,提取了服务调用过程中调用与被调用动态交互中的一些共同的东西,减轻了服务调用者的负担。Java 编程思想里提到:“所有的软件设计的问题都可以通过增加一个抽象的间接层而得到解决或者得到简化!”简单来说 ESB 就是一根管道,用来连接各个服务节点。为了集成不同系统,不同协议的服务,ESB 做了消息的转化解释和路由工作,让不同的服务互联互通。
❞
特点
基于 SOA 的架构思想将重复公用的功能抽取为组件,以服务的形式给各系统提供服务。各项目(系统)与服务之间采用 WebService、RPC 等方式进行通信。使用 ESB 企业服务总线作为项目与服务之间通信的桥梁。
优点
将重复的功能抽取为服务,提高开发效率,提高系统的可重用性、可维护性。可以针对不同服务的特点制定集群及优化方案;采用 ESB 减少系统中的接口耦合。
缺点
系统与服务的界限模糊,不利于开发及维护。虽然使用了 ESB,但是服务的接口协议不固定,种类繁多,不利于系统维护。抽取的服务的粒度过大,系统与服务之间耦合性高。涉及多种中间件,对开发人员技术栈要求高。服务关系复杂,运维、测试部署困难
微服务架构
特点
将系统服务层完全独立出来,并将服务层抽取为一个一个的微服务。微服务中每一个服务都对应唯一的业务能力,遵循单一原则。微服务之间采用 RESTful 等轻量协议传输。
优点
团队独立:每个服务都是一个独立的开发团队,这个小团队可以是 2 到 5 人的开发人员组成;技术独立:采用去中心化思想,服务之间采用 RESTful 等轻量协议通信,使用什么技术什么语言开发,别人无需干涉;前后端分离:采用前后端分离开发,提供统一 Rest 接口,后端不用再为 PC、移动端开发不同接口;数据库分离:每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一数据库;服务拆分粒度更细,有利于资源重复利用,提高开发效率;一个团队的新成员能够更快投入生产;微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值;可以更加精准的制定每个服务的优化方案(比如扩展),提高系统可维护性;适用于互联网时代,产品迭代周期更短。
缺点
微服务过多,服务治理成本高,不利于系统维护;分布式系统开发的技术成本高(网络问题、容错问题、调用关系、分布式事务等),对团队挑战大;微服务将原来的函数式调用改为服务调用,不管是用 rpc,还是 http rest 方式,都会增大系统整体延迟。这个是再所难免的,这个就需要我们将原来的串行编程改为并发编程甚至异步编程,增加了技术门槛;多服务运维难度,随着服务的增加,运维的压力也在增大;测试的难度提升。服务和服务之间通过接口来交互,当接口有改变的时候,对所有的调用方都是有影响的,这时自动化测试就显得非常重要了,如果要靠人工一个个接口去测试,那工作量就太大了,所以 API 文档的管理尤为重要。
总结
分享两个小故事,帮助大家更好的理解 SOA 与微服务的区别。
故事一:
❝
很久以前的一天,Martin 在跟好友的交流中悟到了一种很棒的架构设计。他总结了一下,然后告诉了好友,好友说,这不是新鲜东西,早有人总结了,叫做 SOA。
Martin 很高兴,开始在公司内外推广 SOA。结果,不停有人质疑和挑战他。
你这不是 SOA 吧?SOA 这里应该是如此这般的。对,这里我对 SOA 的理解是这样的。你看,这本 SOA 的书说的和你说的有出入。粒度?SOA 没有谈到这个呀,你这不是 SOA。分层跟 SOA 没有关系,你为什么要说这个呢?…
Martin 没办法,心一横,老子就叫它 Martin's SOA。老子发明的词,老子就是最高权威,有最终解释权。还有谁不服?
同事们一看,这思想本身很不错,值得推广,但叫 Martin's SOA 太没品了吧?还是要取个好一点的名字,最好还能跟 SOA 有某种暗示传承。干脆就叫 Microservices 好了,又新,又有服务含在其中。
Martin 忿忿地接受了这个建议,心里想着:娘的,明明就是 SOA,一群**非要逼我取个新名字。
后来 Martin 发现每次提一个东西就会收到旧恶傻势力对解释权的挑战,所以每次要提一个什么概念,都去发明一个新词,免得一群人在那一边质疑挑战,一边大谈“我的理解”。
这就是微服务、敏捷、精益企业、持续集成、持续交付背后的故事。
一个名词产生之后,命名者的解释权就会随着时间而弱化(比如 Cooper 发明的 Persona 就被无数设计师乱用)。敏捷已经有点烂了,等微服务也烂了,我们还会发明新词。
实在没辙,都是被逼的啊。
❞
故事二:
❝
话说1979年,又是一个春天,莆田乡下的赤脚医生吴大牛被改革的春风吹的心潮澎湃,说干就干,吴大牛趁着夜色朦胧找大队支书汇报了汇报思想,第二天就承包了村卫生室,开启了自己的在医疗圈的传奇历程。
乡村诊所大家都知道,没什么复杂的小编,房子只有一间,一个大柜台中间隔开,一半是诊疗兼候诊区,一半是药房,看病就直接找医生,如果前面有人就自己找个位子坐下,排队等一会,秩序倒也井然,看完病了医生直接给抓药,然后下一个继续,也不需要护士和药剂师,吴大牛一个人全部包办。
辛辛苦苦忙碌了十年,时间来到了八九年,又是一个春天,昔日的单身汉吴大牛已成为十里八乡的知名人物,媳妇娶上了不说,家里还增加了一对双胞胎儿子,二层的小洋房也甚是气派。可是也有烦心事,尽管乡村诊所扩大到了两间,媳妇还偶尔能去帮帮忙,但是医生还是只有自己一个,天天从早忙到晚挣的都是一份钱,想多挣点怎么办?吴大牛日思夜想,还真给他想出来一招,怎么办,扩大规模,多招几个医生一起干。原来吴大牛只能治头疼脑热和跌打损伤,现在新招了一个医科大学的毕业生刘小明专治感冒发烧,又从邻村请来了老大夫李阿花专治妇科病,现在一个普通的小诊所就变成了有三个独立科室加一个公共药房(吴大牛媳妇负责)的小医院了,吴大牛是外科主任兼院长,收入那可比之前翻了三番。人逢喜事精神爽,大牛院长请县里的书法名家为新医院书写了牌匾--“博爱医院”,挑了一个黄道吉日正式挂了上去。
一晃十年过去了,又是一个春天,吴大牛的博爱医院已经发展到了内科外科妇科五官科骨科生殖科六个科室,每个科室3到5名医生不等,也耗费巨资购进了血液化验B超等先进仪器,大牛院长也早已脱离了医疗一线,成为了专职的管理者,但是医院的大事小事大家都找他,就这三十多号员工搞的他每天是焦头烂额,想再扩大规模实在是有心无力了。要说还是大学生有水平,老部下刘小明给大牛院长献了一计,把各个科室独立出去,让各个科室主任自己管理,大牛院长只管科室之间的协调和医院发展的大事,这样既能调动基层的积极性,又能把大牛院长解放出来扩大生产抓大事谋大事,岂不妙哉?就这样,博爱医院的新一轮改革轰轰烈烈的展开了。
又是一个十年,又是一个春天,大牛院长已成为本地知名的企业家,博爱医院也发展到了二十三个科室数百名员工,发展中也出现了新问题,由于各个科室独立挂号、收费、化验,有的科室整天忙忙碌碌效益好,有的科室就相对平庸些,连分到的各种检查仪器都不能满负荷运行,整个医院养了不少闲人。这时候大牛院长视野也开阔了,请来了管理专家进行了顶层设计,把原来分散到各个科室的非核心服务全部收归集中管理,把原来二十三个挂号窗口整合为十个,二十三个收费窗口整合为八个,集中布设在一楼大厅为全院服务,还把分散在各个科室的检查仪器集中起来成立独立的检验科,也为全院服务,这样人人有活干,整个医院的服务能力又上了一个新台阶,这轮改革后博爱医院通过了各级部门的鉴定成为了远近驰名的三甲医院,吴大牛也摇身一变成为了博爱集团的CEO兼董事长,下一步就准备IPO上市了。
说到这里大家可能有点糊涂,这个跟微服务有嘛关系?大牛诊所的1.0阶段就相当于软件开发的单体结构,一个程序员打天下,从头编到尾,很难做大做强。大牛诊所的2.0阶段就相当于软件开发的垂直结构,各科室按照业务划分,很容易横向扩展。博爱医院的1.0阶段就相当于软件开发的SOA结构,除了药房(数据库)外各个服务独立提供(科室主任负责),但需要大牛院长(ESB总线)来协调。博爱医院的2.0阶段就相当于软件开发的微服务结构,公共服务院内共享,科室主任管理功能弱化(只管医生业务),优点是扩容方便,哪个部门缺人直接加,不用看上下游,资源利用率高,人员和设备效率高。
❞
微服务就是将一个单体架构的应用按业务划分为一个个的独立运行的程序即服务,它们之间通过 HTTP 协议进行通信(也可以采用消息队列来通信,如 RabbitMQ,Kafaka 等),可以采用不同的编程语言,使用不同的存储技术,自动化部署(如 Jenkins)减少人为控制,降低出错概率。服务数量越多,管理起来越复杂,因此采用集中化管理。例如 Eureka,Zookeeper 等都是比较常见的服务集中化管理框架。
**微服务是一种架构风格,架构就是为了解耦,实际使用的是分布式系统开发。**一个大型的复杂软件应用,由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好的完成该任务。
❝
「一句话总结:微服务是 SOA 发展出来的产物,它是一种比较现代化的细粒度的 SOA 实现方式。」
❞
微服务设计原则
AKF 拆分原则
业界对于可扩展的系统架构设计有一个朴素的理念,就是:通过加机器可以解决容量和可用性问题(如果一台不行就两台)。
用个段子描述就是:世界上没有什么事是一顿烧烤解决不了的,如果有,那就两顿。
《The Art of Scalability》一书提出了一个系统的可扩展模型——AKF 可扩展立方。这个立方体中沿着三个坐标轴设置分别为 X,Y,Z。
❝
一个叫 AKF 的公司的技术专家抽象总结的应用扩展的三个维度。理论上按照这三个扩展模式,可以将一个单体系统,进行无限扩展。
❞
Y 轴
就是我们所说的微服务的拆分模式,就是基于不同的业务拆分。Y 轴扩展会将庞大的整体应用拆分为多个服务。每个服务实现一组相关的功能,如商品管理、订单管理、用户管理等。
X 轴
X 轴扩展指的是水平复制,通过绝对平等地复制服务与数据,以解决容量和可用性的问题。很好理解,就是将单体系统多运行几个实例,成为集群加负载均衡的模式。
Z 轴
Z 轴扩展通常是指基于请求者或用户独特的需求,进行系统划分,并使得划分出来的子系统是相互隔离但又是完整的。以生产手机的工厂来举例:苹果公司为了发展在中国的业务,或者利用中国的廉价劳动力,在中国建立一个完整的子工厂,与美国工厂一样,负责完整的手机生产。这就是一种 Z 轴扩展。
❝
场景说明:比如单体打车应用,一个集群撑不住时,分了多个集群,后来用户激增还是不够用,经过分析发现是乘客和车主访问量很大,就将打车应用拆成了三个,分别为乘客服务、车主服务、支付服务。三个服务的业务特点各不相同,独立维护,各自都可以再次按需扩展。我们可以水平扩展三个服务,形成各自服务的集群模式。实在不行最后根据北上广热门地区划分为多份,你在哪个城市打车,就给你展示哪个城市的司机数据分区。
❞
前后端分离原则
以前的 Java Web 项目大多都是程序员既当爹又当妈,既搞前端,又搞后端。随着时代的发展,渐渐的许多大中小公司开始把前后端的界限分的越来越明确,前端工程师只管前端的事情,后端工程师只管后端的事情。正所谓术业有专攻,大中型公司需要专业人才,小公司需要全才,但是对于个人职业发展来说,前后端需要分离,毕竟一个人如果什么都会,那么他可能什么都不精。
未分离
在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与后端的耦合度很高。
这种应用模式比较适合纯网页应用,但是当后端对接 App 时,App 可能并不需要后端返回一个 HTML 网页,而仅仅是数据本身,所以后端原本返回网页的接口不再适用于前端 App 应用,为了对接 App 后端还需再开发一套接口。
该时期代表:Servlet + Jsp + JavaBean
<body>
<%
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
System.out.print(username);
%>
</body>
半分离
前后端半分离,前端负责开发页面,通过接口(Ajax)获取数据,采用 Dom 操作对页面进行数据绑定,最终是由前端把页面渲染出来。步骤如下:
打开 WEB,加载基本资源,如 CSS,JS 等;发起一个 Ajax 请求再到服务端请求数据,同时展示 Loading;得到 Json 格式的数据后再根据逻辑选择模板渲染出 DOM 字符串;将 DOM 字符串插入页面中渲染出 DOM 结构;然而,在这种架构下,还是存在明显的弊端的。最明显的有如下几点:
JS 存在大量冗余,在业务复杂的情况下,页面的渲染部分的代码,非常复杂;在 Json 返回的数据量比较大的情况下,渲染的十分缓慢,会出现页面卡顿的情况;资源消耗严重,在业务复杂的情况下,一个页面可能要发起多次 HTTP 请求才能将页面渲染完毕。PC 端建立多次 HTTP 请求也没啥。这里需要考虑一下移动端的感受。该时期代表:SSM(Spring + SpringMVC + Mybatis)和 SSH(Spring + Struts2 + Hibernate)
分离
在前后端分离的应用模式中,后端仅返回前端所需的数据,不再渲染 HTML 页面,不再控制前端的效果。至于前端用户看到什么效果,从后端请求的数据如何加载到前端中,都由前端自己决定,网页有网页的处理方式,App 有 App 的处理方式,但无论哪种前端,所需的数据基本相同,后端仅需开发一套逻辑对外提供数据即可。
浏览器不再直接请求 JSP 的 API,而是:
浏览器请求服务器端的 NodeJS;NodeJS 再发起 HTTP 去请求后端;后端依然原样 API 输出 JSON 给 NodeJS;NodeJS 收到 JSON 后再渲染出 HTML 页面;NodeJS 直接将 HTML 页面 flush 到浏览器;这样,浏览器得到的就是普通的 HTML 页面,而不用再发 Ajax 去请求服务器了。
该时期代表:VueJS、AngularJS、ReactJS
总结
从经典的 Servlet + Jsp + JavaBean 的 MVC 时代,到 SSM(Spring + SpringMVC + Mybatis)和 SSH(Spring + Struts2 + Hibernate)的 Java 框架时代,再到前端框架(VueJS、AngularJS、ReactJS)为主的 MVVM 时代,然后是 Nodejs 引领的全栈时代,技术和架构一直都在进步。创新之路不会止步,无论是前后端分离模式还是其他模式,都是为了更方便地解决需求,但它们都只是一个“中转站”。前端项目与后端项目是两个项目,放在两个不同的服务器,需要独立部署,两个不同的工程,两个不同的代码库,不同的开发人员。前端只需要关注页面的样式与动态数据的解析及渲染,而后端专注于具体业务逻辑。
前后端技术分离,可以由各自的专家来对各自的领域进行优化,这样前端的用户体验优化效果更好。前后端分离模式下,前后端交互界面更清晰,就剩下了接口模型,后端的接口简洁明了,更容易维护。前端多渠道集成场景更容易实现,后端服务无需变更,采用统一的数据和模型,可以支持多个前端:例如:微信 h5 前端、PC 前端、安卓前端、IOS 前端。
无状态服务
对于无状态服务,首先说一下什么是状态:如果一个数据需要被多个服务共享,才能完成一笔交易,那么这个数据被称为状态。进而依赖这个“状态”数据的服务被称为有状态服务,反之称为无状态服务。
这个无状态服务原则并不是说在微服务架构里就不允许存在状态,表达的真实意思是要把有状态的业务服务改变为无状态的计算类服务,那么状态数据也就相应的迁移到对应的“有状态数据服务”中。
场景说明:例如我们以前在本地内存中建立的数据缓存、Session 缓存,到现在的微服务架构中就应该把这些数据迁移到分布式缓存中存储,让业务服务变成一个无状态的计算节点。迁移后,就可以做到按需动态伸缩,微服务应用在运行时动态增删节点,就不再需要考虑缓存数据如何同步的问题。
也就是对同一个 url 请求没有上下文关系。举个生活中的例子:
❝
比如空调遥控器,你按上下调整温度时,空调温度设定值会变化,遥控器信号到空调是单向传输。现在空调显示温度 20 度,遥控器 20 度。如果遥控器与空调之间是有状态的,假设你离开空调接收范围调整了遥控器温度,变成 19,那回到范围内你按一次升高一度,基于原先温度状态,遥控器给空调发送一个“提高1度”的指令,就会出现遥控器提高到 20,而空调变成21。如果要空间与空调之前是无状态的,假设你离开空调接收范围调整了遥控器温度,变成 19,那回到范围内你按一次升高一度,遥控器给空调发送一个“设定温度值20”,这样两者最终还是相同的值。
❞
Restful 通信风格
基于**“无状态通信原则”**,在这里我们直接推荐一个实践优选的 Restful 通信风格 ,因为他有很多好处:
无状态协议 HTTP,具备先天优势,扩展能力很强。例如需要安全加密时,有现成的成熟方案 HTTPS 可用。JSON 报文序列化,轻量简单,人与机器均可读,学习成本低,搜索引擎友好。语言无关,各大热门语言都提供成熟的 Restful API 框架,相对其他的一些 RPC 框架生态更完善。
CAP 原则与 BASE 理论
CAP 原则
CAP 原则又称 CAP 定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
CAP 由 Eric Brewer 在 2000 年 PODC 会议上提出。该猜想在提出两年后被证明成立,成为我们熟知的 CAP 定理。CAP 三者不可兼得。
特性
定理
Consistency
「一致性」,也叫做数据原子性,系统在执行某项操作后仍然处于一致的状态。在分布式系统中,更新操作执行成功后所有的用户都应该读到最新的值,这样的系统被认为是具有强一致性的。等同于所有节点访问同一份最新的数据副本。
Availability
「可用性」,每一个操作总是能够在一定的时间内返回结果,这里需要注意的是"一定时间内"和"返回结果"。一定时间内指的是在可以容忍的范围内返回结果,结果可以是成功或者是失败,且不保证获取的数据为最新数据。
Partition tolerance
「分区容错性」,分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障。
取舍策略
CAP 三个特性只能满足其中两个,那么取舍的策略就共有三种:
「CA without P」:如果不要求P(不允许分区),则C(强一致性)和A(可用性)是可以保证的。但放弃 P 的同时也就意味着放弃了系统的扩展性,也就是分布式节点受限,没办法部署子节点,这是违背分布式系统设计的初衷的。「CP without A」:如果不要求A(可用),相当于每个请求都需要在服务器之间保持强一致,而P(分区)会导致同步时间无限延长(也就是等待数据同步完才能正常访问服务),一旦发生网络故障或者消息丢失等情况,就要牺牲用户的体验,等待所有数据全部一致了之后再让用户访问系统。设计成 CP 的系统其实不少,最典型的就是分布式数据库,如 Redis、HBase 等。对于这些分布式数据库来说,数据的一致性是最基本的要求,因为如果连这个标准都达不到,那么直接采用关系型数据库就好,没必要再浪费资源来部署分布式数据库。「AP without C」:要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。典型的应用就如某米的抢购手机场景,可能前几秒你浏览商品的时候页面提示是有库存的,当你选择完商品准备下单的时候,系统提示你下单失败,商品已售完。这其实就是先在 A(可用性)方面保证系统可以正常的服务,然后在数据的一致性方面做了些牺牲,虽然多少会影响一些用户体验,但也不至于造成用户购物流程的严重阻塞。
总结
现如今,对于多数大型互联网应用的场景,主机众多、部署分散,而且现在的集群规模越来越大,节点只会越来越多,所以节点故障、网络故障是常态,因此「分区容错性」也就成为了一个分布式系统必然要面对的问题。那么就只能在 C 和 A 之间进行取舍。但对于传统的项目就可能有所不同,拿银行的转账系统来说,涉及到金钱的对于数据一致性不能做出一丝的让步,C 必须保证,出现网络故障的话,宁可停止服务,可以在 A 和 P 之间做取舍。而互联网非金融项目普遍都是基于 AP 模式。
总而言之,没有最好的策略,好的系统应该是根据业务场景来进行架构设计的,只有适合的才是最好的。
BASE 理论
CAP 理论已经提出好多年了,难道真的没有办法解决这个问题吗?也许可以做些改变。比如 C 不必使用那么强的一致性,可以先将数据存起来,稍后再更新,实现所谓的 “最终一致性”。
这个思路又是一个庞大的问题,同时也引出了第二个理论 BASE 理论。
❝
BASE:全称 Basically Available(基本可用),Soft state(软状态),和 Eventually consistent(最终一致性)三个短语的缩写,来自 ebay 的架构师提出。
❞
BASE 理论是对 CAP 中一致性和可用性权衡的结果,其来源于对大型互联网分布式实践的总结,是基于 CAP 定理逐步演化而来的。其核心思想是:
❝
既然无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。
❞
Basically Available(基本可用)
基本可用是指分布式系统在出现故障的时候,允许损失部分可用性(例如响应时间、功能上的可用性)。需要注意的是,基本可用绝不等价于系统不可用。
响应时间上的损失:正常情况下搜索引擎需要在 0.5 秒之内返回给用户相应的查询结果,但由于出现故障(比如系统部分机房发生断电或断网故障),查询结果的响应时间增加到了 1~2 秒。功能上的损失:购物网站在购物高峰(如双十一)时,为了保护系统的稳定性,部分消费者可能会被引导到一个降级页面。
Soft state(软状态)
什么是软状态呢?相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种 “硬状态”。
软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据会有多个副本,允许不同副本数据同步的延时就是软状态的体现。
Eventually consistent(最终一致性)
系统不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性。从而达到数据的最终一致性。这个时间期限取决于网络延时,系统负载,数据复制方案设计等等因素。
实际上,不只是分布式系统使用最终一致性,关系型数据库在某个功能上,也是使用最终一致性的,比如备份,数据库的复制都是需要时间的,这个复制过程中,业务读取到的值就是旧值。当然,最终还是达成了数据一致性。这也算是一个最终一致性的经典案例。
总结
总的来说,BASE 理论面向的是大型高可用可扩展的分布式系统,和传统事务的 ACID 是相反的,它完全不同于 ACID 的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间是不一致的。
热门自学前端,java,大数据及项目实战(毕设)教程:
https://yjxxt520.github.io/