开源服务器端软件的接口风格和分歧

发表于2016-06-06
评论0 3.9k浏览

前言

  开源运动风起云涌,现在已经成为IT技术最重要的表现形式。从早期的GNU运动,到Apache基金会项目,到GitHub,开源项目已经几乎覆盖了全部的较通用的软件领域,以及非常多的专用业务领域。一般来说,每个软件的设计都是独特的,其使用接口也是非常多样化的,所以对于开源软件的使用者来说,通常都会碰到所谓“易用性”问题——他们需要花大量的时间去阅读开源软件的使用文档、实例代码,最典型的就是诸如《Linux环境编程》这种书,很少有低于300页的篇幅。不过,在过去的十几年,开源项目在易用性的问题上,渐渐走出了一条新路:越来越多的开源软件,在用户使用界面上,采用了趋同的接口标准。尽管这些渐渐相似的接口标准,在性能上、功能完备性上可能并不是最优的选择,但是这种标准和接口的趋同,大大降低了用户对开源软件学习的难度。本文希望通过七个最常见的服务器端的这种趋同技术取向来阐述,希望能对新的开源项目的技术选择提供一些参考。


    

   


TCP/IP协议

  TCP/IP协议作为互联网的基础通信协议,其“影响力”无与伦比。但是现在我所说的并不是其在一般通讯上的能力,而是关注其作为服务器端进程间通信的手段。一般来说,进程间通信我们往往有比TCP/IP更好的手段,比如在windows上我们有windows消息机制;我们还有共享内存、Linux的信号机制、管道机制、甚至我们还可以用IPX协议。

  从性能和编程便利性上来说,使用windows消息机制、共享内存,往往都会比TCP/IP的使用更好。而管道和信号机制,对于特定模式下的通信,也会比TCP/IP更简单。然而,这些都没什么用,因为TCP/IP是在所有操作系统、所有语言、平台都支持的,这让越来越多的开源项目,把TCP/IP作为一个“标准”的进程间通信方式。

开源项目举例来看:
  MySQL使用一个tcp的地址和端口来提供SQL服务,这和传统的ODBC配置,使用一个“数据库名字”更容易被诊断。
  Tomcat提供了两个TCP地址,一个用于接受来自Apache的请求转发,一个用于直接HTTP访问。这比CGI规范的stdin/stdout更简单明白。
  ActiveMQ提供一个TCP地址,用于接受消息终端进程的读写请求。
  ZooKeeper提供TCP地址作为接入端。
  这个列表还可以很长,除了使用TCP端口外,部分软件还会使用UDP端口,但是由于进程间通讯往往需要保证数据到达和顺序,所以用UDP的较少一些。

             


URL描述符
  在我们开发一个函数、一个服务的时候,我们往往会需要提供一种描述资源的方式给用户,比如在磁盘上的一个文件,网络上的一个服务,集群中的一个进程,甚至直接就是一个集群。在早期的开源项目中,如何“描述”一个资源可谓五花八门,最典型的描述方法就是类似文件目录路径的斜杠法区分;也有很多使用一个简单的数字ID来描述的,比如Linux中无所不在的各种描述符。IP地址也是一种常见的描述符,用4段0-255组成的一个32位数字。
  在互联网用户普及的过程中,URL实际上是作为最初的概念,得以深入人心的。在浏览器地址栏输入的http://xxxx一度被认为是互联网最典型的特征。实际上,URL是一个资源定位的符号约定,他包括了对于互联网上任何一个资源特征的描述规范,而不仅仅是代表一个域名或者一个网页。它的比较完整的定义是:协议://用户名:密码@网络地址(可以是域名或者IP或者任何其他字符串):端口/地址路径信息?查询key=查询值&查询key=查询值。我们最常见的如http://www.qq.com/,实际上代表:以http协议访问的,可以匿名使用的,在地址是www.qq.com上,以默认端口(这个数字由协议决定,HTTP协议默认是80端口)获得的,在根目录上的资源。
  URL逐渐成为开源软件最喜爱的资源标志,是有原因的,其中最重要的原因之一,就是在现在大部分编程语言中,都带有非常完善的处理URL的库,比如java.net.URL类型。这些库可以非常简单的从一个字符串URL中解析出协议、地址、端口、路径、查询KEY和对应的VALUE。如果不是使用URL,那么你可能需要构建一个非常复杂的结构体,来存放如此繁杂的信息。URL受到欢迎的另外一个原因,是因为他本身是一个字符串。而字符串,对于编程来说是最友好的数据结构之一:几乎所有的语言都有字符串类型,你可以简单的在源代码中输入字符串,你可以简单的打印出URL。更重要的是,字符串这种类型,还可以简单的扩展数据,对比于一些结构体,我们需要关注其成员结构、内容长度,而字符串就没有这个问题;当然你也可以使用诸如JSON、XML这类编码的字符串数据,但是对于“标识”一个资源来说,那些也太复杂了点。
  也许URL不是一种最高效的标识方法,它远比类似IP地址类型的数字要占用内存,处理过程也没有子网掩码这么快速,但是它对程序员的友好程度绝对是一流的。我们可以看到很多软件都在使用URL:
  1、用JDBC连接MySQL的时候,我们使用的是:
