Merge pull request #25595 from akka/wip-25336-orset-actorref-patriknw
Revert Support for rolling upgrade of ORSet[ActorRef], #25336
This commit is contained in:
commit
6464dea52b
5 changed files with 95 additions and 61 deletions
|
|
@ -1,4 +1,10 @@
|
||||||
# #25543 allow BigInt increment and decrements in PNCounter
|
# #25543 allow BigInt increment and decrements in PNCounter
|
||||||
ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.cluster.ddata.PNCounter.increment")
|
ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.cluster.ddata.PNCounter.increment")
|
||||||
ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.cluster.ddata.PNCounter.decrement")
|
ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.cluster.ddata.PNCounter.decrement")
|
||||||
ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.cluster.ddata.PNCounter.change")
|
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")
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import java.io.NotSerializableException
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage
|
import akka.cluster.ddata.protobuf.msg.ReplicatorMessages.OtherMessage
|
||||||
import akka.serialization.Serialization
|
import akka.serialization.Serialization
|
||||||
import akka.util.Helpers.toRootLowerCase
|
|
||||||
|
|
||||||
private object ReplicatedDataSerializer {
|
private object ReplicatedDataSerializer {
|
||||||
/*
|
/*
|
||||||
|
|
@ -168,16 +167,6 @@ private object ReplicatedDataSerializer {
|
||||||
override def getValue(entry: rd.ORMapDeltaGroup.MapEntry): dm.OtherMessage = entry.getValue
|
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._
|
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 DeletedDataManifest = "A"
|
||||||
private val GSetManifest = "B"
|
private val GSetManifest = "B"
|
||||||
private val GSetKeyManifest = "b"
|
private val GSetKeyManifest = "b"
|
||||||
|
|
@ -350,20 +325,11 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem)
|
||||||
val otherElements = new ArrayList[dm.OtherMessage]
|
val otherElements = new ArrayList[dm.OtherMessage]
|
||||||
val actorRefElements = new ArrayList[String]
|
val actorRefElements = new ArrayList[String]
|
||||||
gset.elements.foreach {
|
gset.elements.foreach {
|
||||||
case s: String ⇒ stringElements.add(s)
|
case s: String ⇒ stringElements.add(s)
|
||||||
case i: Int ⇒ intElements.add(i)
|
case i: Int ⇒ intElements.add(i)
|
||||||
case l: Long ⇒ longElements.add(l)
|
case l: Long ⇒ longElements.add(l)
|
||||||
case ref: ActorRef ⇒
|
case ref: ActorRef ⇒ actorRefElements.add(Serialization.serializedActorPath(ref))
|
||||||
actorRefFormat match {
|
case other ⇒ otherElements.add(otherMessageToProto(other))
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
if (!stringElements.isEmpty) {
|
if (!stringElements.isEmpty) {
|
||||||
Collections.sort(stringElements)
|
Collections.sort(stringElements)
|
||||||
|
|
@ -415,26 +381,10 @@ class ReplicatedDataSerializer(val system: ExtendedActorSystem)
|
||||||
var otherElementsMap = Map.empty[dm.OtherMessage, Any]
|
var otherElementsMap = Map.empty[dm.OtherMessage, Any]
|
||||||
val actorRefElements = new ArrayList[ActorRef]
|
val actorRefElements = new ArrayList[ActorRef]
|
||||||
orset.elementsMap.keysIterator.foreach {
|
orset.elementsMap.keysIterator.foreach {
|
||||||
case s: String ⇒ stringElements.add(s)
|
case s: String ⇒ stringElements.add(s)
|
||||||
case i: Int ⇒ intElements.add(i)
|
case i: Int ⇒ intElements.add(i)
|
||||||
case l: Long ⇒ longElements.add(l)
|
case l: Long ⇒ longElements.add(l)
|
||||||
case ref: ActorRef ⇒
|
case ref: ActorRef ⇒ actorRefElements.add(ref)
|
||||||
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 other ⇒
|
case other ⇒
|
||||||
val enclosedMsg = otherMessageToProto(other)
|
val enclosedMsg = otherMessageToProto(other)
|
||||||
otherElements.add(enclosedMsg)
|
otherElements.add(enclosedMsg)
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@
|
||||||
@@@ index
|
@@@ index
|
||||||
|
|
||||||
* [migration-guides](migration-guides.md)
|
* [migration-guides](migration-guides.md)
|
||||||
|
* [rolling-update](rolling-update.md)
|
||||||
* [issue-tracking](issue-tracking.md)
|
* [issue-tracking](issue-tracking.md)
|
||||||
* [licenses](licenses.md)
|
* [licenses](licenses.md)
|
||||||
* [links](links.md)
|
* [links](links.md)
|
||||||
|
|
||||||
@@@
|
@@@
|
||||||
|
|
|
||||||
|
|
@ -425,6 +425,8 @@ and here is a summary of things to consider.
|
||||||
* [akka.cluster.sharding.state-store-mode](#mig25-sharding-store)
|
* [akka.cluster.sharding.state-store-mode](#mig25-sharding-store)
|
||||||
* [akka.remote.netty.ssl.require-mutual-authentication](#mig25-mutual)
|
* [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
|
#### 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
|
Starting with 2.5.4, cluster routing supports delivering messages to routees tagged with all specified roles
|
||||||
|
|
|
||||||
75
akka-docs/src/main/paradox/project/rolling-update.md
Normal file
75
akka-docs/src/main/paradox/project/rolling-update.md
Normal file
|
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue