SlideShare a Scribd company logo
Atomicity in RedisAtomicity in Redis
Thomas Hunter IIThomas Hunter II
RoadmapRoadmap
1.
2.
3.
4.
The Basics
Pipelining
Transactions
Lua
Scripting
The BasicsThe Basics
What is Atomicity?What is Atomicity?
Series of database operations
Guaranteed to all run or none run
Prevents operations from running partially
The effects of all operations are immediately visible
I.e. another client cannot see partial state
Also referred to as a Transaction
How do these tools work?How do these tools work?
Redis is Mostly Single-Threaded
Except for things like Background IO
Node.js is Mostly Single-Threaded
Except for IO and Node v10 Worker Threads
Single Client & Server is simple
Things get complicated with multiple clients
EveryEvery SingleSingle Command is AtomicCommand is Atomic
MultipleMultiple Commands aren't AtomicCommands aren't Atomic
Scenario: Two clients want to increment counter
MultipleMultiple Commands aren't AtomicCommands aren't Atomic
Client #1 reads value of counter
MultipleMultiple Commands aren't AtomicCommands aren't Atomic
Client #2 reads value of counter
MultipleMultiple Commands aren't AtomicCommands aren't Atomic
Client #1 sets value of counter to 1
MultipleMultiple Commands aren't AtomicCommands aren't Atomic
Client #2 sets value of counter to 1
Atomic, Multi-Operation CommandsAtomic, Multi-Operation Commands
Common use-cases have single-command variants
INCR key # GET key ; ~value++ ; SET key ~value
SETNX key value # !EXISTS key ; SET key value
LPUSHX key value # EXISTS key ; LPUSH key value
RPOPLPUSH src dest # RPOP src ; LPUSH dest ~value
GETSET key value # GET key ; SET key value
INCRINCR is an Atomic Incrementis an Atomic Increment
Scenario: Two clients want to increment counter
INCRINCR is an Atomic Incrementis an Atomic Increment
Client #1 atomically increments value of counter
INCRINCR is an Atomic Incrementis an Atomic Increment
Client #2 atomically increments value of counter
PipeliningPipelining
PipeliningPipelining
Ensures commands are run in order per-connection
Sends a batch of commands separated by newlines
Commands are sent in the same message
The Node.js redis module usually does this anyway
Pipelining: Example CodePipelining: Example Code
redis.batch()
.zrangebyscore('jobs', 0, now) // get jobs
.zremrangebyscore('jobs', 0, now) // delete jobs
.exec((error, data) => {
let jobList = data[0];
console.log('jobs', jobList); // perform work
});
ZRANGEBYSCORE jobs 0 1000rnZREMRANGEBYSCORE jobs 0 1000
Pipelining: Not Atomic, SorryPipelining: Not Atomic, Sorry
It looks atomic
Prevents command interleaving on one connection
A subset of commands can fail
Other client pipelines can interleave commands
Pipelining: Not Atomic, SorryPipelining: Not Atomic, Sorry
const redis = require('redis').createClient();
// run 10 instances of this process in parallel
let keys = [];
for (let i = 0; i < 100000; i++) {
keys.push(i);
}
shuffle(keys);
let pipeline = redis.batch();
for (let key of keys) {
pipeline = pipeline.hsetnx('pipeline', `k${key}`, process.pid);
}
pipeline.exec(() => redis.quit());
Pipelining: Not Atomic, SorryPipelining: Not Atomic, Sorry
> HGETALL pipeline
...
k46468: 25198
k67664: 25197
k62167: 25197
k5933: 25202
k19146: 25202
k202: 25196
k47418: 25198
k88650: 25202
...
Pipelining: What's it for?Pipelining: What's it for?
Reducing network latency
Send several commands in one message
Receive several responses in one message
echo "PINGrnPINGrnPINGrn" | nc localhost 6379
+PONG
+PONG
+PONG
TransactionsTransactions
MULTI: True AtomicityMULTI: True Atomicity
Atomic regardless of other clients / connections
Client sends MULTI , more commands, EXEC
Other clients can still run commands
Queued commands are run sequentially
Any failures and the entire transaction fails
MULTI: Example CodeMULTI: Example Code
redis.multi()
.zrangebyscore('jobs', 0, now) // get jobs
.zremrangebyscore('jobs', 0, now) // delete jobs
.exec((error, data) => {
let jobList = data[0];
console.log('jobs', jobList); // perform work
});
MULTI
ZRANGEBYSCORE jobs 0 1553099335332
ZREMRANGEBYSCORE jobs 0 1553099335332
EXEC
MULTI Drawback: No command chainingMULTI Drawback: No command chaining
Can't use command result as argument
E.g., cannot pop from list, assign to new key
Lua ScriptingLua Scripting
Lua: The Ultimate in AtomicityLua: The Ultimate in Atomicity
There's a simpler, less-efficient EVAL command
Send the entire script every time
Like sending a normal SQL query
Or use SCRIPT LOAD ahead of time
Then use EVALSHA to run code via resulting hash
Like executing a SQL Stored Procedure
Declare key names as arguments for sharding
Lua: Server-Side LogicLua: Server-Side Logic
Output of one command can be piped into another
Other processing can happen, too
Lua: Game Lobby Example CodeLua: Game Lobby Example Code
-- add-user.lua: add user to lobby, start game if 4 players
local lobby = KEYS[1] -- Set
local game = KEYS[2] -- Hash
local user_id = ARGV[1] -- String
redis.call('SADD', lobby, user_id)
if redis.call('SCARD', lobby) == 4 then
local members = table.concat(redis.call('SMEMBERS',lobby),",")
redis.call('DEL', lobby) -- empty lobby
local game_id = redis.sha1hex(members)
redis.call('HSET', game, game_id, members)
return {game_id, members}
end
return nil
Lua: Game Lobby Example CodeLua: Game Lobby Example Code
const redis = require('redis').createClient();
const rEval = require('util').promisify(redis.eval).bind(redis);
const script = require('fs').readFileSync('./add-user.lua');
const LOBBY = 'lobby-elo-1500', GAME = 'game-hash';
(async () => {
await rEval(script, 2, LOBBY, GAME, 'alice');
await rEval(script, 2, LOBBY, GAME, 'bob');
await rEval(script, 2, LOBBY, GAME, 'cindy');
const [gid,plyrs] = await rEval(script, 2, LOBBY, GAME,'tom');
console.log('GAME ID', gid, 'PLAYERS', plyrs.split(','));
})();
Lua: DrawbacksLua: Drawbacks
Another language to maintain
Simple language, easy syntax
Increases overhead on Redis server
An infinite loop could lock up server
Need to load scripts before using to be efficient
It's idempotent; load scripts when app starts
RecapRecap
Executing singular commands are atomic
Executing multiple commands are not atomic
Pipelining is not atomic, but it's fast
MULTI is atomic, but you can't chain results
Lua scripts are atomic and chainable
Intrinsic: Node.js Security PoliciesIntrinsic: Node.js Security Policies
const REDIS = 'redis://redishost:6379/1';
routes.allRoutes(policy => {
policy.redis.allowConnect(REDIS);
});
routes.get('/users/*', policy => {
policy.redis.allowCommandKey(REDIS, 'GET', 'user-*');
});
routes.post('/server/stats', policy => {
policy.redis.allowInfoSection(REDIS, 'memory');
});
FinFin
Follow me:
About Intrinsic:
This presentation:
@tlhunter
intrinsic.com
bit.ly/redis-atomicity
@tlhunter@tlhunter

