From 61e7365678d57c5f43effc5694ad61106d36c60c Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Tue, 11 Sep 2018 15:01:14 +0200 Subject: [PATCH 1/2] Revert Support for rolling upgrade of ORSet[ActorRef], #25336 This reverts commit b72312d428223156c10130e19f921e8ae5f336b6. --- .../mima-filters/2.5.16.backwards.excludes | 8 ++- .../protobuf/ReplicatedDataSerializer.scala | 68 +++---------------- 2 files changed, 16 insertions(+), 60 deletions(-) diff --git a/akka-distributed-data/src/main/mima-filters/2.5.16.backwards.excludes b/akka-distributed-data/src/main/mima-filters/2.5.16.backwards.excludes index 5d12fcc3e3..5e4898aa7f 100644 --- a/akka-distributed-data/src/main/mima-filters/2.5.16.backwards.excludes +++ b/akka-distributed-data/src/main/mima-filters/2.5.16.backwards.excludes @@ -1,4 +1,10 @@ # #25543 allow BigInt increment and decrements in PNCounter ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.cluster.ddata.PNCounter.increment") ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.cluster.ddata.PNCounter.decrement") -ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.cluster.ddata.PNCounter.change") \ No newline at end of file +ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.cluster.ddata.PNCounter.change") + +# #25336 Revert Support for rolling upgrade of ORSet[ActorRef] +ProblemFilters.exclude[MissingClassProblem]("akka.cluster.ddata.protobuf.ReplicatedDataSerializer$BothOldAndNewActorRefFormat$") +ProblemFilters.exclude[MissingClassProblem]("akka.cluster.ddata.protobuf.ReplicatedDataSerializer$NewActorRefFormat$") +ProblemFilters.exclude[MissingClassProblem]("akka.cluster.ddata.protobuf.ReplicatedDataSerializer$OldActorRefFormat$") +ProblemFilters.exclude[MissingClassProblem]("akka.cluster.ddata.protobuf.ReplicatedDataSerializer$ActorRefFormat") diff --git a/akka-distributed-data/src/main/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializer.scala b/akka-distributed-data/src/main/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializer.scala index cb31928f96..56b27344ea 100644 --- a/akka-distributed-data/src/main/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializer.scala +++ b/akka-distributed-data/src/main/scala/akka/cluster/ddata/protobuf/ReplicatedDataSerializer.scala @@ -28,7 +28,6 @@ import java.io.NotSerializableException import akka.actor.ActorRef import akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage import akka.serialization.Serialization -import akka.util.Helpers.toRootLowerCase private object ReplicatedDataSerializer { /* @@ -168,16 +167,6 @@ private object ReplicatedDataSerializer { override def getValue(entry: rd.ORMapDeltaGroup.MapEntry): dm.OtherMessage = entry.getValue } - // Optimized serializer for ORSet[ActorRef] was added in 2.5.14. - // To support rolling upgrades from Akka 2.5.13 to 2.5.14 and then to 2.5.15 those elements - // are by default sent as both old and new elements in 2.5.14. - // The old is used by 2.5.13 receivers. The new is used by 2.5.14 and 2.5.15 receivers. - // FIXME Remove this in 2.5.15 - private sealed trait ActorRefFormat - private case object OldActorRefFormat extends ActorRefFormat - private case object BothOldAndNewActorRefFormat extends ActorRefFormat - private case object NewActorRefFormat extends ActorRefFormat - } /** @@ -188,20 +177,6 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) import ReplicatedDataSerializer._ - private val actorRefFormat: ActorRefFormat = { - val conf = system.settings.config - val confKey = "akka.cluster.distributed-data.actor-ref-format" - // this config is not in reference.conf because it's only temporary for the 2.5.14 release - if (conf.hasPath(confKey)) { - toRootLowerCase(conf.getString(confKey)) match { - case "old" ⇒ OldActorRefFormat - case "both" ⇒ BothOldAndNewActorRefFormat - case "new" ⇒ NewActorRefFormat - } - } else - BothOldAndNewActorRefFormat - } - private val DeletedDataManifest = "A" private val GSetManifest = "B" private val GSetKeyManifest = "b" @@ -350,20 +325,11 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) val otherElements = new ArrayList[dm.OtherMessage] val actorRefElements = new ArrayList[String] gset.elements.foreach { - case s: String ⇒ stringElements.add(s) - case i: Int ⇒ intElements.add(i) - case l: Long ⇒ longElements.add(l) - case ref: ActorRef ⇒ - actorRefFormat match { - case BothOldAndNewActorRefFormat ⇒ - actorRefElements.add(Serialization.serializedActorPath(ref)) - otherElements.add(otherMessageToProto(ref)) - case OldActorRefFormat ⇒ - otherElements.add(otherMessageToProto(ref)) - case NewActorRefFormat ⇒ - actorRefElements.add(Serialization.serializedActorPath(ref)) - } - case other ⇒ otherElements.add(otherMessageToProto(other)) + case s: String ⇒ stringElements.add(s) + case i: Int ⇒ intElements.add(i) + case l: Long ⇒ longElements.add(l) + case ref: ActorRef ⇒ actorRefElements.add(Serialization.serializedActorPath(ref)) + case other ⇒ otherElements.add(otherMessageToProto(other)) } if (!stringElements.isEmpty) { Collections.sort(stringElements) @@ -415,26 +381,10 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem) var otherElementsMap = Map.empty[dm.OtherMessage, Any] val actorRefElements = new ArrayList[ActorRef] orset.elementsMap.keysIterator.foreach { - case s: String ⇒ stringElements.add(s) - case i: Int ⇒ intElements.add(i) - case l: Long ⇒ longElements.add(l) - case ref: ActorRef ⇒ - actorRefFormat match { - case BothOldAndNewActorRefFormat ⇒ - actorRefElements.add(ref) - val enclosedMsg = otherMessageToProto(ref) - otherElements.add(enclosedMsg) - // need the mapping back to the `other` when adding dots - otherElementsMap = otherElementsMap.updated(enclosedMsg, ref) - case OldActorRefFormat ⇒ - otherElements.add(otherMessageToProto(ref)) - val enclosedMsg = otherMessageToProto(ref) - otherElements.add(enclosedMsg) - // need the mapping back to the `other` when adding dots - otherElementsMap = otherElementsMap.updated(enclosedMsg, ref) - case NewActorRefFormat ⇒ - actorRefElements.add(ref) - } + case s: String ⇒ stringElements.add(s) + case i: Int ⇒ intElements.add(i) + case l: Long ⇒ longElements.add(l) + case ref: ActorRef ⇒ actorRefElements.add(ref) case other ⇒ val enclosedMsg = otherMessageToProto(other) otherElements.add(enclosedMsg) From c9b7dfa6071967e54d628bf63b93726fef90afcd Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Tue, 18 Sep 2018 12:56:03 +0200 Subject: [PATCH 2/2] page about rolling updates, and change log --- akka-docs/src/main/paradox/project/index.md | 3 +- .../project/migration-guide-2.4.x-2.5.x.md | 2 + .../main/paradox/project/rolling-update.md | 75 +++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 akka-docs/src/main/paradox/project/rolling-update.md diff --git a/akka-docs/src/main/paradox/project/index.md b/akka-docs/src/main/paradox/project/index.md index fe38661825..8b2e56df4b 100644 --- a/akka-docs/src/main/paradox/project/index.md +++ b/akka-docs/src/main/paradox/project/index.md @@ -5,8 +5,9 @@ @@@ index * [migration-guides](migration-guides.md) +* [rolling-update](rolling-update.md) * [issue-tracking](issue-tracking.md) * [licenses](licenses.md) * [links](links.md) -@@@ \ No newline at end of file +@@@ diff --git a/akka-docs/src/main/paradox/project/migration-guide-2.4.x-2.5.x.md b/akka-docs/src/main/paradox/project/migration-guide-2.4.x-2.5.x.md index edc084eb67..8487d97db5 100644 --- a/akka-docs/src/main/paradox/project/migration-guide-2.4.x-2.5.x.md +++ b/akka-docs/src/main/paradox/project/migration-guide-2.4.x-2.5.x.md @@ -425,6 +425,8 @@ and here is a summary of things to consider. * [akka.cluster.sharding.state-store-mode](#mig25-sharding-store) * [akka.remote.netty.ssl.require-mutual-authentication](#mig25-mutual) +See also the @ref:[rolling update guide](rolling-update.md) for specifics about later patch releases. + #### Limit lookup of routees to nodes tagged with multiple roles Starting with 2.5.4, cluster routing supports delivering messages to routees tagged with all specified roles diff --git a/akka-docs/src/main/paradox/project/rolling-update.md b/akka-docs/src/main/paradox/project/rolling-update.md new file mode 100644 index 0000000000..3284f8087f --- /dev/null +++ b/akka-docs/src/main/paradox/project/rolling-update.md @@ -0,0 +1,75 @@ +# Rolling Updates + +## Introduction + +A rolling update is the process of replacing one version of the system with another without downtime. +The changes can be new code, changed dependencies such as new Akka version, or modified configuration. +Rolling updates are typically used for a stateful Akka Cluster where you can't run two separate clusters in +parallel during the update as in blue green deployments. + +There are two parts of Akka that need careful consideration when performing an rolling update. + +1. Compatibility of remote message protocols. Old nodes may send messages to new nodes and vice versa. +1. Serialization format of persisted events and snapshots. New nodes must be able to read old data, and + during the update old nodes must be able to read data stored by new nodes. + +There are many more application specific aspects. It's important to have a strategy for serialization +format that can be evolved and you can find advice in +@ref:[Persistence - Schema Evolution](../persistence-schema-evolution.md), which also applies to +remote messages when deploying with rolling updates. + +Akka supports rolling updates between two consecutive patch versions unless an exception is +mentioned on this page. For example updating Akka version from 2.5.15 to 2.5.16. Many times +it is also possible to skip several versions and exceptions to that are also described here. +For example it's possible to update from 2.5.14 to 2.5.16 without intermediate 2.5.15. + +It's not supported to have a cluster with more than two different versions. Roll out the first +update completely before starting next update. + +## Shutdown order + +It's best to keep the node that has been running the longest until last. That is because +Cluster Singletons (including Cluster Sharding coordinators) are running on the oldest nodes. It's more +efficient to avoid moving the singletons more than necessary since those typically have to recover +their state and it might introduce unnecessary delays in for example access to new sharded actors. + +## Change log + +### 2.5.0 Several changes in minor release + +See @ref:[migration guide](migration-guide-2.4.x-2.5.x.md#rolling-update) when updating from 2.4.x to 2.5.x. + +### 2.5.10 Joining regression + +Issue: [#24622](https://github.com/akka/akka/issues/24622) + +Incompatible change was introduced in 2.5.10 and fixed in 2.5.11. + +This means that you can't do a rolling update from 2.5.9 to 2.5.10 and must instead do update from 2.5.9 to 2.5.11. + +### 2.5.10 Joining old versions + +Issue: [#25491](https://github.com/akka/akka/issues/25491) + +Incompatibility was introduced in in 2.5.10 and fixed in 2.5.15. + +That means that you should do rolling update from 2.5.9 directly to 2.5.15 if you need to be able to +join 2.5.9 nodes during the update phase. + +### 2.5.14 Distributed Data serializer for `ORSet[ActorRef]` + +Issue: [#23703](https://github.com/akka/akka/issues/23703) + +Intentional change was done in 2.5.14. + +This change required a two phase update where the data was duplicated to be compatible with both old and new nodes. + +* 2.5.13 - old format, before the change. Can communicate with intermediate format and with old format. +* 2.5.14, 2.5.15, 2.5.16 - intermediate format. Can communicate with old format and with new format. +* 2.5.17 - new format. Can communicate with intermediate format and with new format. + +This means that you can't update from 2.5.13 directly to 2.5.17. You must first update to one of the intermediate +versions 2.5.14, 2.5.15, or 2.5.16. + + +