1.2 使用应用程序库解决问题

第一批知道如何在云环境中运行应用程序和服务的组织是大型互联网公司,其中许多公司是我们今天所知道的云基础设施的先驱。这些公司投入了大量的时间和资源,为每个人都必须使用的语言构建库和框架,这有助于应对在云原生架构中运行服务的挑战。谷歌构建了像Stubby这样的框架,Twitter构建了Finagle,2012年Netflix将其微服务库开放给开源社区。例如,在NetflixOSS中,针对Java开发人员的库处理云原生问题:

Hystrix——熔断和bulkheading。

Ribbon——客户端负载均衡。

Eureka——服务的注册和发现。

Zuul——动态边缘代理。

因为这些库是针对Java运行时的,所以它们只能在Java项目中使用。要使用它们,我们必须创建对它们的应用程序依赖,将它们拉到类路径中,然后在应用程序代码中使用。下面的例子使用NetflixOSS Hystrix将一个Hystrix依赖拉到你的依赖控制系统中:

为了使用Hystrix,我们用一个基本的Hystrix类HystrixCommand来包装命令。

如果每个应用程序都负责在其代码中构建弹性,我们就可以分散处理这些关注点,消除中心瓶颈。在不可靠的云基础设施上进行大规模部署时,弹性是一个理想的系统特性。

应用程序库的缺点

当我们将应用程序弹性的实现去中心化并分发到应用程序本身时,虽然减少了对大规模服务架构的关注,但也引入了一些新的挑战。第一个挑战是关于应用程序的预期假设。新引入架构中的服务将受到其他人或其他团队所做决策的限制。例如,要使用NetflixOSS Hystrix,必须使用Java或基于JVM的技术。在通常情况下,熔断和负载均衡是结合在一起的,所以你需要同时使用这两个弹性库。要使用Netflix Ribbon进行负载均衡,你需要某种注册表来发现服务实例,这可能意味着需要使用Eureka。沿着使用应用程序库这条路径,在与系统其余部分进行交互时,将围绕一个未定义的协议引入隐式约束。

第二个挑战是引入一种新的语言或框架来实现一个服务。你可能会发现,NodeJS更适合实现面向用户的API,但你的架构其余部分使用的是Java和NetflixOSS。你可以选择寻找一组不同的库来实现服务弹性,例如,你可以尝试寻找类似的软件包,如resilient或hystrixjs。你还需要为自己想引入的每一种语言(微服务支持多语言开发环境,尽管只使用一种语言通常是最好的)搜索相关软件包,证实它的可用性,并把它引入你的技术栈中。每个库都有不同的实现,并做出不同的假设。在某些情况下,你可能无法为每个框架/语言组合都找到类似的替代品。最终一些语言的部分实现和实现的整体会不一致,这在请求失败的场景中将很难推演问题路径和定位错误根因。图1.3显示了不同服务如何实现相同的库来管理应用程序网络。

图1.3 应用网络库与应用程序的结合

最后,在一堆编程语言和框架中维护几个库需要遵循很多原则,而且很难做到准确。关键是要确保所有的实现都是一致的和正确的。只要有一次偏离,就会给系统带来更多的不可预测性。在一系列服务中同时更新库也是一项艰巨的任务。

尽管应用程序网络的去中心化更适合云架构,但是这种方法给系统带来的运维负担和限制,对于大多数组织来说都是难以承受的。即使他们接受了这个挑战,要把它做好也会很难。如果有一种方法既能获得去中心化的好处,又不用为使用嵌入式库来维护和运维这些应用程序而付出巨大的开销,那会怎么样呢?