mysql://127.0.0.1:3306/dbname?user=xxx&password=xxx
  2、 我们在windows窗口地址栏可以输入http://... ftp://...File://... mailto://...
  3、 Hadoop里面你可以使用hdfs://host/…来读取一个文件
  4、 Rsync://xxxx 可以用来同步服务器

       

HTTP协议
  互联网上使用的最广泛协议,一定是HTTP协议。这个协议不是一种特别“高效”的协议:它是基于文本字符串的,它的header居然是按换行符分隔的,它往往是短连接的同时它还居然是使用TCP的……当我们在设计一个客户端-服务器通信的协议时,我们往往会采用长连接的,用来节省反复建立连接的开销;我们喜欢用TLV形式的编码格式(Type:Length:Value),觉得在TCP流中这样处理是最快的;我们喜欢用位来代替字节,用数字代替字符串,这样能节省流量……但是,HTTP协议有几个最典型的优点,是其他我们没有关注的,那就是:可扩展性、请求应答性。
  如果我们的协议内容是文本的,以换行符分隔的,那么,我们就无需维护一个有限数量的header,这样任何的使用者,都可以去扩展任意的header,比如HTTP里面就因为增加了著名的Cookie的header,从而让WEB服务变得可以携带会话信息。就连对于HTTP正文的“数据类型”的header,也是一种叫MIME的分类字符串来标识,比如text/html、image/jpeg,任何人都可以创造新的“类型”。HTTP协议另外一个特征,是保持了非常简单的“请求应答”模型,这个模型可以很简单的在一个阻塞的线程里表现,所以对于使用者来说,太容易学习了,你甚至可以用telnet指令来直接模拟一个HTTP的过程。如果按一般我们设计的高效通信模型,我们往往会在一个连接里面承载多次交互,你可以连续发一堆请求,然后收一堆回应,但是HTTP不是这样,因为如果这样设计,整个处理过程会变得复杂:你必须要记录起所有发出的请求,你还要在请求里面放入一个序列号,再从回应中读取对应的序列号,来对应请求……在HTTP里面,没有序列号,无需记录请求,他每个连接,每个时刻,只有一个会话,就是一个请求对应一个回应。这样的简单设计,让我们在使用它的时候,可以用很简单的编程方法来使用,从而扩大了各种各样的使用者。当使用者扩大之后,各种语言,各种平台,都提供了对HTTP协议进行操作的工具库,就算你找不到这样的工具库,你也可以很简单的利用TCP的socket功能来写一个HTTP协议操作库。
  我们似乎一下难以举出很多例子使用HTTP协议,原因是,我们接触到的开源软件,其真正的大数据量通信的通道,都不是用HTTP协议的,因为这里确实有性能上的需求。但是,当我们看到各种使用开源软件组合而成的系统,都是使用HTTP接口的,比如Facebook的开放平台的各种接口。这些越来越多的接口,虽然形式上有RESTful的,有WebService的……所有的这些接口,都是基于HTTP协议的。

       

