微服务架构、资源
柏舟 新冠4年 01-28
在SOA架构中,我们将系统划分为一个个服务。一个服务可能依赖很多资源对象,输出很多资源对象。我们通过描述系统中每个服务依赖的外部资源对象(uri)、内部函数资源对象和输出的资源对象,就可以得到系统的链路关系图。在此基础上,就可以通过网关统一管理资源的流量、日志、追踪和向外暴露服务。
例子
以一个常见的博客服务举例,它依赖外部资源:
- postgres:xxx@xxx
- http://127.0.0.1:8080/oauth2/xxx
依赖内部资源:各种队列、调度器等。
提供资源:
只要有每个服务完整的依赖对象和对外的资源对象,就可以很容易的得到多个微服务的依赖关系,从而得到容器创建顺序。而且能够计算是否存在环状结构,导致系统发散。
问题
资源和函数是不同的。无状态的函数是可以无限扩展的,但是有状态的资源天生就存在各种竞争问题:锁、事务、顺序。比如为了解决死锁问题,就需要细化资源的使用时机和策略等等。
现有的语言和框架在函数和资源上没有区分。对于编程语言来说,资源和值是很难区分的,全局可变的变量可以明确算资源,但是局部共享的变量呢?外部的资源对象呢?我们也没有什么工具可以在编完程序后一键导出资源对象清单。其次,像kubernetes确实可以描述service提供的API,但是kubernetes的depend只能用于镜像的顺序,不能细化到资源的描述。
现有的编程语言的import机制只能描述函数依赖关系,不能表述内部和外部资源的依赖关系,对外提供的资源。
网关
上文介绍了资源的描述问题,但是在如何使用外部资源有不同的方案。
第一种,是容器直接通信,这需要使用服务发现获取资源对象的ip地址,同时兼容资源对象的网络协议和内容格式,此时,所有外部服务是透明的。
第二种,是使用网关代理,对于容器来说,外部只有一个网关,网关与其它容器的通信都不可见。好处是资源对象真的变成了统一资源标识符,甚至可以写死在代码里面,而且做链路追踪这些很方便,屏蔽通信协议的影响,但是额外的请求会增加开销降低可靠性。
第三种,是使用sidebar,将通信完全托管给envoy实现。
不同的方案对应不同的拓扑结构,如果有链路追踪这些需求,还是得使用第二种或第三种方案。但是,系统的最终目标是解决实际需求,并且需要在潜在的需求和开发效率取得平衡。如果在复杂性允许的范围内,还是尽量在单体内部解决问题,一旦引入分布式资源的锁、事务问题,得不偿失。