Orbit是在JVM上的一个使用虚拟actor来做分布式系统的框架。它使得开发者在开发分布式和易扩展的应用的时候,能够极大简化系统的集群、服务发现、网络、状态管理、actor生命周期等特性的开发。
Orbit是由EA(对,就是那个著名游戏公司)的下属游戏子公司Bioware(开发了无冬之夜、质量效应等优秀游戏)开发并开源的,这个框架的灵感是由微软的Orleans框架得来的,其目前的版本是1.1.0,这个版本优化了本地缓存,其使用了caffeine cache,增强了KryoSerializer,并优化了一些性能。Orbit所需的环境是java8、maven3.1及以上。Orbit这个框架目前在github上有超过一千的star,不算太小众,而且还获得了2016年的Duke's Choice Award for Open Source,所以还是值得一看的。
Orbit的一个重要组件是actor,actor之间的通信都是通过异步消息来交互的,Orbit确保一个actor不会同时被并行调用,这样开发者就不用担心actor的并发访问问题,但是如果开发者使用@Reentrant这个annotation来标识actor的话,当服务被阻塞时就能够让另一个请求进来(其实还是只有一个线程在活动)。创建一个actor时必须得先创建一个接口,如下,这个interface必须extends Orbit的Actor接口,然后里面定义的方法的返回类型必须是Orbit的Task类。Task类对CompletableFuture进行了简单的封装,可见Actor的方法都是通过异步回调方式来处理的。
public interface Chat extends Actor { @OneWay Task<Void> say(ChatMessageDto message); Task<Boolean> join(ChatObserver observer); Task<Boolean> leave(ChatObserver observer); Task<List<ChatMessageDto>> getHistory(int messageCount); }
然后你得创建一个类来实现上述接口,如下,这个类得extends Orbit的AbstractActor抽象类,并且这个类一次只能实现一个actor的接口。
public class ChatActor extends AbstractActor<ChatActor.State> implements Chat { private int maxMessages = 1000; private long lastSave; public static class State { ObserverManager<ChatObserver> observers = new ObserverManager<>(); LinkedList<ChatMessageDto> history = new LinkedList<>(); } @Override public Task<Void> say(final ChatMessageDto message) { System.out.println(message.getMessage()); if (getLogger().isDebugEnabled()) { getLogger().debug("Message received: " + message.getMessage()); } message.setWhen(new Date()); state().history.add(message); trimHistory(); state().observers.notifyObservers(o -> o.receiveMessage(message)); if (System.currentTimeMillis() - lastSave > TimeUnit.SECONDS.toMillis(60)) { return writeState(); } return Task.done(); } 省略。。。 }
不像别的框架,在Orbit中没有明确的actor的生命周期管理,actor不会创建和销毁,在概念上它是一直存在的。只不过它是分为“活动”和“不活动”两种状态,如果一个actor 被加载到内存中,那就是“活动”的,如果没有那就是相反。
Stage是Orbit的另一个重要组件,它是一个运行时执行容器,并且它是开发者与actor交互的重要手段。Orbit默认会使用UDP广播模式结合JGroups、Infinispan组件来做集群间的通信,但是通常UDP广播模式不太适合做云部署(比如AWS就没有提供UDP广播的支持),所以Orbit可以让开发者来配置具体的通信方式(如tcp通信),可以自定义xml配置文件放置到资源路径classpath下,如:classpath:/conf/jgroups.xml。
Actor能通过定义一个内部静态类来保存自己的状态,如下,可见还需要在extends AbstractActor的时候定义一下泛型。
public class StatefulActor extends AbstractActor<StatefulActor.State> implements Some { public static class State { String lastMessage; } }
这个状态操作起来也很方便,在actor的创建时就已经生成了它的内部静态类的一个实例,然后通过state()这个方法来获取这个实例,然后操作里面的属性。并且还能通过writeState()、readState()等方法来持久化存取状态(需要有相应的存储扩展)。
通常情况下Orbit只允许同id的actor只有一个是“活动”中的,不过有些情况下actor是无状态的,并且想提高吞吐量和降低响应时间,那就可以使用@StatelessWorker这个annotation,这样就能支持同id的actor能有多个实例“活动”着了。
Orbit有良好的扩展机制,目前官方也提供了很多不错的扩展,比如AWS S3、MongoDB、Jetty、HK2等的支持,自己去实现一些扩展也是很容易的,Orbit提供了很多扩展接口出来,如关于存储方面的StorageExtension,S3、MongoDB的扩展实现了这个接口,关于生命周期的LifetimeExtension,HK2的扩展实现了这个接口。
Orbit还与spring有了简单的集成,帮助开发者通过配置文件配置相关参数来自动创建stage并维护在容器里。还提供了OrbitHealthIndicator这个HealthIndicator(需要引入spring boot actuator)来监控容器内stage的状态,通过actuator暴露的rest api来获取信息。
目前Orbit还比较年轻,不过已经开始用于Bioware公司里的一些项目里,让我们多关注关注这些新兴的框架,说不定哪天它们就能火呢,哈哈。