在现代软件开发中,微服务架构因其带来的诸多好处而受到青睐。独立部署的模块、更集中的测试工作、为每个部分选择正确的技术、以及基于集群部署的弹性增加,都是微服务架构的优势。然而,对于许多人来说,包括在内,最难的部分是如何构建微服务,以及每个部分应该有多小,它们如何协同工作。以下是发现的一些有用的实践,如果开始在解决方案中利用微服务架构。
首先,面临的问题是容器应该有多小。有没有太小的问题?一个好的经验法则是专注于分离关注点。如果将每个用例分解为单一目的,很快就会得到一个好的微服务设计。
以最近与同事合作的一个解决方案为例,它最终从一个API拉取数据,然后将这些信息提取到数据模型中。在单体架构的思维方式中,这将是一个API调用。传入数据,然后循环处理。但问题是吞吐量,如果拉取67个不同区域,每个区域300多条记录,并将其作为一批处理,那将是一个巨大的API调用的混乱。
因此,有一个函数循环遍历区域,并将它们全部拉取到blob存储中的json文件中,然后排队一个消息。然后有另一个函数,当一个消息被排队时,将取这个消息,读取该区域的记录,并处理保存到数据库中。这个独立的函数是另一个微服务。
这种方法有几个好处,但最主要的是,第二个函数可以独立于第一个函数进行扩展,可以响应排队的消息,使用异步处理。
领域驱动设计(Domain-Driven Design,简称DDD)是一种软件设计方法,它强调以业务领域为中心进行软件开发。这意味着微服务应该反映它们试图做的事情。以电子商务为例,如果需要跟踪订单,并在订单提交后有一个处理流程,包括:
根据上述步骤,一种实现方式可能是:
如果注意到上述情况,除了编排之外,它们与业务步骤完全匹配。这提供了一种简化的方法,使得变更更容易,对新团队成员来说也更容易理解。服务之间的通信很可能是通过队列进行的。
这是最重要的一点,如果想看到微服务的好处,它们必须是独立部署的。这意味着,如果看上面的例子,可以部署这些独立的服务,并在不进行全面应用程序部署的情况下对其中一个进行更改。
以上述场景为例,如果想添加一种新的支付方式,应该能够更新OrderPaymentService,提交这些更改,然后将其部署到开发环境,通过生产环境,而不需要部署整个应用程序。
第一次听到这个想法时,觉得这是最荒谬的事情,但有一些方法可以使这成为可能。
如果采用这种方法构建微服务,很快就会注意到的一件事是每个微服务都变成了它自己的黑盒子。因此,发现构建这些组件时考虑到弹性是很好的。像利用Polly进行重试,或断路器模式这样的事情。这些是确保服务保持弹性的好方法,并且会对应用程序产生累积效应。
以OrderPaymentService为例,知道队列消息应该包含订单和支付细节。可以对这个服务进行微观分析,并说,它可能在哪里失败,不难得到这样的列表:
对于上述一些情况,只是一些简单的错误处理,比如检查消息的格式。还可以构建逻辑来检查支付服务是否可用,并进行指数级重试,直到它可用。
还可以考虑实现一个断路器,如果在多次尝试后无法处理支付,服务切换到不健康状态,并引发通知工作流。
在最后一种情况下,可以实现一个状态存储,指示支付处理的状态,以防服务失败并需要被另一个接管。
这是每个人都容易忘记的一点,但它很好地与前一点相吻合。重要的是要有一个机制来跟踪和监控微服务的状态。发现人们很容易说“哦,服务正在运行,所以它很好。”这就像说,只是因为首页加载了,一个完整的Web应用程序就在工作。
应该在微服务中构建跟踪它们健康的能力,并为操作工具提供一种这样做的方法。让面对现实,最终,所有的代码都会被部署,所有部署的代码都必须被监控。
例如,看看上面的例子。如果在OrderPaymentService中构建了一个断路器模式,并且每次失败都会更新存储在服务内存中的状态,说它是不健康的。然后可以公开一个HTTP端点,返回该断路器的状态。
然后可以构建逻辑,当它达到半开,甚至打开特定的事件会发生。
这似乎有点讽刺,因为上述情况。但如果正在处理一个现有的应用程序,永远无法说服管理层允许放弃它并重新开始。所以过去所做的是,当发现应用程序的某个部分需要更改时,抓住机会重新架构并使其更具弹性。解构这些部分,并实现一个微服务响应来解决问题。