官方文档:https://getakka.net/index.html

官网:https://petabridge.com/

一、Akka.NET 是什么?

Akka 是一个构建高并发、分布式和弹性消息驱动的工具包。Akka.NET 是 Akka 的一个 .NET 的移植库。

Akka.NET 内部都是 Actor 构成的,Actor 是一个状态、行为、邮箱、子节点和监视者策略构成的容器。

二、Akka.NET 的一些基础模块

Akka - 核心 Actor 库
Akka.Remote - 跨节点 Actor 部署/通信
Akka.Cluster - 弹性 Actor 网络(HA)
Akka.Persistence - 事件源, 持久化 Actor 状态 & 恢复
Akka.Streams - 流式工作流
Akka.Cluster.Tools - 集群单例, 分布式发布/订阅
Akka.Cluster.Sharding - 持久化状态分区
Akka.DData - 最终一直的数据复制

三、Akka.NET 的架构

如图所示,一个 akka 系统有一个跟节点 root,然后 root 有2个子节点,user 和 system ,你定义的 actor 都在 user 下,system 下都是系统定义的

四、Akka.NET 发送消息的规则

  • 最多一次交付

  • 每个配对的发送者、接收者对消息保持排序。

五、基础 Actor 类型

  • ReceiverActor:如果使用这个类型的 Actor 为基类,使用 Receive<T>(msg=>{}); 来接收消息
  • UntypedActor:如果使用这个类型的 Actor 为基类,需要重写 OnReceive(object message) 方法,然后区分 message 类型

六、使用 Akka.NET

  • 普通模式

因为 Helloworld 的例子太多了,官网也有,这里直接略过。

代码在这里

代码里有些特殊情况的处理没写,这里简单说一下

比如 sender 发送给了 receiver 一个消息,但是 receiver 还有些事情没有准备好,比如发送来一个消息,但是可能需要先登录,那就先缓存下来,等办完事再处理

流程是:先 Stash 消息,开启 Scheduler ,发送 GetToken 消息,token 获取成功返回 GetTokenSuccess 消息,取消 Scheduler ,变成 Redy 状态,正常处理消息

