单一应用架构
1.应用内容
一个服务器端的企业级应用,它必须支持多种不同的客户端,包括Web浏览器、手机浏览器、以及手机APP。这个应用也许还会暴露一个API,给第三方程序去调用。它也许还会与其他应用集成,通过web services或消息中间件。 这个应用通过运行业务逻辑、访问数据库、与别的系统交换消息、然后返回一个HTML/JSON/XML响应的方式来处理HTTP或者消息请求。也就是说把所有的功能都放在一个项目工程里,部署在一台服务器上。
2.解决方案
比如我们一个互联网金融网站,我们创建一个工程叫p2p,这个工程里面包含所有的功能:注册、登录、投资、充值、提现、合同、红包、消息等等。
这时需要构建一个单一应用架构的应用,比如一个单一的Java War文件,然后在Tomcat上运行的Java web应用。
3.方案结果
- 易于开发:现在很多开发工具和IDE的目标都是支持开发单一应用结构的应用;
- 易于部署:你只要在合适的运行时环境上简单的部署一个WAR文件(或者目录结构);
- 易于伸缩:你可以在一个load balance后面运行多个应用实例,以达到提高可用性和可伸缩性的目的。
⚠ 但是,一旦这个应用变得庞大,团队规模变大,这种解决方案的缺点变得越来越重大:
- 巨大的单一应用结构的代码吓坏了开发者,尤其是团队里的新人。这个应用变得难以理解和维护。结果是,开发工作变得缓慢,而且,因为没有严格的模块界限,模块化常常会被打破。此外,因为很难去理解如何正确地实现一次变动,代码质量下降。
- IDE负载严重:代码越多,IDE越慢,开发效率越低。
- web容器负载严重: 项目越大,启动时间越长。这对于开发效率有很大影响,因为有很多时间都浪费在了等待web容器启动上面。这也影响了部署。
- 持续部署很困难:一个庞大的单一应用架构的应用是频繁部署的障碍。为了更新一个组件,你需要重新部署一整个应用。这会中断后台的任务,比如java里的Quartz job,这可能会导致问题。还有一种可能是,未更新的组件会在启动时失败,导致的结果是,重新部署的风险升高,不利于频繁更新。 这对UI开发者来说尤其是个问题,因为他们经常需要快速迭代和频繁的重新部署。
- 伸缩这个项目变得困难:一个单一应用架构的应用只能在一个维度上伸缩。一反面,成交量上升时,可以通过运行更多实例的方法来伸缩,一些云服务甚至可以按需调节实例个数。但是在另一方面,这种架构难以根据数据量来调节。每个应用实例都会访问数据,使得缓存变得不那么有效,提高了内存消耗和I/O传输。同时,不同的组件有不同的资源需求,一个组件可能是CPU密集型,而另一个可能是内存密集型。单一应用架构下,我们很难对每个组件分别进行伸缩。
- 对于调节开发规模是个障碍: 一旦一个单一应用架构的应用达到了一个具体的规模,把团队分别几个更小的团队,专注与不同的功能块上是有效的。比如说,我们也许想要UI团队、审计团队、仓储团队等。但是单一应用架构阻碍了各个团队之间的独立工作。团队之间必须共同合作。
分布式应用架构
1.应用内容
同单一应用架构的内容。
2.解决方案
创建一个应用架构,使得这个应用的结构是一系列松耦合、互相合作的服务(services)。把所有的程序、功能拆分成不同的子系统,部署在多台不同的服务器上,这些子系统相互协作共同对外提供服务,而对用户而言他并不知道后台是多个子系统和多台服务器在提供服务,在使用上和集中式系统一样。
服务之间用同步协议比如HTTP/REST或者异步协议比如AMQP来进行通信。 每个服务有自己独立的数据库,从而与别的服务解耦。服务之间的数据一致性通过使用事件驱动架构来维护。如下图:
3.方案结果
优势:
- 每个微服务相对都比较小
- 易于开发者理解
- IDE更快
- 应用启动更快,利于开发和部署
- 每个服务可以独立于其他服务单独部署,利于频繁部署新版本
- 更容易伸缩开发资源。使你可以把开发资源分成多个团队。每个团队负责一个或多个服务。
- 提高了错误的隔离。比如说,在一个服务中产生了内容泄露,只有那一个服务会受影响。
- 不会对一个技术栈产生长期的依赖。在开发一个新服务或者重写服务时,可以选择新的技术栈。
缺陷:
- 开发者需要处理创建一个分布式系统时的额外的复杂度
- 测试更复杂
- 开发者必须实现服务间的通信机制
- 如果不使用分布式事务,会很难实现跨多个服务的用例
- 实现跨多个服务的用例需要团队间的更认真的合作
- 部署复杂性。在生产环境下,部署或者管理一个微服务系统有运维方面的复杂性。
- 更高的内存消耗。微服务架构需要N*M个实例,而单一架构只需要N个实例。如果每个服务在它自己的JVM上运行, 就需要M倍的JVM运行时。
4.问题
⭐什么时候适合使用分布式架构❓
当访问量越来越大,单一的单服务器已不能满足需要,我们需要通过不断添加服务器的方式来应对越来越大的访问量,但是通过不断添加服务器的方式带来的速度提升也越来越小,此时我们就需要拆分我们的应用,拆分成几个独立的不相干的应用,部署在不同的服务器上,以提升服务的能力。
⭐如何把应用拆解成多个服务❓
- 根据业务能力分离, 然后定义一个个服务
- 根据子域来拆解
- 根据用例/动词来拆解。比如说Shipping Service负责订单的输送。
- 根据资源/名词来拆解。比如说,Account Service负责管理用户的账号。
⭐如何保持数据一致性❓
为了保证松耦合,每个service有它自己的数据库。维护service之间的数据一致性是一个挑战,因为二阶段提交事务/分布式事务并不是很多应用的一个选项。相反的,一个应用必须使用事件驱动架构。一个服务在它的数据变化时,会发布一个事件。别的服务消费这个事件,然后更新自己的数据。有很多种可靠的数据更新和事件发布的方法,包括事件源和事务日志跟踪。
⭐如何实现查询❓
另一个挑战是实现需要从多个服务那里获取数据的查询。一个普遍的做法是使用命令查询职责分离,维护一个或多个view,它们通过订阅事件流的方式一直保持最新,事件流中的事件是别的service在数据变化时发布的。
作者: Zealon
崇尚简单,一切简单自然的事物都是美好的。