More Related Content

PDF
Nestjs MasterClass Slides
PDF
Clean backends with NestJs
PDF
Clean coding-practices
PDF
Lets make a better react form
PDF
All about Zookeeper and ClickHouse Keeper.pdf
PDF
PPTX
Terraform on Azure
PPTX
Capabilities for Resources and Effects
Nestjs MasterClass Slides
Clean backends with NestJs
Clean coding-practices
Lets make a better react form
All about Zookeeper and ClickHouse Keeper.pdf
Terraform on Azure
Capabilities for Resources and Effects

What's hot (20)

PDF
Redis Lua Scripts
PPTX
Docker 101 - Nov 2016
PDF
Domain Driven Design
PPTX
Docker Networking Overview
KEY
Redis overview for Software Architecture Forum
PDF
TypeScript: coding JavaScript without the pain
PPTX
MongoDB - Aggregation Pipeline
PDF
PDF
Akka.NET 으로 만드는 온라인 게임 서버 (NDC2016)
PDF
Terraform -- Infrastructure as Code
PDF
Keycloak Single Sign-On
PDF
Intro to Terraform
PDF
왜 쿠버네티스는 systemd로 cgroup을 관리하려고 할까요
PPTX
Clean code slide
PDF
Monitoring Kubernetes with Prometheus
PDF
[KGC 2012]Boost.asio를 이용한 네트웍 프로그래밍
PDF
NodeJS for Beginner
PDF
Docker Introduction.pdf
PDF
Terraform
PDF
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Redis Lua Scripts
Docker 101 - Nov 2016
Domain Driven Design
Docker Networking Overview
Redis overview for Software Architecture Forum
TypeScript: coding JavaScript without the pain
MongoDB - Aggregation Pipeline
Akka.NET 으로 만드는 온라인 게임 서버 (NDC2016)
Terraform -- Infrastructure as Code
Keycloak Single Sign-On
Intro to Terraform
왜 쿠버네티스는 systemd로 cgroup을 관리하려고 할까요
Clean code slide
Monitoring Kubernetes with Prometheus
[KGC 2012]Boost.asio를 이용한 네트웍 프로그래밍
NodeJS for Beginner
Docker Introduction.pdf
Terraform
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Ad