public ReceiveActor()
{
private ICancelable _cancel; public ReceiveActor()
{
Receive<TestMsg>(msg =>
{
Stash.Stash();
}); Receive<GetToken>(msg =>
{
GetTokenProcess();
} Receive<GetTokenSuccess>(msg =>
{
_cancel?.Cancel();
_cancel = null; Become(Ready);
}); if (_cancel == null)
{
_cancel = Context.System.Scheduler.ScheduleTellRepeatedlyCancelable(TimeSpan.Zero, TimeSpan.FromSeconds(), Self, new GetToken(), Self);
}
} private void Ready()
{
Receive<TestMsg>(msg =>
{
//Todo
}); Stash.UnstashAll();
} private void GetTokenProcess()
{
var tokenActor = Context.ActorOf(Props.Create(() => new TokenActor("url")));
tokenActor.Ask<GetTokenSuccess>(new GetToken
{
Token = "",
}).ContinueWith(tr =>
{
if (tr.IsCanceled || tr.IsFaulted)
{
return new GetTokenSuccess();
} return tr.Result;
}).PipeTo(Self);
} public class GetToken
{
public string Token { get; set; }
}
}
  • Router

Actor 内部其实是单线程的处理消息的,但是用了 Router 可以把消息分出去给多个节点处理,这里分为2种模式,group 和 pool

先来看 group 配置

akka {
actor{
provider = cluster
deployment {
/api/myClusterGroupRouter {
router = broadcast-group # routing strategy
routees.paths = ["/user/api"] # path of routee on each node
nr-of-instances = 3 # max number of total routees
cluster {
enabled = on
allow-local-routees = on
use-role = crawler
}
}
}
}
}

如图看到在 89节点上注册了 90 和 91 节点的 Routees

pool 模式

akka {
actor{
provider = cluster
deployment {
/api/myClusterPoolRouter {
router = round-robin-pool # routing strategy
nr-of-instances = 10 # max number of total routees
cluster {
enabled = on
allow-local-routees = on
use-role = crawler
max-nr-of-instances-per-node = 1
}
}
}
}
}

这种模式其实是在 90 和 91 的节点上分别注册了 89 的 routee,89上是akka.tcp://Sys@localhost:90/remote/akka/tcp/localhost:89/$a 和 akka.tcp://Sys@localhost:91/remote/akka/tcp/localhost:89/$a

具体代码在这里

  • Shard

用逻辑 id 联系,不关心集群中的物理位置或管理他们的创建,可以 rebalance (消耗资源比较大,只有差异比较大的时候才会,默认 rebalance-threshold = 10,shard 数量设置为集群节点最大数量的10倍,shard 数量太大消耗大)

整个 ActorSystem 中只能有一个Codinator,在最老的节点上,因为最老的节点被认为是安全的。

如图所示整个系统分为了 Coordinator ,Shard region(typeName), Shard,Entity 部分,节点的路径是  /user/sharding/<typeName>/<shardId>/<entityId> 和普通的路径 /user/<actorName> 不一样

这里使用了 Persistent ,每种数据库的配置完全不同,我是 Redis 的配置,建议使用即时更新的数据库,不更新的很可能是弃用的,比如 mysql。

具体代码在这里

这里需要注意的是:

  1. 只能有一个 Lighthourse —— 否在爆 ID 13 error
  2. 创建 ActorSystem 的时候后边加上 _config.WithFallback(ClusterClientReceptionist.DefaultConfig()).WithFallback(DistributedPubSub.DefaultConfig()); —— 否在爆 ID 9 error
  • 区别

Shard 看着好像也能处理 Router 的问题,但这里又有些区别,此处摘自官方文档,用的自动翻译,请自行理解下:

在一致的散列场景中,整个密钥空间被拼接在我们在路由器配置中定义的参与者数量之间。这究竟意味着什么?单个参与者实例负责处理整个范围的密钥。例如:假设在一个一致的哈希路由器后面,我们有一个数字1-100的密钥空间,在5个参与者之间平均共享。这意味着,第一个参与者将负责处理ID为1-20、第二个参与者21-40、第三个参与者41-60等的所有消息。如果您的目标是每个标识符有一个唯一的参与者,那么对于您的情况来说,这不是一个有效的场景。在集群分片场景的另一边,每个实体(这就是我们如何引用分片参与者)由对(ShardId,EntityId)标识。它是1-1关系,因此用同一对标识的消息保证总是路由到相同的单个实体。 另一个区别是灵活性。一致的哈希路由器几乎是静态的,在您想要调整集群大小的情况下,它们不能很好地工作。你记得以前提到过的拼接键空间的概念吗?想象一下,一旦我们改变分配给它的参与者/节点的实际数量,它将如何工作。当然,这些关键范围也必须改变。因此,在集群大小调整之后,以前处理ID为1-20的消息的演员现在可以处理不同的范围(即,1-15)。这称为“分区切换”。当使用集群切分时,我们的参与者将能够随着集群大小的改变迁移到其他节点,即使在集群大小改变时,也能够保持消息id和分割实体之间的关系。

七、总结

除了 stream 没研究,其他的多少都看了一点,因为我没有使用 stream 的场景,其他发现 Helloworld 的入门真的没什么用,只是让你理解 Actor 的开发的思想和模式,实际使用需要多看文档,一点点研究,还有就是官网的博文,再就是一些大神写的例子,

这里放几个网址供大家学习

GitHub:

https://github.com/cgstevens/FileProcessor

https://github.com/Horusiath/AkkaDemos

https://github.com/petabridge/akkadotnet-code-samples

https://github.com/Lutando/Akkatecture

文档:

Streams:https://petabridge.com/blog/akkadotnet-11-cluster-streams/

Distributed Pub-Sub:https://petabridge.com/blog/distributed-pub-sub-intro-akkadotnet/

Shard:https://petabridge.com/blog/introduction-to-cluster-sharding-akkadotnet/

Shard:https://petabridge.com/blog/cluster-sharding-technical-overview-akkadotnet/

Petabridge.Cmd:https://petabridge.com/blog/petabridgecmd-release/

Moonitoring:https://github.com/petabridge/akka-monitoring

你是不是感觉很奇怪,没有 Dashboard 呢,其实是有,但是收费,在这里:https://phobos.petabridge.com/

走进 Akka.NET的更多相关文章

  1. Akka.net路径里的user

    因为经常买双色球,嫌每次对彩票号麻烦,于是休息的时候做了个双色球兑奖的小程序,做完了发现业务还挺复杂的,于是改DDD重做设计,拆分服务,各种折腾...,不过这和本随笔没多大关系,等差不多了再总结一下, ...

  2. [C#] 走进异步编程的世界 - 开始接触 async/await

    走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $&qu ...

  3. [C#] 走进 LINQ 的世界

    走进 LINQ 的世界 序 在此之前曾发表过三篇关于 LINQ 的随笔: 进阶:<LINQ 标准查询操作概述>(强烈推荐) 技巧:<Linq To Objects - 如何操作字符串 ...

  4. Aaron Stannard谈Akka.NET 1.1

    Akka.NET 1.1近日发布,带来新特性和性能提升.InfoQ采访了Akka.net维护者Aaron Stannard,了解更多有关Akka.Streams和Akka.Cluster的信息.Aar ...

  5. 【NLP】前戏:一起走进条件随机场(一)

    前戏:一起走进条件随机场 作者:白宁超 2016年8月2日13:59:46 [摘要]:条件随机场用于序列标注,数据分割等自然语言处理中,表现出很好的效果.在中文分词.中文人名识别和歧义消解等任务中都有 ...

  6. 走进缓存的世界(三) - Memcache

    系列文章 走进缓存的世界(一) - 开篇 走进缓存的世界(二) - 缓存设计 走进缓存的世界(三) - Memcache 简介 Memcache是一个高性能的分布式内存对象缓存系统,用于动态Web应用 ...

  7. Akka.NET v1.0 已发布,支持Mono

    Akka.NET 是Java/Scala 流行框架Akka的一个 .NET 开源移植.可用于构建高并发,分布式和容错事件驱动的应用在 .NET 和 Mono 平台之上.Akka.NET 经过一年多的努 ...

  8. 小丁带你走进git的世界三-撤销修改

    一.撤销指令 git checkout还原工作区的功能 git reset  还原暂存区的功能 git clean  还没有被添加进暂存区的文件也就是git还没有跟踪的文件可以使用这个命令清除他们 g ...

  9. 小丁带你走进git的世界二-工作区暂存区分支

    小丁带你走进git的世界二-工作区暂存区分支 一.Git基本工作流程 1.初始化一个仓库 git  init git  clone git仓库分为两种情况: 第一种是在现有项目或目录下导入所有文件到 ...

随机推荐

  1. rn初体验

    react-native 需要的工具 .nodejs .rn cli .xcode and as ---------------- 打开终端,切换到根路径(mac中修改npm的默认安装来源) 一.op ...

  2. Java日期时间实用工具类

    Java日期时间实用工具类 1.Date (java.util.Date)    Date();        以当前时间构造一个Date对象    Date(long);        构造函数   ...

  3. Leetcode 703. 数据流中的第K大元素

    1.题目要求 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器, ...

  4. jq 正则

    if(_each_this_type_name == 'post_num'){ var patrn = /^[a-zA-Z0-9]{3,12}$/; if(!patrn.test(_each_this ...

  5. Http字段含义

    转载自:http://blog.csdn.net/sand_ant/article/details/10503579 一.request请求Header简介 Accept:--客户机支持的类型 Acc ...

  6. [LeetCode] 14. Longest Common Prefix ☆

    Write a function to find the longest common prefix string amongst an array of strings. 解法: 广度优先搜索:先比 ...

  7. linux查找进程id端口占用和杀死进程

    linux 查找进程id端口占用和杀死进程 ps 命令用于查看当前正在运行的进程 辅助上grep 用于搜索匹配ps -ef | grep java ps ax : 显示当前系统进程的列表 ps aux ...

  8. 【Tools】Windows下Github的配置和使用

    1.在网址:http://windows.github.com/下载git软件,具体的安装步骤可以参见:Windows 系统下Git安装图解 2.同样根据上面的教程生成SSH key: 3.将publ ...

  9. 【BZOJ4517】【SDOI2016】排列计数 [数论]

    排列计数 Time Limit: 60 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 求有多少种长度为 n 的序列 A, ...

  10. 【BZOJ】1718: [Usaco2006 Jan] Redundant Paths 分离的路径

    [题意]给定无向连通图,要求添加最少的边使全图变成边双连通分量. [算法]Tarjan缩点 [题解]首先边双缩点,得到一棵树(无向无环图). 入度为1的点就是叶子,两个LCA为根的叶子间合并最高效,直 ...