以前的博客提到过我和某些人准备成立另外一个公司(因为不想和原来的那个公司其他合伙人混在一块)试水另一个项目,前一段时间太忙,现在闲下来总算可以开工了。最近这两个月同事们都在讨论“微服务”这个概念,不过由于我们在公司没有正式的项目使用这种设计,所以说得再天花乱坠也是纸上谈兵。正好哥要开始做自己这个私人项目,所以可以正好拿过来试水。
目前我所大体规划的进度安排如下:
- 6 月底前大体了解一下要使用到的技术,并且根据初期的需求大体确定系统的结构、数据库设计,以及各服务提供的接口。
- 7 月底前初步完成重要服务的初期接口以及单元测试,并确定 API Gateway 的方案和大体结构。
- 8 月开始设计前端页面,并最终确定各服务需要提供的接口。
- 9 月底前基本实现完前期需求的功能。这样 10 月开始就可以去目标客户那里试水了。
不过由于我们几个都是在业余时间进行打酱油式的开发,再加上我们要用很多以前没接触过的东西,所以上述时间并不能保证。不过我会在完成一定阶段后更新此类型的博文,以便对进度进行“监督”。
(一)微服务架构介绍
至于微服务架构的大体描述,可以参考一下 nginx 网站上的这个系列的文章:《Introduction to Microservices》。
总体来说,由于传统单体式应用(英文原文为“Monolithic”)存在着诸多问题(例如:可维护性差,几乎不可能重写;可靠性和差,因为如果服务中存在 bug 可能导致整个系统不可用;扩展性受限;所选用的硬件和技术由于只能部署在相同的机器上因此也不能充分满足各种业务的需求),现在越来越流行把一个大的服务拆分成独立部署的许多小服务(比较复杂的应用可能有几十甚至上百个小服务)。
例如上面推荐的那个系列文章中给出的简单的例子:
上图中每个六角形所示的都是独立的服务,处于单独的进程中(通常在不同的服务器上)。对于每一个服务,都有自己的数据库和相关 API 接口。传统的单体应用会将这些功能拆分成不同的模块,但本质上还是一起发布和部署。在不同模块的相互调用中,只需要调用相关业务逻辑的方法即可。而对于微服务架构,由于各个服务都运行在不同的进程中,因此通信方式也会更加复杂:例如上面例子中的通过 Rest API(而是用进程间通信的一大难处是要处理服务不可用、过慢等问题)。
初看起来微服务是一个很好的架构,但是必须看到微服务是一个相当复杂的架构。你必须要解决如何在多个服务间实现事务(因为很多服务可能会使用不支持事务的 NoSQL,而且通常大的事务要访问众多服务);此外需求的变更通常会导致更改很多服务,如果由不同团队维护,那么会有很多沟通成本;还有部署的问题,对于单体应用只需要重新编译一次然后把副本部署到多个负载均衡的服务器上即可,而微服务则需要根据自己的需求在不同服务器上部署。
因此微服务通常只适用于复杂的系统,对于一个需求简单的小系统而言并不适合。例如你可能只需要 1 个月就能快速实现一个单体服务,而要解决微服务所带来的问题可能需要花 3 个月或者更长时间。不过好在我们这个项目并没有明确的 release 时间(需求和进度完全由自己控制),而我们也想试试众多的“新技术”,所以对于我们来说更具有挑战性,也更有趣(传统的服务器我已经做得不想再做了!)。
(二)API Gateway
对于我们项目真正实现的第一步,除了要把需求讨论清楚外,一个很重要的任务是想好如何设计 API Gateway。
至于为什么要一个这样的 Gateway,原因是显而易见的。试想我们有 100 个不同的服务(部分服务可能有多个服务器的副本),如果没有一个统一的访问接口,那么客户端需要维护这 100 个服务的地址和 URL(因为服务器的地址可能会经常更换,而且客户端还需要一些负载均衡的处理),更要命的是,一个页面可能要访问诸多服务,此时客户端代码就会变得相当复杂。所以实现一个访问入口是很有必要的。对于这个 Gateway,通常提供如下功能:
- 授权认证。
- 安全性。例如 API Gateway 与后台服务通信可以采用明文传输,而对客户端统一采用 SSL。
- 负载均衡。
- 请求转发。
- 请求转换与合并。很多情况下一个请求需要访问多个服务,此时 API Gateway 可以向客户端提供一个粒度较粗的接口,而在 Gateway 将这些请求处理好后一并发送给客户端。又例如某些服务可能不采用 Rest 进行通信,此时 Gateway 可以转换成统一的接口形式。
因此我们目前的任务是通过学习其他项目的设计来思考自己项目的实现方式(当然不能照搬别人的,因为无论是业务规模还是复杂度都不太一样)。所以在我们初步完成 API Gateway 的设计之后会再更新一篇文章描述我们是如何做的。