使用Akka构建集群(一)
概述
Akka提供的非常吸引人的特性之一就是轻松构建自定义集群,这也是我要选择Akka的最基本原因之一。如果你不想敲太多代码,也可以通过简单的配置构建一个非常简单的集群。本文为说明Akka集群构建的学习成本低廉,以Akka官网的例子代码出发,进行简单改造后与Spring集成,有关Spring集成的信息你可以选择阅读《Spring与Akka的集成》一文。本文所讲述的是一款十分简便的集群监听器,它通过订阅集群成员的消息,对整个集群的成员进行管理(管理的方式只是打印一行日志)。
Akka集群规范
根据Akka官网的描述——Akka集群特性提供了容错的、去中心化的、基于集群成员关系点对点的,不存在单点问题、单点瓶颈的服务。其实现原理为闲聊协议和失败检查。
集群概念
- 节点(node):集群中的逻辑成员。允许一台物理机上有多个节点。由元组hostname:port:uid唯一确定。
- 集群(cluster):由成员关系服务构建的一组节点。
- 领导(leader):集群中唯一扮演领导角色的节点。
- 种子节点(seed node):作为其他节点加入集群的连接点的节点。实际上,一个节点可以通过向集群中的任何一个节点发送Join(加入)命令加入集群。
节点状态
这里以Akka官网提供的成员状态状态图为例,如图1所示。

图1
图1展示了状态转换的两个因素:动作和状态。
状态
- joining:节点正在加入集群时的状态。
- weekly up:配置了akka.cluster.allow-weakly-up-members=on时,启用的状态。
- up:集群中节点的正常状态。
- leaving/exiting:优雅的删除节点时,节点的状态。
- down:标记为已下线的状态。
- removed:墓碑状态,表示已经不再是集群的成员。
动作
- join:加入集群。
- leave:告知节点优雅的离开集群。
- down:标记集群为已下线。
配置
本节将要展示构建集群所需要的最基本的配置,几乎不会引入过多的开发成本,一个集群就构建完成了。application.conf文件的内容如下:
akka {
actor {
provider = "akka.cluster.ClusterActorRefProvider"
}
remote {
log-remote-lifecycle-events = off
netty.tcp {
hostname = "127.0.0.1"
port = 2551
}
}
cluster {
seed-nodes = [
"akka.tcp://metadataAkkaSystem@127.0.0.1:2551",
"akka.tcp://metadataAkkaSystem@127.0.0.1:2552"]
#//#snippet
# excluded from snippet
auto-down-unreachable-after = 10s
#//#snippet
# auto downing is NOT safe for production deployments.
# you may want to use it during development, read more about it in the docs.
#
# auto-down-unreachable-after = 10s
# Disable legacy metrics in akka-cluster.
metrics.enabled=off
}
}
此配置文件与我在《使用Akka的远程调用》一文中的配置有很多不同:
- provider不再是akka.remote.RemoteActorRefProvider,而是akka.cluster.ClusterActorRefProvider。这说明ActorRef将由akka.cluster.ClusterActorRefProvider提供;
- 增加了cluster配置;
cluster配置详解
简单集群监听器
我们创建一个简单的集群监听器SimpleClusterListener(实际上是一个Actor,因为继承了UntypedActor),它向集群订阅MemberEvent(成员事件)和UnreachableMember(不可达成员)两种消息,来对集群成员进行管理(打印),其实现见代码清单1所示。
代码清单1
@Named("SimpleClusterListener")
@Scope("prototype")
public class SimpleClusterListener extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
Cluster cluster = Cluster.get(getContext().system());
// subscribe to cluster changes
@Override
public void preStart() {
// #subscribe
cluster.subscribe(getSelf(), ClusterEvent.initialStateAsEvents(), MemberEvent.class, UnreachableMember.class);
// #subscribe
}
// re-subscribe when restart
@Override
public void postStop() {
cluster.unsubscribe(getSelf());
}
@Override
public void onReceive(Object message) {
if (message instanceof MemberUp) {
MemberUp mUp = (MemberUp) message;
log.info("Member is Up: {}", mUp.member());
} else if (message instanceof UnreachableMember) {
UnreachableMember mUnreachable = (UnreachableMember) message;
log.info("Member detected as unreachable: {}", mUnreachable.member());
} else if (message instanceof MemberRemoved) {
MemberRemoved mRemoved = (MemberRemoved) message;
log.info("Member is Removed: {}", mRemoved.member());
} else if (message instanceof MemberEvent) {
// ignore
} else {
unhandled(message);
}
}
}
运行展示
logger.info("Start simpleClusterListener");
final ActorRef simpleClusterListener = actorSystem.actorOf(springExt.props("SimpleClusterListener"), "simpleClusterListener");
actorMap.put("simpleClusterListener", simpleClusterListener);
logger.info("Started simpleClusterListener");
我们首先启动第一个种子节点,配置跟第一小节完全一致。我们观察SimpleClusterListener的日志输出如下图所示。

我们再启动第二个种子节点,其配置的akka.remote.netty.tcp.port为2552,我们观察SimpleClusterListener的日志输出如下图所示。

我们再启动一个非种子节点,没有为其指定akka.remote.netty.tcp.port,我们观察SimpleClusterListener的日志输出如下图所示。

可以看到新加入的节点信息被SimpleClusterListener打印出来了,细心的同学可能发现了一些Akka集群中各个节点的状态迁移信息,第一个种子节点正在加入自身创建的集群时的状态时JOINING,由于第一个种子节点将自己率先选举为Leader,因此它还将自己的状态改变为Up。后面它还将第二个种子节点和第三个节点从JOINING转换到Up状态。
我们停止第三个加入的节点,我们观察SimpleClusterListener的日志输出如下图所示。

