Akka Coordination Lease implementation using Redis and Redlock algorithm.
The library is currently compatible with Akka 2.5.22 and 2.5.23. It is tested with 2 use cases built-in into Akka:
-
Cluster Singletons (implemented in
ClusterSingletonManagerSettings
) -
Cluster Sharding (implemented in
Shard
).
Add akka-coordination-redis
to sbt dependencies:
libraryDependencies ++= Seq(
"com.github.nstojiljkovic" %% "akka-coordination-redis" % "0.3.1"
)
Sample configuration using 5 Redis servers, with minimum amount of locks set to 4:
redisson-red-lock-lease {
# reference to the lease implementation class
lease-class = "com.nikolastojiljkovic.akka.coordination.lease.RedissonRedLockLease"
# if the node that acquired the leases crashes, how long should the lease be held before another owner can get it
heartbeat-timeout = 120s
# interval for communicating with the third party to confirm the lease is still held
heartbeat-interval = 12s
# interval to time out after acquire and release calls or document
lease-operation-timeout = 5s
# minimum number of (single) locks required, defaults to N / 2 + 1 if not defined
min-locks-amount = 4
# custom dispatcher to use, defaults to actor system default dispatcher if not specified
dispatcher = custom-dispatcher
# common configuration option, not used directly by RedissonRedLockLease
default-server {
singleServerConfig {
address = "redis://10.10.11.40:6379"
connectionMinimumIdleSize = 8
connectionPoolSize = 16
}
threads = 64
nettyThreads = 64
transportMode = NIO
transportMode = NIO
}
# list of servers
servers = [
${redisson-red-lock-lease.default-server} {singleServerConfig.address = "redis://10.10.11.40:6379"},
${redisson-red-lock-lease.default-server} {singleServerConfig.address = "redis://10.10.11.41:6379"},
${redisson-red-lock-lease.default-server} {singleServerConfig.address = "redis://10.10.11.42:6379"},
${redisson-red-lock-lease.default-server} {singleServerConfig.address = "redis://10.10.11.43:6379"},
${redisson-red-lock-lease.default-server} {singleServerConfig.address = "redis://10.10.11.44:6379"}
]
}
If min-locks-amount
is not configured it will be calculated as N / 2 + 1
where N
is the number of configured Redis servers.
The default-server
from the above sample is just used to copy the common configuration to each of the configured servers
.
Each of the servers in the servers
array accepts any of the configuration options as per
JSON/YAML based Redisson configuration. You should also probably take special
care when configuring the Redisson thread and connection pools.
There's also an option to specify custom execution context used by RedissonRedLockLease
(which is completely separate
from the Redisson thread pool) using the dispatcher
configuration option. It should point to the name of a custom Akka
dispatcher, configured as per Akka official documentation.
The lease-class
, heartbeat-timeout
, heartbeat-interval
and lease-operation-timeout
configuration options all come from
Akka Coordination Lease API.
Redisson is used as a Redis client library. However, Redisson's RedLock implementation does not map 1:1 to Akka Lease API. Notable changes and tweaks are listed bellow:
-
RedissonRedLock is Redis based distributed reentrant Lock object for Java and implements
java.util.concurrent.locks.Lock
interface. It means that only lock owner thread can unlock it otherwiseIllegalMonitorStateException
would be thrown. On the other hand, Akka Coordination Lease API has configurable owner (without locking the leases to threads) soakka-coordination-redis
implementation uses custom internalRedissonLockWithCustomOwnerAndFixedLeaseTime
. It does not comply with the Java lock specification and is therefore marked private. That also means that you should, as per Akka Coordination specification, take special care when picking up a lease name that will be unique for your use case. -
RedissonRedLock has bunch of functions which throw
UnsupportedOperationException
(and which would otherwise be useful for implementing Akka Coordination Lease). Theakka-coordination-redis
library has custom logic implemented inRedissonRedLockLease
to overcome the missing functionality from Redisson RedLock implementation.-
Akka allows to specify both
heartbeat-timeout
andheartbeat-interval
. Redisson allows to specifylockWatchdogTimeout
(which maps to Akka'sheartbeat-timeout
for locks withleastTime
set to -1), but theheartbeat-interval
is then locked to 1/3 oflockWatchdogTimeout
(hardcoded in a private method inRedissonLock
). In order to fully allow Akka'sheartbeat-interval
setting,RedissonRedLockLease
does not use Redisson's watchdog, but instead renews the lease itself. -
It is assumed that every server configured for each of the (single) locks constituting a distributed RedLock will be actually a single Redis server (though that is not a requirement).
RedissonRedLockLease
listens for disconnects from each of the configured servers and opts to mark lease as lost on any server disconnect. So if you have anything besidessingleServerConfig
as a single lock server (for example Redis cluster), note that acquired leases will be marked as lost if any of the cluster servers goes down.
-
Please feel free to create a new pull request for each change or bug fix. Make sure that all of the changes are covered using tests. You can run the full suite of tests using sbt:
> testOnly com.nikolastojiljkovic.akka.coordination.lease.*
See the LICENSE file for details.