<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将所有反序列化异样解决为暂时性问题。## 序列化ActorRefsactor援用通常蕴含在音讯中。当与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是否可序列化,能够启用以下配置选项:
>正告咱们倡议仅在运行测试时关上这些配置选项。 在生产中关上这些选项是没有意义的,因为这会对本地消息传递的性能产生负面影响,而不会带来任何收益。