java akka_Akka反模式:Java序列化

java akka

当消息离开JVM边界时, Akka将使用序列化。 这可能主要发生在两种情况下:使用Akka Cluster( 不要直接使用Akka Remote )或使用Akka Persistence通过网络发送消息时。

现在有个问题:在Akka中配置的默认序列化技术不过是臭名昭著的Java序列化, Mark Reinhold称之为“可怕的错误”,并且Oracle计划在不久的将来将其转储

使用Java序列化时,您会在日志中收到警告消息:

[WARN] [03/29/2016 16:53:40.137] [LookupSystem-akka.remote.default-remote-dispatcher-8] 
[akka.serialization.Serialization(akka://LookupSystem)] Using the default Java serializer for class 
[sample.remote.calculator.Subtract] which is not recommended because of performance implications.
Use another serializer or disable this warning using the setting 'akka.actor.warn-about-java-serializer-usage'

很好,但这还不够-毕竟它们很容易被忽略(可以关闭警告-可能很诱人)。

Akka文档不鼓励使用Java序列化– 序列化文档中有一条注释,主要指出了性能问题:

"It is highly encouraged to disable java serialization, so please plan to do so at the earliest possibility you have in your project.
One may think that network bandwidth and latency limit the performance of remote messaging, but serialization is a more typical bottleneck."

现在,性能是不使用Java序列化的原因之一-但有更多的理由不使用Java序列化,尤其是在Akka的情况下:

  • 安全性:Java序列化是一段时间以来已知的攻击媒介
  • 模式演化 :使用Akka Persistence进行事件源化时,您将遇到需要演化存储的消息的情况(除非您不在生产中使用项目,并且需求也不会演化)。 Java序列化不适合处理消息编码中的更改, 有一些方法可以向后兼容,但充其量是繁琐的。 如果您不计划并拥有一个运行中的带有Java序列化的生产系统,那么您会感到很意外-您必须在运行中的生产系统中进行序列化技术的转换,这需要非常小心协调的
  • 消息协议的演变:当您运行集群应用程序并想以滚动方式重新部署它(即,一个节点升级另一个节点)时,将面临运行不同协议版本的节点的麻烦。 对此没有灵丹妙药-对于不兼容的更改,您可能仍然需要构建消息适配器-但对于更常见的更改(例如添加或重命名字段),二进制协议使生活比Java序列化要容易得多

该怎么做呢?

在开始新项目时,您应该做的第一件事是通过将以下行添加到application.conf来禁用Java序列化:

akka.actor.allow-java-serialization = off

接下来,您将需要一个二进制序列化协议。 您真的不想使用JSON,除非您是那种喜欢像Martin Thompson所说的那样对其负载收集器进行负载测试的人。 现在有很多周围:

马丁·克莱普曼(Martin Kleppmann) 对Avro,协议缓冲区和Thirft进行了很好的比较,重点是消息演化。 二进制协议中有不同的方法,一种是使用逐字段方法的方法,另一种是使用完整方案的方法–两种方法各有优缺点,确实需要根据您的项目和组织结构进行评估。

Akka在内部使用协议缓冲区,其优点是集成它们非常简单。 例如,如果使用ScalaPB从协议缓冲区定义中生成案例类,则只需进行以下配置即可使工作正常:

akka {
  actor {
    # repeated here, because you really should have this line in your project
    akka.actor.allow-java-serialization = off
 
    # which serializers are available under which key
    serializers {
      proto = "akka.remote.serialization.ProtobufSerializer"
    }
 
    # which interfaces / traits / classes should be handled by which serializer
    serialization-bindings {
      "scalapb.GeneratedMessage" = proto
    }
  }
}

还有一件事:随着Akka Typed的兴起,为每个参与者定义一个协议(而不是共享消息)的最佳实践变得越来越重要。 因此,我在许多项目中成功使用的一种方法现在使用以下模式(与ScalaPB结合使用):

  • 为每个参与者定义一个协议文件
  • proto文件与actor的包结构放置在相同的目录结构中,例如actor foo.bar.SomeActor src/main/protobuf/foo/bar/SomeActorProtocol.proto
  • 启用正确的选项以仅为所有参与者消息生成一个scala源文件

例如, SomeActorProtoco.proto文件将如下所示:

syntax = "proto3";
 
import "scalapb/scalapb.proto";
import "google/protobuf/timestamp.proto";
 
package foo.bar.SomeActorProtocol;
 
option (scalapb.options) = {
    single_file: true
    flat_package: true
    preamble: "sealed trait Command"
    preamble: "sealed trait Event"
};
 
// Commands
 
message Greet {
    option (scalapb.message).extends = "Command";
    string message = 1;
}
 
// Events
 
message GreetingReceived {
    option (scalapb.message).extends = "Event";
    String greeting = 1;
    google.protobuf.Timestamp timestamp = 2;
}

而已! 如果您现在意识到自己做错了所有事情,并且很可能会在Java序列化方面遇到麻烦,那么我邀请您查看Akka反模式概述 。 可能不会使您心情舒畅,但是您可能会发现一两个有用的东西。

这篇文章最初发表在曼努埃尔·伯恩哈特(Manuel Bernhardt)的博客上


翻译自: https://jaxenter.com/akka-java-serialization-147078.html

java akka

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值