关于akka:序列化

3次阅读

共计 4401 个字符,预计需要花费 12 分钟才能阅读完成。

<h1> 序列化 </h1>

# 依赖
要应用序列化,必须在我的项目中增加以下依赖项:
# 介绍
Akka actor 互相发送的音讯是 JVM 对象。actor 在同一个 JVM 上传递音讯很简略。通过援用传递实现。然而,音讯逾越 JVM,必须通过某种模式的序列化,能力达到在不同主机上运行的 actor。(即对象转换为字节数组,或从字节数组复原音讯)。Akka 中的序列化机制容许您编写自定义序列化程序,并定义用哪个序列化程序。在许多状况下,应用 Jackson 进行序列化是一个不错的抉择,如果您没有其余抉择,咱们倡议应用。如果您想更好地管制音讯的架构演变,则 Google Protocol Buffers 是很好的抉择,然而它须要更多的工作来开发和保护序列化示意模式与畛域示意模式的映射。Akka 自身应用 Protocol Buffers 来序列化内部消息(例如集群 gossip 音讯)。# 用法
## 配置
为了使 Akka 晓得要应用哪个序列化程序,您须要编辑配置:“akka.actor.serializers”,将名称绑定到要应用的 akka​​.serialization.Serializer 的实现中,如下所示:

在将名称绑定到不同的序列化实现之后,须要指定哪个类应用哪个 Serializer,这在“akka.actor.serialization-bindings”局部中实现:
您只须要指定音讯的接口名称或形象基类即可。在不置可否的状况下,即音讯实现了几个配置的类,将应用最具体的配置类,即所有其余候选者的超类。如果无奈满足此条件,例如已配置用于序列化的两个标记接口都实用,并且都不是另一个的子类型,将收回正告。> 留神
 如果将 Scala 用于音讯协定,并且音讯蕴含在 Scala object 中,则为了援用这些音讯,您将须要应用规范 Java 类名称。对于蕴含在名为 Wrapper 的 Scala object 中的名为 Message 的音讯,您须要将其援用为 Wrapper$Message 而不是 Wrapper.Message。Akka 默认为几种原始类型和 protobuf com.google.protobuf.GeneratedMessage(protobuf2)和 com.google.protobuf.GeneratedMessageV3(protobuf3)提供序列化程序(后者仅取决于 akka-remote 模块),因而如果您将原始的 protobuf 音讯作为 actor 音讯发送,则无需为此增加配置。## 程式化
 如果要应用 Akka 序列化, 以编程形式进行序列化 / 反序列化,请参见以下示例:

清单是一种类型提醒,因而同一序列化程序可用于不同的类。请留神,从字节反序列化时,须要清单和 serializer 的标识符。重要的是,以这种形式应用序列化程序标识符来反对滚动更新,其中类的 serialization-bindings 可能已从一个序列化程序更改为另一个序列化程序。因而,由字节,序列化 ID 和清单组成的三个局部应始终一起传输或存储,以便能够应用不同的序列化绑定配置对它们进行反序列化。SerializationExtension 是经典扩大,但能够与 akka.actor.typed.ActorSystem 一起应用,如下所示:

# 个性化
此页面上的第一个代码段蕴含一个配置文件,该配置文件援用了自定义序列化程序 docs.serialization.MyOwnSerializer。咱们将如何创立这样的自定义序列化程序?## 创立新的序列化器
自定义序列化程序必须继承 akka.serialization.JSerializer,并且能够如下定义:

标识符必须是惟一的。抉择要用于反序列化的序列化器时,将应用该标识符。如果您意外地配置了多个具备雷同标识符的序列化程序,这些序列化程序将被检测到并阻止 ActorSystem 启动。它能够是硬编码的值,因为它必须放弃雷同的值以反对滚动更新。清单是一种类型提醒,因而同一序列化程序可用于不同的类。fromBinaryJava 中的 manifest 参数是被序列化的对象的类。在 fromBinary 中,您能够在类上进行匹配,并将字节反序列化为不同的对象。而后,您只须要填写空白,将其绑定到配置中的名称,而后列出应应用其反序列化的类。启动 ActorSystem 时,serializers 将由 SerializationExtension 初始化,因而,序列化程序自身不能从其构造函数拜访 SerializationExtension。相同,它应该提早拜访 SerializationExtension。## 字符串清单的序列化器
下面阐明的序列化程序反对基于类的清单(类型提醒)。对于须要随工夫变动的数据进行序列化,倡议应用 SerializerWithStringManifest 而不是 Serializer,因为清单 (类型提醒) 是 String 而不是 Class。这意味着能够挪动 / 删除该类,并且 serializer 仍能够通过匹配 String 来反序列化旧数据。这对于持久性特地有用。清单字符串还能够编码一个版本号,该版本号可用于 fromBinary 中以不同形式反序列化, 将旧数据迁徙到新的畛域对象。如果数据最后是应用 Serializer 进行序列化的,并且在零碎的更高版本中更改为 SerializerWithStringManifest,则清单字符串将是残缺的类名(如果您应用 includeManifest = true),否则它将是空字符串。这是 SerializerWithStringManifest 的样子:

