边缘服务的一致性、耦合和复杂性

技术公司采用微服务架构已经十多年了 , 结果好坏参半 。 微服务之间的依赖关系导致在修改一个服务时也需要修改其他服务 , 微服务的优势因此打了折扣 。 这就是所谓的紧密耦合 。 但组件之间的依赖关系是不可避免的 。
如果微服务不能满足用户的需求 , 那它还有什么用?本文重点讨论如何维护有用的微服务 , 并能够从微服务的迁移流程中得到好处 。 关键的是要在各个层保持清晰的关注点分离 , 并遵循最适合每一个层的设计原则 。
RESTfulAPI设计
2000年 , ApacheHTTP服务器联合创始人发表了一篇题为“网络软件架构的架构风格和设计”的博士论文 。 其中的第5章介绍了REST(RepresentationalStateTransfer) , 作为分布式超媒体系统的一种架构风格 。 这篇有关Richardson成熟度模型的博文是了解REST在API设计中所起作用的一个很好的资源 。
在API设计和HTTP标准之间存在着紧密的一致性 。 在RESTfulAPI设计中 , URI的路径部分用于标识特定实体(也称为资源) 。 HTTP谓词用于标识要对实体执行的操作类型 。 实体可以通过其他实体的URI路径部分链接到其他实体 。 对于HTTP状态代码含义的解释也存在一致性 。
提供在线应用程序的公司将API设计成平台 , 他们之所以这样做有很多原因 。 或许 , 他们希望从第三方那里获得额外的收入来源 , 或者向高级用户追加销售 。 或许 , 他们希望让不同的团队更容易调用彼此的API 。 或许 , 他们希望以这样一种方式来组织他们的API , 让它们可以很容易被相同产品族中的类似或相关的产品所重用 。 最后 , 他们希望设计出易于进行自动化测试的API 。
就像提供在线应用程序的公司开发便于用户理解的GUI应用程序一样 , 平台公司也应该开发便于开发人员理解的API 。 RESTfulAPI非常适合这一需求 。
在RESTfulAPI出现之前 , API是基于所谓的远程过程调用(RemoteProcedureCall , RPC)而设计的 。 这些API的设计不存在一致性 , 以致于难以看出它们是干什么用的 。 REST在API设计中引入了一致性 。 当你将REST与OpenAPI结合在一起时 , 开发人员很容易就知道如何使用你的API 。
边缘服务的一致性、耦合和复杂性
文章图片
一个基本的新闻源RESTfulAPISwagger规范 。
后端服务可以很容易地调用RESTfulAPI , 但对于前端应用程序来说就不那么容易了 。 这是因为好的用户体验不那么RESTful 。 用户不想要背后满是碎片化实体的GUI 。 他们希望一下子看到所有的东西 , 除非在设计上确实需要渐进显示 。 例如 , 我不想在规划旅行行程时打开多个页面 , 我希望在下订单之前能够在一个页面上看到所有的摘要信息(包括航班、汽车租赁和酒店预订) 。
当用户导航到一个Web页面或链接到单页应用程序(SPA)或移动应用程序的某个视图时 , 前端应用程序需要调用后端服务来获取渲染视图所需的数据 。 如果使用的是RESTfulAPI , 单个调用不太可能获得所有的数据 。 通常是先执行一个调用 , 然后前端代码遍历该调用的结果 , 并对每个结果项进行更多的API调用 , 以获得所需的所有数据 。 这不仅使前端开发复杂化 , 而且还增加了应用程序的页面加载时间 。 稍后再详细介绍 。
这里还有另一个问题 , 即RESTfulAPI与前端GUI关注点不是很契合 。 RESTfulAPI本身不支持推送通知 , 但支持回调(通过WebHook实现) 。 WebHook对推送通知的支持程度不如WebSocket 。 WebHook和WebSocket的不同之处在于 , Web浏览器不支持WebHook , 但支持WebSocket 。 这是因为WebSocket是由前端发起的 , 并与后端保持连接 , 后端会向前端发送更新 。 WebHook是由后端发起的 , 但浏览器没有一个固定的IP地址来接收这些请求 。 因为路径在RESTfulAPI中被用于标识一个特定的实体 , 所以请求和响应的格式不应该发生明显的变化 。 为了节省连接资源 , SPA可能会为所有类型的推送通知打开单个WebSocket , 允许每一条消息的格式之间存在巨大差异 。