一个新系统,需要集中管理公司的几个现有业务系统的基础数据。其中每个被管系统有N多实例,全球多地区异地部署。
架构挑战:
- 被管系统基础数据变更需要实时收集到新系统
- 新系统的用户指令需要实时下达到被管系统。即双向实时(双工)。
- 网络连接单向建立:只能由被管系统主动连接新系统,并保持长连接
- 比较多的被管系统实例,连接数不少
- 网络情况不稳定:由于是全球部署
- 新系统本身需要支持分布式部署。需要正确路由不同节点的用户指令到不同节点的被管系统长连接
- 快速响应不确认的需求变化和动态调整,模块依赖性必须低,内聚性好。需要支持消息的广播和点对点传播
- 支持灰度发布
面对以上挑战,传统的双向RPC+负载均衡架构不适合。事件驱动的框架(EDA)成为主要考虑方向 。而一个好用的EDA架构设计,需要一套成熟的架构和开发模式支持。实施时需要一套成熟的框架支持以减少工作量和提高稳定性。以下为技术选型的思考结果和说明。
1.基本概念
1.1 Actor Model 模式
What:什么是Actor模式
出处:http://www.brianstorti.com/the-actor-model/
形象点说,每个Actor是一个人,他有多个输入源(耳、鼻、眼),同一时间他只能就输入源来响应做一件事。他有自己的记忆(状态)。他耐性不好,向其它人口头下达指令后,不等其它人做完就忙其它的事情去了。
每个Actor可认为一个Event Loop可简单理解为线程(实际可能多个Actor共享线程)。它有以下组件:
- 事件信箱
- 内部状态数据
Actor Event Loop的状态有:
- 等待信箱事件
- 处理事件中(运行中)
一般,研发会使用异步IO编程方法,来实现具体的Actor。即,具体Actor的关心的IO读写事件也会放入Actor自己的信箱。处于【处理事件中】的事件消费程序,不会有IO引起的Block等待。
Why: Actor模式的用处
- 简化多线程编程:单线程的Actor程序,可以保证内部状态不并发访问。不再需要考虑多线程共享状态下的各种问题。
- 天然分布式设计:Actor间基于消息的通讯,天然地支持分布式的部署,如果使用合适的Actor容器,多Actor实例的管理等,天然地实现了“微服务”架构。
- HA:Actor 容器可以用统一的健康探测消息,来测试Actor的健康情况。需要时可以重启新的Actor
- 其它Event Driven Arch(EDA)的好处。
Who:谁在用Actor模式
- Erlang
- Akka
- Vert.x
- ......
1.2 Vert.x
What:什么是Vert.x
官话是这样说的:
Eclipse Vert.x is a tool-kit for building reactive applications on the JVM.
- Scale:Eclipse Vert.x is event driven and non blocking. This means your app can handle a lot of concurrency using a small number of kernel threads. Vert.x lets your app scale with minimal hardware.
- Polyglot:You can use Vert.x with multiple languages including Java, JavaScript, Groovy, Ruby, Ceylon, Scala and Kotlin.
- General purpose:Vert.x is incredibly flexible - whether it's simple network utilities, sophisticated modern web applications, HTTP/REST microservices, high volume event processing or a full blown back-end message-bus application, Vert.x is a great fit.
- fun:Enjoy being a developer again.Unlike restrictive traditional application containers, Vert.x gives you incredible power and agility to create compelling, scalable, 21st century applications the way you want to, with a minimum of fuss, in the language you want.
我关注的是最后一点:) 有人说它是java界的Node.js。但它自称性能上,多语言上超越Node.js。有人说它是瑞士军刀,管饭还管车,因为他是个异步框架,Web框架,也送Event Bus,支持Actor模式,支持微服务管理和发现等等……我真心怀疑它能做得精吗?
Actor框架
Actor,在Vert.x中叫Verticle。(http://vertx.io/docs/vertx-core/java/#_verticles)
Event Bus
事件总线,支持事件广播、点到点发送、点对点发送与回复(Reply)
http://vertx.io/docs/vertx-core/java/#event_bus
并发编程框架
- inline异步任务(Verticle中异步调用阻塞代码的类似ForkJoinPool)
- Future的串并联使用,异步任务与结果的封装
- 莱坞原则的异步Callback编程
异步IO编程框架
响应式编程
如果你认为OOP或好莱坞原则的异步Callback编程已经OUT了,或者已经被Callback Hell坑过。那么可以试试Reactive。Vert.x 支持Rx-ified using RxJava
集群
跨JVM的集群Event Bus,基于hazelcast来实现集群的发现和消费订阅的登记
http://vertx.io/docs/vertx-core/java/#_cluster_managers
1.2.1 Vert.x 中的Actor模式怎么玩
Actor模式在Vert.x中这样体现:
- Actor --> Verticle
- 信箱 --> 一般的事件,如Event Bus 消息到达池。还有其它事件,如Http/Websocket/异步JDBC请求或事件池、inline异步任务(Verticle中异步调用阻塞代码的类似ForkJoinPool)的结果池。
- Actor的信箱消费线程--> Event Loop
所以,黄金规则是Verticle中不能写阻塞的代码,如果一定要用,解决方法是:放在后台工作线程池中阻塞
1.2.2 Vert.x EventBus是什么
Vert.x EventBus是个普通的无中心消息框架
- 消息框架支持:
- 事件广播
- 点到点发送
- 点对点发送与回复(ACK)
事件总线的作用:
- 事件的发生源模块,事件的监听模块完全解藕。
- 事件可以支持广播、路由、点对点等方法传递。生产者不关心订阅者的数量、实现逻辑。
- 生产者与订阅者可以关注自己的subject。生产者与订阅者间没有相互的依赖关系。
SLA:
- 消息没有持久化,可能丢失。消息的投递以最大努力为原则,即不保证成功
Vert.x EventBus是个分布式消息框架
- 支持机器间EventBus的集群共享(可选基于hazelcast),消息和Subject可以在集群中传播。
- 在有分布式部署,功能和服务热插拔,HA要求的情况下可以灵活支撑。
- 集群自治,同时支持成员的发现和异常发现
Vert.x EventBus是个打通到客户端的消息框架,是个All in one工具集
由于它包含一个EventBus SockJS Bridge。模块,浏览器可以通过它提供的JS库,使用sockjs协议(Server-Sent Events/Websocket/HTTP poll)来接入EventBus。官方文档:http://vertx.io/docs/vertx-web/java/#_sockjs_event_bus_bridge
好处:
- 后端的事件,可以实时通知到浏览器(提供event bus javascript库),实时推浏览器的广播变得相对容易实现。想想一个长后台任务完成,或监控事件发发时,一切都变得实时响应到用户端。
- 浏览器也可以向后端发送异步指令和请求。