JSON编码
  我们经历过各种各样的编码格式,从最早的计算机课程中,我们就要学习如何用数字来表达文字(使用ASCII表)。在后来,我们使用过CSV格式,就是那种每行文字表示一个序列,每个逗号分开两个字段。再后来,我们发现我们可以用memcpy来把一个结构体拷贝来拷贝去,这也是一种编码,只不过和编译器、操作系统有关。在某个时候,我们发现XML的宣传铺天盖地,似乎这个世界的编码格式终于要统一了。但是在实际的使用过程中,我们发现XML其实是一个超级复杂的概念,就算不管那个复杂的“合法性检查”规范,我们也要掌握DOM和SAX两种奇怪的处理手段。而且,这个号称“对人类友好”的格式,真正用键盘去敲的时候,需要输入那么多字符,才能表达一个很简单的数据。所以有一部分人,觉得XML是一个骗局,他们完全放弃了对“兼容人类读写和机器处理”的理想,采用TLV或者其他一些完全只针对计算机处理的编码格式。他们会写很多处理的工具,以及工具的工具,最著名的是Google Protocol Buffer这个开源工具。另外一部分人,继续探索一种让人类和机器平衡的格式,我们现在有CSV格式,Markdown格式等等,其中最成功的,就是JSON格式。
  有一次,我们发现这个流行很广的格式,不是一个“高效”的技术规格。JSON也是全字符串的,他也是基于标识划分字段的,这比起按长度来划分字段的编码格式来说,处理起来是非常浪费内存和CPU的。不过,人类在使用JSON编写和阅读时比较轻松,它还能简单的以树状格式来展示。在AJAX(JavaScript)流行的时代,JSON作为标配的格式,早已突破了JavaScript的使用领域。说实在的,我很难去列举更多JSON的优点,因为它实在是太简单了,几乎简单到,你如果想用文本来表达一种树状结构,最后都会得出类似JSON的东西,差别只是各种标识符不同而已。
  Redis可以存储JSON的结构,Chef用JSON来存放部署数据,Apache CouchDB甚至直接就是用JSON作为数据库存储格式。

     

脚本
  相信大家都接触过SQL,这是一种很特别的语言,他似乎不是一种完整的语言,但是他又能做很多事情。我们也使用过XML,这个格式可以用来描述很多东西,曾几何时,大部分的开源软件的配置文件,都是XML格式的,比如Tomcat,Spring,Hibernate,Log4J…我们也有试用过简单的INI格式作为配置,用过Apache那种看起来有点奇怪的格式配置文件,甚至让人莫名其妙的bind配置、network配置……上面所说的这些东西,有一部分是所谓的配置文件,但是从本质来说,这些都是一种用户使用接口。最开始的时候,我们希望能让用户非常简单的去使用已有的软件,因此我们设计了各种各样的配置文件。当这些配置文件越来越复杂,学习如何配置他们的难度,甚至已经和编程不相上下了,比如Spring的XML配置文件。
  另外一个方面,软件业界在降低编程难度的努力上,结出了非常多的成果,其中非常突出的一个,就是脚本语言。和最早的perl语言不同,现在的脚本语言,已经非常成熟了,比如python/ruby/lua,这些脚本语言除了具备高效的解析器以外,一般都还具备即时编译的能力(JIT),这让脚本语言好学不好用的名声渐渐褪去。因此,有很多人就想,我们为什么要发明一个奇怪的配置文件格式,而不直接使用某个流行的脚本语言呢?因此在现在最流行的Web服务器Ngix,就采用了lua脚本作为配置文件。我们再也不用去记忆奇怪的Apache配置文件的写法,我们只需要使用lua语言就好了。使用脚本语言的功能扩展性,远比配置文件要强,用户可以利用编程的能力,更好的使用这个程序。在这个方面,SQL实际上是一个非常优秀的前辈,由于有SQL这种接口,数据库软件的使用变得非常的易学,也能很强大,对比更久之前的FoxPro这种数据库,它提供的语法和功能,远远没有SQL那么丰富。
  除了能力的强大外,脚本语言还是一种通用知识,使用者的学习精力不用被浪费在某个特别的软件上。对于使用者来说,也是一种特别的吸引力,毕竟,我花时间学习了lua语言,并不仅仅可以用在配置ngix上,我还可以用来写wow的UI界面插件。
  更进一步,我们的开源库、框架,以前往往会假定,使用者和源代码是同一种语言,比如著名的Cocos2d-X游戏引擎。但是,更多的开源库,更喜欢提供脚本形式的接口,比如Unity游戏引擎,就提供了C#和JS两种脚本语言(C#可能算不上脚本语言),这样能让用户在易用性上得到更好的服务。这显然会让这些开源库和框架的复杂度,但是也让这些软件的用户市场得到极大的扩展。现在Cocos2d-Lua已经越来越多人用,就是脚本威力的证明。毕竟我们所有人,都希望能更快的完成工作。