您还必须将其绑定到配置中的名称,而后列出应由其序列化的类。如果清单未知,倡议将 IllegalArgumentException 或 java.io.NotSerializableException 放入 fromBinary 中。这样就能够引入新的音讯类型,并将其发送到不晓得它们的节点。在执行滚动降级时,即运行具备混合版本的集群一段时间后,通常须要这样做。这些异样在经典近程解决层中被视为临时问题。该问题将被记录,并且音讯被抛弃。其余异样将断开 TCP 连贯,因为它可能表明传输的字节损坏。Artery TCP 将所有反序列化异样解决为暂时性问题。## 序列化 ActorRefs
actor 援用通常蕴含在音讯中。当与 Jackson 一起应用序列化时,所有 ActorRef 都能够序列化,然而如果您正在编写本人的序列化器,则可能想晓得如何正确地序列化和反序列化它们。要应用字符串对 actor 进行序列化、反序列化,能够应用 ActorRefResolver。例如,以下是 Ping 和 Pong 音讯序列化:

经典 ActorRef 的序列化在 Classic Serialization 进行了形容。经典和 Typed actor 援用具备雷同的序列化格局,因而能够调换。## actor 的深度序列化
倡议应用 Akka Persistence,对外部 actor 状态进行深度序列化。# Akka 音讯的序列化
Akka 正在应用 Protobuf 3 对 Akka 定义的音讯进行序列化。这种依赖关系隐含在 akka-protobuf-v3 中,以便应用程序能够应用 Protobuf 的另一个版本。应用程序应应用规范的 Protobuf 依赖关系,而不是 akka-protobuf-v3。# Java 序列化
家喻户晓,Java 序列化速度很慢,并且容易受到各种类型的攻打 - 毕竟,它素来都不是为高吞吐量消息传递而设计的。可能有人认为网络带宽和提早会限度近程消息传递的性能,然而序列化是一个更为典型的瓶颈。> 留神
默认状况下,应用 Java 序列化的 Akka 序列化是禁用的,并且 Akka 自身不对其外部任何音讯应用 Java 序列化。不倡议在生产中启用 Java 序列化。生产中禁用的 Java 序列化程序收回的日志音讯, 应视为序列化程序阻止的潜在攻打,因为它们可能示意内部操作试图发送旨在应用 Java 序列化作为攻打向量的歹意音讯。尝试应用 SECURITY 标记记录。然而,对于晚期原型制作来说,应用起来十分不便。因而,为了与依赖 Java 序列化的旧零碎兼容,能够应用以下配置启用它:

当应用 Java 序列化时,Akka 仍会记录正告,增加以下内容敞开正告:

## Java 序列化兼容性
当应用 Java 序列化时,混合次要的 Scala 版本并不平安,因为 Scala 无奈保障兼容性,这可能会导致十分令人诧异的谬误。# 滚动降级
序列化的近程音讯 (或长久事件) 由序列化器 ID,清单和二进制有效载荷组成。反序列化时,仅查看 serializer-id 以抉择要用于 fromBinary 的序列化器。音讯类 (绑定) 不用于反序列化。该清单仅在 Serializer 中用于决定如何反序列化无效负载,因而一个 Serializer 能够解决许多类。这意味着能够通过执行两个滚动降级步骤来切换到新的序列化程序来更改音讯的序列化。1. 增加 Serializer 类,并在 akka.actor.serializers 配置中定义它,而不在 akka.actor.serialization-bindings 中定义它。为此更改执行滚动降级。这意味着序列化程序类存在于所有节点上并已注册,但仍未用于序列化任何音讯。这很重要,因为在滚动降级过程中,旧节点依然不理解新的序列化程序,因而无奈反序列化具备该格局的音讯。2. 第二个更改是用 akka.actor.serialization-bindings 配置中定义那些序列化程序,对某些类注册序列化程序。为此更改执行滚动降级。这意味着新节点在发送音讯时将应用新的序列化器,而旧节点将可能反序列化新格局。发送音讯时,旧节点将持续应用旧序列化程序,而新节点将可能反序列化旧格局。作为可选的第三步,如果旧的序列化程序未用于持久性事件,则能够将其齐全删除。依然必须能够反序列化旧序列化程序存储的事件。# 内部 Akka 序列化器
- Kryo serializer for Akka

- Twitter Chill Scala extensions for Kryo

## 验证
通常,在本地 actor(即同一 JVM)之间发送的音讯不会进行序列化。对于测试,有时可能心愿对所有音讯 (近程音讯和本地音讯) 强制进行序列化。如果要执行此操作以验证音讯可序列化,则能够启用以下配置选项:

通过扩大标记接口 akka.actor.NoSerializationVerificationNeeded 或在配置 akka.actor.no-serialization-verification-needed-class-prefix 中定义类名称前缀,能够将某些音讯从验证中排除。如果要验证 Props 是否可序列化,能够启用以下配置选项:
> 正告
咱们倡议仅在运行测试时关上这些配置选项。在生产中关上这些选项是没有意义的,因为这会对本地消息传递的性能产生负面影响,而不会带来任何收益。
正文完
 0