今天小数给大家带来的干货来自国外一个小组会议上的分享。目前,大部分微服务架构都会使用REST协议以实现不同服务之间的通信,但是它却有天然的缺陷——怎样的缺陷?如何解决?请看下文。
最近,Lightbend技术负责人James Roper在纽约Java特别兴趣小组会议上分享了一个观点:
现在许多人正着手将传统的整体式应用拆分成微服务集合,但如果这些微服务组件都通过REST(即表述性状态转移)实现彼此通信,那么它依然只是一款整体式的应用程序。
Roper表示自己是异步通信的铁杆支持者——Lightbend(前身为Typesafe)推出的一套名为Lagom的Scala微服务平台正好是基于异步通信所打造。
这里提到的“异步通信”与我们常说的“异步I/O”并不是一回事。异步I/O的实质在于避免因等待进程线程完成而导致的操作停止。而作为微服务中的重要组成部分,异步通信则旨在设计出一套系统,其中某项服务的执行无需等待另一项任务的完成。
“使用异步通信,如果用户向某项服务提出一条请求,而该服务又需要向另一服务发出请求,那么前一服务的通信无需受阻即可向用户直接返回响应,”Roper解释称。
目前,大部分微服务架构都会使用REST协议以实现不同服务之间的通信(取代对象调用)。尽管REST较其它常规方式(例如基于XML的SOAP)更为简单,但其同步特性仍然成为固有缺陷——换言之,它天然拥有同步属性,而非异步。
“当客户端发出一条请求,服务器则发出一条响应,”Roper这样形容REST的工作原理。
一项服务发生故障,即会导致操作整体瘫痪。
面向用户的服务通常包含大量以同步方式通信的微服务,这意味着各微服务彼此依赖。这种处理方式在各服务皆能正常运转时并不会带来什么麻烦,然而一旦某项服务发生故障,即会引发不可阻挡的故障链并导致最终用户面临拒绝服务状况。
同样的,如果某项微服务速度缓慢,则响应时间也会被同时拖累。
使用REST等同步通信机制,Roper指出,“从技术角度讲,我们仍然相当于构建了一款整体式方案。无论各组件是否被拆分为独立服务,系统本身还是会像整体应用那样高度关联。”
而在异步通信中,各服务间仍然彼此依赖,但不再因相互等待结果而导致响应速度缓慢。因此,如果一项服务发生故障,其不会影响到其它服务,瓶颈与单点故障问题也将不复存在。
利用基于Java的一套类Twitter服务演示,Roper解释了如何通过多种方式实现代码中的异步调用。方法之一在于确保每项微服务都在信息更新时对其进行发布,而非等待其它微服务针对该信息提出请求。通过这种办法,假设通讯服务需要一份用户的“好友”列表,则可使用由“好友”相关微服务提供的最新信息,而非直接指向该服务发出请求。
Roper坦言,异步通信带来的最大挑战在于如何确保最终用户始终能够获得最新信息。很多社交网络都会使用最终一致性机制,并不保证每位用户都能够获得最新版本信息。
另外,REST调用由于极易实现而使用户产生了稳定的使用习惯。一位与会者提到,需要经过大量编码工作才能实现异步通信。
Roper指出,像Apache Kafka这样的软件能够自动处理异步服务中的低级细节,“如果使用简单的REST调用,大家的服务有可能瘫痪。而通过这种方式,情况就不会那么糟糕。”