喜欢和它的错误内核
Akka and its Error Kernel
我正在阅读 Akka (Java lib) 文档,需要澄清一些他们自己宣称的 Akka/Actor Best Practices。
Actors should not block (i.e. passively wait while occupying a Thread) on some external entity...The blocking operations should be
done in some special-cased thread which sends messages to the actors which shall act on them.
那么 Akka/Java 中的代码示例是什么样的?如果 Actor
不适合放置 必须 阻塞的代码,那么 所做的 满足 "some special-cased thread"?
Do not pass mutable objects between actors. In order to ensure that, prefer immutable messages.
我熟悉如何制作不可变的 classes(没有 public 设置器,没有 public 字段,使 class final
, ETC。)。但是 Akka 有自己的 "immutable class" 定义吗?如果有,它是什么?
Top-level actors are the innermost part of your Error Kernel...
我什至不知道这是什么意思!我理解他们所说的 "top-level" 演员(在 actor/manager/supervisor 等级中最高)的意思,但是什么是 "Error Kernel",它与演员有什么关系?
我只能回答第一个问题(以后请在 post 中只填一个问题)。
例如,考虑一个固有阻塞的数据库连接。为了允许参与者连接到数据库,程序员应该创建一个带有数据库请求队列的专用线程(或线程池)。请求包含数据库语句和对接收结果的参与者的引用。专用线程循环读取请求,访问数据库,将结果发送给引用的actor等。请求队列阻塞——当没有请求时,连接线程阻塞在queue.take()
操作中。
因此,对数据库的访问分为两个参与者 - 一个向队列发出请求,另一个处理结果。
更新:Java 代码草图(我不擅长 Scala)。
class Request {
String query;
ActorRef handler;
}
class DatabaseConnector implements Runnable {
LinkedBlockingQueue<Request> queue=new LinkedBlockingQueue<Request>();
Thread t = new Thread(this);
{t.start();}
public void sendRequest(Request r) {
queue.put(r);
}
public void run() {
for (;;) {
Request r=queue.take();
ResultSet res=doBlockingCallToJdbc(r.query);
r.handler.sendOneWay(res);
}
}
这是您第二个问题的答案。来自 Akka Doc:
If one actor carries very important data (i.e. its state shall not be
lost if avoidable), this actor should source out any possibly
dangerous sub-tasks to children it supervises and handle failures of
these children as appropriate. Depending on the nature of the
requests, it may be best to create a new child for each request, which
simplifies state management for collecting the replies. This is known
as the “Error Kernel Pattern” from Erlang.
所以你说的这句话意味着这些演员是 "last line of defence" 来自你的监督等级制度的错误,所以他们应该是强壮有力的人(突击队)而不是一些软弱的工人。你拥有的突击队员越少——管理他们就越容易,避免高层出现混乱。准确地说,突击队的数量应该接近您拥有的业务协议的数量(转向超级英雄 - 假设一个用于 IronMan,一个用于 Hulk 等)
这篇文档也很好地解释了如何管理阻塞操作。
说起来
If an Actor isn't an appriote place to put code that has to block then what does satisfy the definition of "some special-cased thread
Actor 肯定不会,因为 Akka 只保证顺序性,但您的消息可以在任何线程上处理(它只是从池中获取一个空闲线程),即使对于单个 actor 也是如此。不建议在那里进行阻塞操作(至少在与正常线程池相同的线程池中),因为它们可能会导致性能问题甚至死锁。例如,参见 Spray 的解释(它基于 Akka):
你可能会认为 akka 需要只与异步交互 API。您可以考虑 Future 将同步转换为异步 - 只需将数据库的响应作为消息发送给参与者。 scala 示例:
receive = { //this is receiving method onReceive
case query: Query => //query is message safely casted to Query
Future { //this construction marks a peace of code (handler) which will be passed to the future
//this code will be executed in separate thread:
doBlockingCallToJdbc(query)
} pipeTo sender //means do `sender ! futureResult` after future's completion
}
}
同一文档中描述了其他方法 (Akka Doc)
我正在阅读 Akka (Java lib) 文档,需要澄清一些他们自己宣称的 Akka/Actor Best Practices。
Actors should not block (i.e. passively wait while occupying a Thread) on some external entity...The blocking operations should be done in some special-cased thread which sends messages to the actors which shall act on them.
那么 Akka/Java 中的代码示例是什么样的?如果 Actor
不适合放置 必须 阻塞的代码,那么 所做的 满足 "some special-cased thread"?
Do not pass mutable objects between actors. In order to ensure that, prefer immutable messages.
我熟悉如何制作不可变的 classes(没有 public 设置器,没有 public 字段,使 class final
, ETC。)。但是 Akka 有自己的 "immutable class" 定义吗?如果有,它是什么?
Top-level actors are the innermost part of your Error Kernel...
我什至不知道这是什么意思!我理解他们所说的 "top-level" 演员(在 actor/manager/supervisor 等级中最高)的意思,但是什么是 "Error Kernel",它与演员有什么关系?
我只能回答第一个问题(以后请在 post 中只填一个问题)。
例如,考虑一个固有阻塞的数据库连接。为了允许参与者连接到数据库,程序员应该创建一个带有数据库请求队列的专用线程(或线程池)。请求包含数据库语句和对接收结果的参与者的引用。专用线程循环读取请求,访问数据库,将结果发送给引用的actor等。请求队列阻塞——当没有请求时,连接线程阻塞在queue.take()
操作中。
因此,对数据库的访问分为两个参与者 - 一个向队列发出请求,另一个处理结果。
更新:Java 代码草图(我不擅长 Scala)。
class Request {
String query;
ActorRef handler;
}
class DatabaseConnector implements Runnable {
LinkedBlockingQueue<Request> queue=new LinkedBlockingQueue<Request>();
Thread t = new Thread(this);
{t.start();}
public void sendRequest(Request r) {
queue.put(r);
}
public void run() {
for (;;) {
Request r=queue.take();
ResultSet res=doBlockingCallToJdbc(r.query);
r.handler.sendOneWay(res);
}
}
这是您第二个问题的答案。来自 Akka Doc:
If one actor carries very important data (i.e. its state shall not be lost if avoidable), this actor should source out any possibly dangerous sub-tasks to children it supervises and handle failures of these children as appropriate. Depending on the nature of the requests, it may be best to create a new child for each request, which simplifies state management for collecting the replies. This is known as the “Error Kernel Pattern” from Erlang.
所以你说的这句话意味着这些演员是 "last line of defence" 来自你的监督等级制度的错误,所以他们应该是强壮有力的人(突击队)而不是一些软弱的工人。你拥有的突击队员越少——管理他们就越容易,避免高层出现混乱。准确地说,突击队的数量应该接近您拥有的业务协议的数量(转向超级英雄 - 假设一个用于 IronMan,一个用于 Hulk 等)
这篇文档也很好地解释了如何管理阻塞操作。
说起来
If an Actor isn't an appriote place to put code that has to block then what does satisfy the definition of "some special-cased thread
Actor 肯定不会,因为 Akka 只保证顺序性,但您的消息可以在任何线程上处理(它只是从池中获取一个空闲线程),即使对于单个 actor 也是如此。不建议在那里进行阻塞操作(至少在与正常线程池相同的线程池中),因为它们可能会导致性能问题甚至死锁。例如,参见 Spray 的解释(它基于 Akka):
你可能会认为 akka 需要只与异步交互 API。您可以考虑 Future 将同步转换为异步 - 只需将数据库的响应作为消息发送给参与者。 scala 示例:
receive = { //this is receiving method onReceive
case query: Query => //query is message safely casted to Query
Future { //this construction marks a peace of code (handler) which will be passed to the future
//this code will be executed in separate thread:
doBlockingCallToJdbc(query)
} pipeTo sender //means do `sender ! futureResult` after future's completion
}
}
同一文档中描述了其他方法 (Akka Doc)