Similar to Atomicity In Redis: Thomas Hunter (20)

PDF
Tuga IT 2017 - Redis
PDF
Redis is not just a cache, Andrew Lavers, ConFoo Montreal 2020
PDF
Introduction to Redis
PDF
Everything you always wanted to know about Redis but were afraid to ask
PPTX
Anatomy of a Redis Command by Madelyn Olson of Amazon Web Services - Redis Da...
PDF
RedisConf18 - Writing modular & encapsulated Redis code
PPTX
PDF
An Introduction to Redis for Developers.pdf
PPT
Redis And python at pycon_2011
PDF
Introduction to redis - version 2
PDF
Introduction to Redis - LA Hacker News
PPT
Python redis talk
PDF
A Brief Introduction to Redis
PPTX
Get more than a cache back! - ConFoo Montreal
PDF
Fun with Ruby and Redis
PDF
quickguide-einnovator-9-redis
KEY
Redis - N✮SQL Berlin
PDF
quickguide-einnovator-10-redis-admin
PDF
Redispresentation apac2012
PPT
Introduction to redis
Tuga IT 2017 - Redis
Redis is not just a cache, Andrew Lavers, ConFoo Montreal 2020
Introduction to Redis
Everything you always wanted to know about Redis but were afraid to ask
Anatomy of a Redis Command by Madelyn Olson of Amazon Web Services - Redis Da...
RedisConf18 - Writing modular & encapsulated Redis code
An Introduction to Redis for Developers.pdf
Redis And python at pycon_2011
Introduction to redis - version 2
Introduction to Redis - LA Hacker News
Python redis talk
A Brief Introduction to Redis
Get more than a cache back! - ConFoo Montreal
Fun with Ruby and Redis
quickguide-einnovator-9-redis
Redis - N✮SQL Berlin
quickguide-einnovator-10-redis-admin
Redispresentation apac2012
Introduction to redis
Ad

More from Redis Labs (20)