可以看到其状态首先被标记为Down,最后被转换为Removed。
总结
通过以上介绍相信大家对使用Akka构建集群有了基本的认识,是不是很轻松?如果想要继续了解如何使用Akka构建集群,请阅读《使用Akka构建集群(二)》。
使用Akka构建集群(一)的更多相关文章
- 使用Akka构建集群(二)
前言 在<使用Akka构建集群(一)>一文中通过简单集群监听器的例子演示了如何使用Akka搭建一个简单的集群,但是这个例子“也许”离我们的实际业务场景太远,你基本不太可能去做这样的工作,除 ...
- memcached构建集群分析之一
memcached本身是不支持集群的,集群所关注的容灾.容错.宕机恢复机制统统都没有,实战中需要自己实现容灾机制. memcached集群相比memcached的优势: 巨量数据分布到集群的多台应用主 ...
- 分布式搜索ElasticSearch构建集群与简单搜索实例应用
分布式搜索ElasticSearch构建集群与简单搜索实例应用 关于ElasticSearch不介绍了,直接说应用. 分布式ElasticSearch集群构建的方法. 1.通过在程序中创建一个嵌入es ...
- Docker 0x13: Docker 构建集群/服务/Compose/分布式服务栈
目录 Docker 构建集群/服务/Compose/分布式服务栈 集群 初始化集群服务 安装docker-machine 管理节点和工作节点 docker集群构建完成 集群中部署应用 集群服务访问特性 ...
- 如何通过云效Flow完成自动化构建—构建集群
如何通过云效Flow完成自动化构建-构建集群,云效流水线Flow是持续交付的载体,通过构建自动化.集成自动化.验证自动化.部署自动化,完成从开发到上线过程的持续交付.通过持续向团队提供及时反馈,让交付 ...
- KingbaseES R6 通过脚本构建集群案例
案例说明: KingbaseES V8R6部署一般可采用图形化方式快速部署,但在生产一线,有的服务器系统未启用图形化环境,所以对于KingbaseES V8R6的集群需采用手工字符界面方式部署,本 ...
- akka 的集群访问方式
akka 中采用startProxy分区代理 访问 ,跟使用shardRegion 来访问的区别 这两种访问方式是不是重了呢. 而另外这是一个单例代理 private fun startUniver ...
- JBoss 系列四十八:JBoss 7/WildFly 使用TCP构建集群
我知道JBoss 集群Default 的设定就是UDP(JGroups),但在实际环境中的网络环境时常不允许UDP,在这种情况下,我们就需要使用TCP. JBoss 7/WildFly 中负责集群的主 ...
- 使用docker-compose快速构建集群示例(一)
一.zookeeper集群 docker-compose文件: version: '3.1' services: zoo1: image: zookeeper hostname: zoo1 conta ...
随机推荐
- 4.update更新和delete删除用法
一.update更新 UserMapper.java package tk.mybatis.simple.mapper; import org.apache.ibatis.annotations.Pa ...
- https://www.cnblogs.com/hnxxcxg/p/6085149.html
DELPHI微信支付代码 不管是微信支付还是支付宝支付, 3个最棘手的问题是:1,如何生成签名2,支付请求如何提交3, 如何验证签名 下面就围绕这二个问题来讲. 我使用的是XE3. 先看微信支付: ...
- Spring与多线程
前言背景 在做新项目,作为中间件的项目,主要做数据服务.这次想把项目做的简洁一些,之前用的什么ActiveMq等中间件产品,这次全部不用,能自己实现就自己实现.自己用BlockingQueue阻塞队列 ...
- python操作excel及json
有一个存着学生成绩的文件:stuscore.txt,里面存的是json串,json串读起来特别不直观,需要你写代码把它都写到excel中,并计算出总分和平均分,json格式如下: { ":[ ...
- Asp .Net core 2 学习笔记(2) —— 中间件
这个系列的初衷是便于自己总结与回顾,把笔记本上面的东西转移到这里,态度不由得谨慎许多,下面是我参考的资源: ASP.NET Core 中文文档目录 官方文档 记在这里的东西我会不断的完善丰满,对于文章 ...
- 【转】「Chris Richardson 微服务系列」微服务架构的优势与不足
Posted on 2016年5月4日 编者的话|本文来自 Nginx 官方博客,是微服务系列文章的第一篇,主要探讨了传统的单体式应用的不足,以及微服务架构的优势与挑战. 作者介绍:Chris Ric ...
- Python isinstance 与 instance 的用法
instance: instance 属于python2的关键字,python2中如果一个类没有继承自object, 那么实例化出来的对象就是instance类型,否则就是class类型. isins ...
- spring boot实现异步调用
今天在这里学习下使用springboot的异步调用async 首先使用@EnableAsync开启异步功能 /** * @author fengzp * @date 17/5/8 * @email f ...
- [Vuejs] 组件 v-if 和 v-show 切换时生命周期钩子的执行
v-if 初始渲染 初始值为 false 组件不会渲染,生命周期钩子不会执行,v-if 的渲染是惰性的. 初始值为 true 时,组件会进行渲染,并依次执行 beforeCreate,created, ...
- JSX 和 template 随想
就目前而言,我用到的前端页面开发框架主要有两种:以JSX为主的react和以template为主的vue. 虽然这两种方式各有千秋,但我其实更偏爱template多一些.为什么? 相较于灵活的JSX, ...