1.4 知识点关联
站在巨人的肩膀上
从上文中我们可以看到,Elasticsearch并非从0起步,重复制造轮子,而是站在巨人Lucene的肩膀上构建的。其实很多新技术都是基于已有的技术发展演进而来的,如最近几年火热的区块链技术。
1.REST协议
RESTful编程风格是近年来前后端流行的交互模式,在工作和面试中,有人会将REST协议与HTTP混为一谈,因此这里介绍REST协议的由来。
下面从几个维度来展开叙述:
① Web技术发展与REST的由来——讲历史。
② REST架构风格的推导过程——讲过程。
③ REST定义——讲定义。
④ REST关键原则——讲原则。
⑤ 总结REST风格的架构特点——讲特点。
⑥ REST架构风格的优点和缺点——讲辩证。
2.Web技术发展与REST的由来
Web技术基础有哪些?从技术架构层面上看,Web技术架构包括四个基石:URI、HTTP、HyperText、MIME(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展类型)。这四个基石相互支撑,相互助力,共同推动着Web这座宏伟的大厦以几何级数的速度迅猛发展起来。
在Web开发技术历程中,Web开发技术经历了5个阶段,分别是静态内容阶段、CGI (Common Gateway Interface)程序阶段、脚本语言阶段、瘦客户端应用阶段、RIA (Rich Internet Application)应用阶段和移动Web应用阶段。其中:
在静态内容阶段,Web由静态HTML文档组成,Web服务器有点像支持超文本的共享文件服务器。
在CGI程序阶段,Web服务器增加了编程API,研发人员可以通过CGI协议完成程序开发,这类应用程序被称作CGI程序。
在脚本语言阶段,服务器端先后出现了ASP、PHP、JSP、ColdFusion等支持session的脚本语言技术,浏览器端则出现了Java Applet、JavaScript等技术。基于这些技术,网站可以提供更加丰富的动态内容。
在瘦客户端应用阶段,在服务器端出现了独立于Web服务器的应用服务器,出现了Web MVC开发模式。基于这些框架开发的Web应用,通常都是瘦客户端应用。
在RIA应用阶段,出现了多种RIA技术,大幅改善了Web应用的用户体验,如最为广泛的RIA技术DHTML+Ajax,Ajax技术支持前端在不刷新页面的情况下动态更新页面中的局部内容,显著提升了用户体验。这一时期也诞生了大量的Web前端DHTML开发库,如Prototype、Dojo、ExtJS、jQuery/jQuery UI。其他的RIA技术还有Adobe公司的Flex、微软公司的Silverlight、Sun公司的JavaFX(现在为Oracle公司所有),等等。
在移动Web应用阶段,出现了大量面向移动设备的Web应用开发技术。除Android、iOS、Windows Phone等操作系统平台原生的开发技术外,基于HTML5的开发技术也变得非常流行。
从上述Web开发技术的发展过程可以得出结论,Web从最初其设计者所构思的主要支持静态文档的阶段,逐渐变得越来越动态化;Web应用的交互模式变得越来越复杂,从静态文档发展到以内容为主的门户网站、电子商务网站、搜索引擎、社交网站,再到以娱乐为主的大型多人在线游戏、手机游戏。
Web开发技术和REST之间有什么关系呢?上面提及Web技术架构包括四个基石,其中之一就是HTTP,下面简要介绍HTTP的发展历程。
1995年,CGI、ASP等技术出现后,沿用多年、面向静态文档的HTTP/1.0已无法满足Web应用的开发需求,因此需要设计新版本的HTTP。于是,HTTP/1.0协议专家组成立。在这些专家之中,有一位名叫Roy Fielding的年轻人脱颖而出,显示出了不凡的洞察力,后来Roy Fielding成为HTTP/1.1协议专家组的负责人。而Roy Fielding还是Apache HTTP服务器的核心开发者,更是Apache软件基金会的合作创始人。
HTTP/1.1的第一个草稿于1996年1月发布,后经三年多的反复修订和论证,于1999年6月成为IETF的正式规范。
2000年,Roy Fielding在其博士学位论文Architectural Styles and the Design of Network-based Software Architectures中,系统、严谨地阐述了这套理论框架,还使用这套理论框架推导出了一种新的架构风格,并且为这种架构风格取了一个令人轻松愉快的名字“REST”——Representational State Transfer(表述性状态转移)。
2007年1月,支持REST开发的Ruby on Rails 1.2版发布。特别的是,Rails将支持REST开发作为其未来发展的优先内容。Ruby on Rails的创始人DHH做了一场名为“World of Resources”的精彩演讲。DHH在Web开发技术社区中的强大影响力,使得REST一下子处在Web开发技术舞台的聚光灯之下。在Rails等新兴Web开发技术的推波助澜之下,Web开发技术社区掀起了一场重归Web架构设计本源的运动。REST架构风格得到了越来越多的关注,现在各种流行的Web开发框架几乎都支持REST开发。
而广大的开发人员也纷纷学习REST架构风格。当然大多数Web开发者都是通过阅读REST开发框架的文档,以及通过一些例子代码来学习REST开发的。不过,通过例子代码来学习REST有非常大的局限性,因为REST并不是一种具体的技术,也不是一种具体的规范,而是一种内涵非常丰富的架构风格。
虽然通过例子代码来学习REST,能“短平快”地学习到一种有趣的Web开发技术,但并不能全面深入地理解REST究竟是什么,甚至还会误以为这些简单的例子代码就是REST本身,以为REST不过是一种简单的Web开发技术而已。这有点类似像盲人摸象,有的人摸到了象鼻子、有的人摸到了象耳朵、有的人摸到了象腿、有的人摸到了象尾巴。摸象的众人都坚信自认为感觉到的大象才是最真实的大象,而其他人的感觉都是错误的,但现实往往恰恰相反。
3.REST架构风格的推导过程——讲过程
Roy Fielding在批判性继承前人研究成果的基础上,建立起了一整套研究和评价软件架构的方法论。这套方法论的核心是“架构风格”这个概念。
架构风格是一种研究和评价软件架构设计的方法,它是比架构更加抽象的概念。一种架构风格是由一组相互协作的架构约束来定义的。架构约束是指软件的运行环境施加在架构设计之上的约束。
Roy Fielding的REST架构风格的推导过程如图1-2所示。
图1-2
每一个椭圆形里面的缩写词代表了一种架构风格,而每一个箭头边的单词代表了一种架构约束。其中:
● RR(Replicated Repository)可译为复制仓库。RR利用多个进程提供相同的服务,来改善数据的可访问和可伸缩。
● COD(Code-On-Demand),可译为按需代码。
● $表示Cache,指的是复制个别请求的结果,以便可以被后面的请求重用。
● CSS(Client-Stateless-Server)可译为客户无状态服务器。
● LCS(Layered-Client-Server)可译为分层客户服务器。
● VM(Virtual Machine)可译为虚拟机风格。
通过推导,Roy Fielding得出了REST架构风格中最重要的6个架构约束,即客户—服务器(Client-Server)、无状态(Stateless)、缓存(Cache)、统一接口(Uniform Interface)、分层系统(Layered System)和按需代码(Code-on-Demand)。其中:
● 客户-服务器是指通信只能由客户端单方面发起,表现为请求-响应的形式。
● 无状态是指通信的会话状态(Session State)应该全部由客户端负责维护。
● 缓存是指响应内容可以在通信链的某处被缓存,以改善网络效率。
● 统一接口是指通信链的组件之间通过统一的接口相互通信,以提高交互的可见性。
● 分层系统是指通过限制组件的行为,将架构分解为若干等级的层。
● 按需代码是指支持通过下载并执行一些代码,对客户端的功能进行扩展。
HTTP/1.1作为一种REST架构风格的架构实例,其架构演变经历了图1-3和图1-4所示的过程。
图1-3
图1-4
用户代理处在三个并行交互(a、b和c)的中间,用户代理的客户端连接器缓存无法满足请求,因此它根据每个资源标识符的属性和客户端连接器的配置,将每个请求路由到资源的来源。
请求a被发送到一个本地代理,代理随后访问一个通过DNS查找发现的缓存网关,该网关将这个请求转发到一个能够满足该请求的来源服务器,来源服务器的内部资源由一个封装过的对象请求代理(Object Request Broker)架构来定义。
请求b直接发送到一个来源服务器,它能够通过自己的缓存满足这个请求。
请求c被发送到一个代理,它能够直接访问WAIS(一种与Web架构分离的信息服务),并将WAIS的响应翻译为一种通用的连接器接口能够识别的格式。
在图1-4中,每个组件只知道与它们自己的客户端或服务器连接器的交互。
4.REST定义——讲定义
REST(REpresentational State Transfer,表述性状态转移)是所有Web应用都应该遵守的架构设计指导原则。
当然,REST并不是法律法规。如果在软件开发实践中违反了REST的指导原则,虽然能够实现应用的功能,但是会付出很多代价,特别是对于大流量的网站。
5.REST关键原则——讲原则
REST有5个关键原则,分别是Resource、Hypertext Driven、Uniform Interface、Representation和State Transfer。
● Resource(资源)表示为所有事物定义ID。
● Hypertext Driven(超文本驱动)表示将所有事物链接在一起。
● Uniform Interface(统一接口)表示使用标准方法。
● Representation(资源的表述)表示资源多重表述的方式。
● State Transfer(状态转移)表示无状态的通信。
注:在翻译外文文献时,可参考严复在《天演论》中的“译例言”讲到的“译事三难:信、达、雅”。这三个原则的核心在于意译。
资源(Resource)
资源其实可以看作一种看待服务器的方式。
与面向对象设计类似,资源是以名词为核心来组织的。
一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互访问并获取。
将服务器看作由很多离散的资源组成,每个资源是服务器上一个可命名的抽象概念。资源可以是服务器文件系统中的一个文件,也可以是数据库中的一张表。
上文提到资源意味着为所有事物定义ID,也就是说,每个事物都是可被标志的,都会拥有一个ID标识符。在Web开发中,代表ID的统一概念就是URI。URI构成了一个全局命名空间,使用URI标识你的关键资源意味着它们获得了一个唯一、全局的ID。
这里要注意区分URI、URL和URN。
● URI,即Uniform Resource Identifier:统一资源标识符,包括URL和URN。
● URL,即Uniform Resource Locator:统一资源定位符,常见的有Web URL和FTP URL。
● URN,即Uniform Resource Name:统一资源名称,例如tel:+1-888-888-8888。
设计URI的4个原则是:
● 它们是名词。
● 区分单复数。
● URI有长度限制,建议小于1KB。
●在URI中不要放未经加密的敏感信息。
在URI中,有几个符号需要特别注意:
①/表示层次关系,例如https://www.×××/cn/products/elasticsearch。
②;,来表示并列关系,例如https://www.×××.com/axis;x=0,y=9 sip:user@domain.com;foo=bar;x=y。
③-来提高可读性,最好全用小写,例如https://www.×××-fan.com/。
④ 用参数或者HTTP Range Header来限定范围,例如
https://www.×××.com/sortbyAsc=name&fileds=email,title&limit=10&start=20.
超文本驱动
超文本驱动意味着将所有事物链接在一起。超媒体被当作应用状态引擎(Hypermedia As The Engine of Application State,HATEOAS),其核心是超媒体概念,换句话说是链接的思想。
引入链接后,我们可以将Web应用看作一个由很多状态组成的有限状态机。资源之间通过超链接相互关联,超链接既代表资源之间的关系,也代表可执行的状态迁移。
使用URI表示链接时,链接可以指向由不同应用、不同服务器甚至位于不同地域、不同洲际的不同公司提供的资源——因为URI命名规范是全球标准,所以构成Web的所有资源都可以互联互通。
超媒体原则还意味着应用“状态”,服务器端为客户端提供一组链接,使客户端能够通过链接将应用从一个状态改变为另一个状态。而链接恰恰是构成动态应用的非常有效的方式。
因此链接成就了现在的Web。
统一接口
统一接口意味着使用标准方法。
按REST要求,必须通过统一接口对资源执行各种操作。对于每个资源只能执行一组有限的操作。
在RESTful HTTP方式中,一般开发人员通过组成HTTP应用协议的通用接口访问服务程序。在HTTP/1.1中,已经定义了一个操作资源的统一接口,主要包括以下内容。
● 7个HTTP方法:POST、GET、PUT、DELETE、PATCH、HEAD和OPTIONS。
● HTTP头信息(可自定义)。
● HTTP响应状态代码(可自定义)。
● 一套标准的内容协商机制。
● 一套标准的缓存机制。
● 一套标准的客户端身份认证机制。
对开发人员而言,程序代码将从图1-5中转变。
图1-5
资源的表述
资源的表述是一段对资源在某个特定时刻的状态的描述。资源可以在客户端—服务器端之间转移传递。
资源的表述有多种格式,如HTML、XML、JSON、文本、图片、视频、音频等。资源的表述格式可以通过协商机制来确定。请求—响应的表述通常使用不同的格式。
状态转移
状态转移意味着无状态通信。这里的状态转移是指在客户端和服务器端之间转移。通过转移和操作资源的表述,间接实现操作资源的目的。
无状态意味着服务器的变化对客户端是不可见的。这主要是为了保证架构设计的可伸缩性和可扩展性。试想一下,如果服务器需要存储每个客户端状态,那么大量的客户端交互会严重影响服务器的内存可用空间。
总结REST风格的架构特点
判断REST架构设计是否优秀的标准有6个:分别是面向资源、可寻址、连通性、无状态、统一接口和超文本驱动。
REST架构风格的优点&缺点——讲辩证
REST架构设计的优点是简单、可伸缩、松耦合。需要指出的是,REST架构设计不是“银弹”。在实时性要求很高的应用中,REST的表现不如RPC。因此,在做架构设计和技术选型时,需要根据具体的运行环境对具体问题进行具体分析。