RESTful接口
  前文已经说到过HTTP协议,事实上,很多年前,很多人已经在使用HTTP协议作为软件模块、进程间的交互方式。但是,我们发现HTTP仅仅是一个应用层的传输协议,你可以用来做任何事情。因此最先被人想到的,就是用来模拟函数调用,这也是所谓RPC(远程过程调用),于是WebService诞生了,有些公司还进一步,对于内容编码格式也提供了,比如SOAP编码协议。但是这些技术,虽然知名度很高,但真正的使用者却更少。到后来,有一些更加复杂的所谓“企业级”技术诞生,比如EJB,这种技术提供了强大的“非功能性”能力,比如高可用性、高伸缩性、自动扩容容灾,balabala…但是这种技术能提供的“功能”却非常少,对比要把这套东西配置构建起来的复杂努力,对比实在太大了。
  因此终于有聪明人发现了RESTful,并且流行起来。使用RESTful,终于能让我们摆脱“不够高大上”的心理压力——因为业界都很流行嘛,但是实际上,大家还是看重它的易用性。我们甚至无需任何特别的库和工具,就用现有的HTTP协议工具,就能使用和构建RESTful服务。并且这个技术还有很好的一点,就是我们再也不用提供各种语言各种平台的SDK接口库了,我们看到各种开放平台和数据系统,都抛弃了旧的SDK接口库模型,而采用了RESTful接口。——如果我们SDK要升级,还会让用户的代码崩溃的话,我们不如直接用这种基于文本和自描述的技术来提供接口。
  总体来说,RESTful有它技术上的独特之处,但是让它流行起来的原因,其实还是一个简单的原因——易用性。

Web管理界面
  在早期的开源项目中,我们如果要控制一个软件,或者监视这个软件的运行情况,往往都只有非常简陋的手段:配置文件和日志文件。比如Apache这款软件,他的配置文件和日志文件都是非常复杂的,基于acesss_log的这个文件,甚至出现了大量的其他开源软件,用来专门“展示”这个内容超级丰富的日志文件。而另外一些软件,提供了一个命令行界面,我们可以用一些文本命令,去控制这款软件。最著名的例子就是redis,其实MySQL来说也是这种,只不过这个命令是SQL。
  不可否认,不管是日志文件,还是命令行,都是非常强大能力。他们的表达能力非常强,能够对非常复杂的功能提供支持。但是他们也有一个最严重的问题,就是“提示力”不足:对于用户来说,他是不知道这个软件有什么信息的,更加没法快速的学会怎么使用。提供给他们的,只有各种手册、文档。但是,有一些软件,提供了一个Web的管理界面,就能让这些复杂的手册、文档统统变得没必要了,因为用户可以直接在这个图形界面上探索。这方面最突出的成功例子,就是discuz。以前我们要安装一个网上论坛,我们需要操作命令行、脚本、SQL……,但是这个软件,从安装、维护、使用,都可以通过WEB的图形界面来使用,猛然的打开了网络论坛的市场。
  除了discuz论坛,像tomcat/chef……都是有WEB图形界面的。除了开源软件,我们发现现在的路由器、电视机、投影机甚至都有WEB的操作界面。因为对于用户来说,不管是电脑还是手机,都一定会带有一个浏览器,这样对于软件的操作接口,只需要输入一个URL,就可以发现一个五彩斑斓的界面世界。

            

总结
  上面说的这些,看起来并不是非常高大上的技术,但是这些能流行,最核心的一点,就是易用性。对于开源软件来说,流行是一个最重要的因数,所以易用性是一个非常关键的特性。特别是现在开源软件之间的竞争非常激烈的情况下,易用性已经让用户非常挑剔之后,我们更是要把这些易用性作为一个产品的底线,因为如果不到达这个底线,就会被用户轻易的丢弃。
  感谢大家的阅读,如觉得此文对你有那么一丁点的作用,麻烦动动手指转发或分享至朋友圈。如有不同意见,欢迎后台留言探讨。


如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引