PPTX
Redis Day Bangalore 2020 - Session state caching with redis
PPTX
Protecting Your API with Redis by Jane Paek - Redis Day Seattle 2020
PPTX
The Happy Marriage of Redis and Protobuf by Scott Haines of Twilio - Redis Da...
PPTX
SQL, Redis and Kubernetes by Paul Stanton of Windocks - Redis Day Seattle 2020
PPTX
Rust and Redis - Solving Problems for Kubernetes by Ravi Jagannathan of VMwar...
PPTX
Redis for Data Science and Engineering by Dmitry Polyakovsky of Oracle
PPTX
Practical Use Cases for ACLs in Redis 6 by Jamie Scott - Redis Day Seattle 2020
PPTX
Moving Beyond Cache by Yiftach Shoolman Redis Labs - Redis Day Seattle 2020
PPTX
Leveraging Redis for System Monitoring by Adam McCormick of SBG - Redis Day S...
PPTX
JSON in Redis - When to use RedisJSON by Jay Won of Coupang - Redis Day Seatt...
PPTX
Highly Available Persistent Session Management Service by Mohamed Elmergawi o...
PPTX
Building a Multi-dimensional Analytics Engine with RedisGraph by Matthew Goos...
PPTX
RediSearch 1.6 by Pieter Cailliau - Redis Day Bangalore 2020
PPTX
RedisGraph 2.0 by Pieter Cailliau - Redis Day Bangalore 2020
PPTX
RedisTimeSeries 1.2 by Pieter Cailliau - Redis Day Bangalore 2020
PPTX
RedisAI 0.9 by Sherin Thomas of Tensorwerk - Redis Day Bangalore 2020
PPTX
Rate-Limiting 30 Million requests by Vijay Lakshminarayanan and Girish Koundi...
PDF
Three Pillars of Observability by Rajalakshmi Raji Srinivasan of Site24x7 Zoh...
PPTX
Solving Complex Scaling Problems by Prashant Kumar and Abhishek Jain of Myntr...
PPTX
Redis as a High Scale Swiss Army Knife by Rahul Dagar and Abhishek Gupta of G...
Redis Day Bangalore 2020 - Session state caching with redis
Protecting Your API with Redis by Jane Paek - Redis Day Seattle 2020
The Happy Marriage of Redis and Protobuf by Scott Haines of Twilio - Redis Da...
SQL, Redis and Kubernetes by Paul Stanton of Windocks - Redis Day Seattle 2020
Rust and Redis - Solving Problems for Kubernetes by Ravi Jagannathan of VMwar...
Redis for Data Science and Engineering by Dmitry Polyakovsky of Oracle
Practical Use Cases for ACLs in Redis 6 by Jamie Scott - Redis Day Seattle 2020
Moving Beyond Cache by Yiftach Shoolman Redis Labs - Redis Day Seattle 2020
Leveraging Redis for System Monitoring by Adam McCormick of SBG - Redis Day S...
JSON in Redis - When to use RedisJSON by Jay Won of Coupang - Redis Day Seatt...
Highly Available Persistent Session Management Service by Mohamed Elmergawi o...
Building a Multi-dimensional Analytics Engine with RedisGraph by Matthew Goos...
RediSearch 1.6 by Pieter Cailliau - Redis Day Bangalore 2020
RedisGraph 2.0 by Pieter Cailliau - Redis Day Bangalore 2020
RedisTimeSeries 1.2 by Pieter Cailliau - Redis Day Bangalore 2020
RedisAI 0.9 by Sherin Thomas of Tensorwerk - Redis Day Bangalore 2020
Rate-Limiting 30 Million requests by Vijay Lakshminarayanan and Girish Koundi...
Three Pillars of Observability by Rajalakshmi Raji Srinivasan of Site24x7 Zoh...
Solving Complex Scaling Problems by Prashant Kumar and Abhishek Jain of Myntr...
Redis as a High Scale Swiss Army Knife by Rahul Dagar and Abhishek Gupta of G...

Recently uploaded (20)

PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
KodekX | Application Modernization Development
PPTX
sap open course for s4hana steps from ECC to s4
PPT
Teaching material agriculture food technology
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
cuic standard and advanced reporting.pdf
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Encapsulation theory and applications.pdf
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PPTX
Big Data Technologies - Introduction.pptx
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Empathic Computing: Creating Shared Understanding
PPTX
Cloud computing and distributed systems.
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Per capita expenditure prediction using model stacking based on satellite ima...
KodekX | Application Modernization Development
sap open course for s4hana steps from ECC to s4
Teaching material agriculture food technology
Chapter 3 Spatial Domain Image Processing.pdf
The Rise and Fall of 3GPP – Time for a Sabbatical?
cuic standard and advanced reporting.pdf
Network Security Unit 5.pdf for BCA BBA.
Encapsulation theory and applications.pdf
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Unlocking AI with Model Context Protocol (MCP)
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Big Data Technologies - Introduction.pptx
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Empathic Computing: Creating Shared Understanding
Cloud computing and distributed systems.
“AI and Expert System Decision Support & Business Intelligence Systems”
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf

Atomicity In Redis: Thomas Hunter

  • 1. Atomicity in RedisAtomicity in Redis Thomas Hunter IIThomas Hunter II
  • 4. What is Atomicity?What is Atomicity? Series of database operations Guaranteed to all run or none run Prevents operations from running partially The effects of all operations are immediately visible I.e. another client cannot see partial state Also referred to as a Transaction
  • 5. How do these tools work?How do these tools work? Redis is Mostly Single-Threaded Except for things like Background IO Node.js is Mostly Single-Threaded Except for IO and Node v10 Worker Threads Single Client & Server is simple Things get complicated with multiple clients
  • 6. EveryEvery SingleSingle Command is AtomicCommand is Atomic
  • 7. MultipleMultiple Commands aren't AtomicCommands aren't Atomic Scenario: Two clients want to increment counter
  • 8. MultipleMultiple Commands aren't AtomicCommands aren't Atomic Client #1 reads value of counter
  • 9. MultipleMultiple Commands aren't AtomicCommands aren't Atomic Client #2 reads value of counter
  • 10. MultipleMultiple Commands aren't AtomicCommands aren't Atomic Client #1 sets value of counter to 1
  • 11. MultipleMultiple Commands aren't AtomicCommands aren't Atomic Client #2 sets value of counter to 1
  • 12. Atomic, Multi-Operation CommandsAtomic, Multi-Operation Commands Common use-cases have single-command variants INCR key # GET key ; ~value++ ; SET key ~value SETNX key value # !EXISTS key ; SET key value LPUSHX key value # EXISTS key ; LPUSH key value RPOPLPUSH src dest # RPOP src ; LPUSH dest ~value GETSET key value # GET key ; SET key value
  • 13. INCRINCR is an Atomic Incrementis an Atomic Increment Scenario: Two clients want to increment counter
  • 14. INCRINCR is an Atomic Incrementis an Atomic Increment Client #1 atomically increments value of counter
  • 15. INCRINCR is an Atomic Incrementis an Atomic Increment Client #2 atomically increments value of counter
  • 17. PipeliningPipelining Ensures commands are run in order per-connection Sends a batch of commands separated by newlines Commands are sent in the same message The Node.js redis module usually does this anyway
  • 18. Pipelining: Example CodePipelining: Example Code redis.batch() .zrangebyscore('jobs', 0, now) // get jobs .zremrangebyscore('jobs', 0, now) // delete jobs .exec((error, data) => { let jobList = data[0]; console.log('jobs', jobList); // perform work }); ZRANGEBYSCORE jobs 0 1000rnZREMRANGEBYSCORE jobs 0 1000
  • 19. Pipelining: Not Atomic, SorryPipelining: Not Atomic, Sorry It looks atomic Prevents command interleaving on one connection A subset of commands can fail Other client pipelines can interleave commands
  • 20. Pipelining: Not Atomic, SorryPipelining: Not Atomic, Sorry const redis = require('redis').createClient(); // run 10 instances of this process in parallel let keys = []; for (let i = 0; i < 100000; i++) { keys.push(i); } shuffle(keys); let pipeline = redis.batch(); for (let key of keys) { pipeline = pipeline.hsetnx('pipeline', `k${key}`, process.pid); } pipeline.exec(() => redis.quit());
  • 21. Pipelining: Not Atomic, SorryPipelining: Not Atomic, Sorry > HGETALL pipeline ... k46468: 25198 k67664: 25197 k62167: 25197 k5933: 25202 k19146: 25202 k202: 25196 k47418: 25198 k88650: 25202 ...
  • 22. Pipelining: What's it for?Pipelining: What's it for? Reducing network latency Send several commands in one message Receive several responses in one message echo "PINGrnPINGrnPINGrn" | nc localhost 6379 +PONG +PONG +PONG
  • 24. MULTI: True AtomicityMULTI: True Atomicity Atomic regardless of other clients / connections Client sends MULTI , more commands, EXEC Other clients can still run commands Queued commands are run sequentially Any failures and the entire transaction fails
  • 25. MULTI: Example CodeMULTI: Example Code redis.multi() .zrangebyscore('jobs', 0, now) // get jobs .zremrangebyscore('jobs', 0, now) // delete jobs .exec((error, data) => { let jobList = data[0]; console.log('jobs', jobList); // perform work }); MULTI ZRANGEBYSCORE jobs 0 1553099335332 ZREMRANGEBYSCORE jobs 0 1553099335332 EXEC
  • 26. MULTI Drawback: No command chainingMULTI Drawback: No command chaining Can't use command result as argument E.g., cannot pop from list, assign to new key
  • 28. Lua: The Ultimate in AtomicityLua: The Ultimate in Atomicity There's a simpler, less-efficient EVAL command Send the entire script every time Like sending a normal SQL query Or use SCRIPT LOAD ahead of time Then use EVALSHA to run code via resulting hash Like executing a SQL Stored Procedure Declare key names as arguments for sharding
  • 29. Lua: Server-Side LogicLua: Server-Side Logic Output of one command can be piped into another Other processing can happen, too
  • 30. Lua: Game Lobby Example CodeLua: Game Lobby Example Code -- add-user.lua: add user to lobby, start game if 4 players local lobby = KEYS[1] -- Set local game = KEYS[2] -- Hash local user_id = ARGV[1] -- String redis.call('SADD', lobby, user_id) if redis.call('SCARD', lobby) == 4 then local members = table.concat(redis.call('SMEMBERS',lobby),",") redis.call('DEL', lobby) -- empty lobby local game_id = redis.sha1hex(members) redis.call('HSET', game, game_id, members) return {game_id, members} end return nil
  • 31. Lua: Game Lobby Example CodeLua: Game Lobby Example Code const redis = require('redis').createClient(); const rEval = require('util').promisify(redis.eval).bind(redis); const script = require('fs').readFileSync('./add-user.lua'); const LOBBY = 'lobby-elo-1500', GAME = 'game-hash'; (async () => { await rEval(script, 2, LOBBY, GAME, 'alice'); await rEval(script, 2, LOBBY, GAME, 'bob'); await rEval(script, 2, LOBBY, GAME, 'cindy'); const [gid,plyrs] = await rEval(script, 2, LOBBY, GAME,'tom'); console.log('GAME ID', gid, 'PLAYERS', plyrs.split(',')); })();
  • 32. Lua: DrawbacksLua: Drawbacks Another language to maintain Simple language, easy syntax Increases overhead on Redis server An infinite loop could lock up server Need to load scripts before using to be efficient It's idempotent; load scripts when app starts
  • 33. RecapRecap Executing singular commands are atomic Executing multiple commands are not atomic Pipelining is not atomic, but it's fast MULTI is atomic, but you can't chain results Lua scripts are atomic and chainable
  • 34. Intrinsic: Node.js Security PoliciesIntrinsic: Node.js Security Policies const REDIS = 'redis://redishost:6379/1'; routes.allRoutes(policy => { policy.redis.allowConnect(REDIS); }); routes.get('/users/*', policy => { policy.redis.allowCommandKey(REDIS, 'GET', 'user-*'); }); routes.post('/server/stats', policy => { policy.redis.allowInfoSection(REDIS, 'memory'); });
  • 35. FinFin Follow me: About Intrinsic: This presentation: @tlhunter intrinsic.com bit.ly/redis-atomicity @tlhunter@tlhunter