API(s):
BuySafeAtomically decrements stock in database.BuyFastAtomicAtomically decrements stock in in-memory cache.BuyFastSignalNon-locking synchronization context to decrementing stock in in-memory cache.BuyFastLockingExclusive lock while decrementing stock in in-memory cache.
API(s):
BuyFastAtomicAtomically decrements stock in Concurrent Dictionary.
Command(s):
- Navigate to directory SuperStock/Tests in terminal
- Run
k6 run k6.js
Redis Pub/Sub is stateless which means cache update events could be lost if either publisher, consumer, or Redis are down. Writes will still be consistent, as long as Writer node is up and running. Possibility of oversell in this case, since all the state is entirely maintained in memory.
- Primary sells some tickets i.e. writes
- Cache update events fail to be sent by Primary or accepted by Redis or consumer by Secondaries
- Primary then goes down
- Readers still have old stock counts for ticket in their cache
- Last few writes by Primary are forever lost
-
Use Write Ahead Log (WAL). Orchestrator synchronizes them during automatic failover. Perhaps we can access WAL for inaccessible Primary node via docker volumes. But that tighly couples Orchestrator with the SuperStock cluster (all 3 nodes). Orchestrator is still a single point of failure. Need to look into leaderless distributed election.
-
Use Quorams. Primary publishes a message and majority nodes reply with success, then Primary commits the transaction i.e. Ticker Sold. But what happens if all replies got Success but Primary went down? Then all the majority nodes would have comitted the sell (I hope...), even though Primary did not commit. In this case, Orchestrator can detect that Primary node died and send TraceId to all Secondary nodes who will revert the stock for the corresponding TraceId. No need to worry about lost updates on Secondary Nodes, since all the subsequent writes after our TraceId are not possible since Primary was already down.
- 2686 RPS
siege -c5 -t2s -b 'http://localhost:5059/api/v1/OneStock/Db/Buy POST' - 7140 RPS
siege -c5 -t2s -b 'http://localhost:5059/api/v1/OneStock/Cache/Atomic/Buy POST' - 9872 RPS
siege -c5 -t2s -b 'http://localhost:5059/api/v1/OneStock/Cache/Signal/Buy POST' - 6496 RPS
siege -c5 -t2s -b 'http://localhost:5059/api/v1/OneStock/Cache/Lock/Buy POST'
K6 Scipt ensures multiple readers and writers operate on multiple products at the same time. In this scenario, the stock for some popular company shares (NVDA, TSLA, AMD) starts at 15000. Then all concurrent requests buy those and eventually, I ensure that the number of buys are equal the number of sells (incremented atomically on successful buy).
Build and run mongo db container
docker pull mongo
docker run -d --name mongo-for-super-stock -p 27018:27017 mongoGo to directory containing DockerFile and build:
docker build --no-cache -t couter-image:latest -f Dockerfile .Then run the container (3 copies)
docker run -d --name core-counter -p 5059:5059 couter-image
docker run -d --name core-counter-1 -p 5080:5059 couter-image
docker run -d --name core-counter-2 -p 5081:5059 couter-imageStop and remove container
docker rm -f core-counter- Primary instance publishes cache update events
- Secondary instances consume the message
- Primary ignores the consumption of echo message
docker run -it -e STOCK_HOST_ID=SuperPrimary --name core-counter -p 5059:5059 couter-image
docker run -it -e STOCK_HOST_ID=SuperSecondary --name core-counter-1 -p 5080:5059 couter-image
docker run -it -e STOCK_HOST_ID=DuperSeconfary --name core-counter-2 -p 5081:5059 couter-imageHere are “bigger-picture” places you’d reach for Interlocked / Volatile—not just code snippets:
Hot-reloadable config / feature flags (snapshot publish) Build a new immutable config object and Exchange it into place; readers Volatile.Read the latest snapshot without locks. (RCU / copy-on-write.)
In-process leader / ownership Competing workers attempt CompareExchange(ref ownerThreadId, myId, 0). The winner becomes the single writer; others act as readers.
Zookeeper? https://zookeeper.apache.org/doc/current/zookeeperOver.html MPSC? https://alexsaveau.dev/blog/opinions/performance/lockness/lockless-queues-are-not-queues






