high level design
- support high concurrency and write-heavy load
- high availability > consistency
probabilistic data structures
- hash set -> constant time complexity at expense of increased memory usage
- redis’ hyperloglog -> estimate/approximate the cardinality of set (count), and doesn’t support delete operation
relational database
- acquire lock (mutex) before counter is increased
- reader-writer lock can be used to reduce lock granularity and improve performance of reads -> strong consistency
- support batch update count events from cache, it may cause delay in updating counter -> inaccurate count, fault tolerance is reduced because counter cannot be recalculated if value is not written to DB
- store each update event in a single record -> high concurrent writes (no need for locks), but require reads aggregate on entire table, and more cost of storage
- DB can be partitioned/shared (consistent hashing) or replicated (leader-followers + failover) to scale counter
shared counter

- probability of lock conflicts is reduced through partitioning
- when page/… becomes more popular, userId/… can be used as key for partition
- multiple counters are initialized, updated in parallel, and final value is summed from all shards (scatter/gather) -> only optimal for low data volume access
- DB replication causes write congestion and poor latency. it still needs resolve conflicts
-> NOT USE
nosql database
- apache cassandra supports partitioning using gossip protocol and consistent hashing -> highly available
- disk access may be bottleneck of read performance, use cache (cache-aside pattern) can improve performance of read -> data consistency cannot be guaranteed
- counter type of cassandra (race-free) can be utilized for distributed counter
- operation complexity is high and lack of repeatability (idempotency - perform an operation multiple times -> same result)
-> NOT USE
message queue

- used as buffer the count update events from clients, database is asynchronously updated at periodic intervals -> use serverless function to query and update DB (pull model)
- pull model increase operation complexity and may return inaccurate counter due to asynchronous update
lambda

- separate count update events (source of truth) and aggregation count (increase storage usage)
- batch processing service recompute counter accurately at periodic intervals
- the final result of counter is merged from both batch service and real-time service
- use cache to reduce load on reads -> improve performance
-> NOT USE
redis
- high performance, throughput -> use for write-intensive distributed counter?
- use write-behind cache pattern (app -> cache -> DB) to persist counter for durability
- update operations must be idempotent for conflict-free synchronization, but redis’ update operations are not idempotent, and non-trivial
-> NOT USE
conflict-free replicated data type (CRDT) distributed counter
-
CRDT is data type that ensures data always converge to consistent state among nodes
-
allows lock-free for reads and writes, and use mathematically proven rules for conflict resolution
-
prevents data duplication and doesn’t rely on the order of replications?
-
relaxes consistency constraints, tolerates network partition (accepts writes to disconnected nodes, merges later) -> high performance/throughput, low latency for both reads and writes
-
CRDT exchanges data and operations including ordering and causality
-
3 types
- G-Counter (grow/increase only)
- needs to know number of replicas
- PN-Counter (positive/negative)
- supports read-your-write (reads after write) and monotonic reads for strong consistency, and arbitrary number of replicas for high scalability
- G-sets
- Handoff counter
- is eventually consistent, more stable than PN-counter
- G-Counter (grow/increase only)
-
support count synchronization with reduced storage, low latency and high performance, and converge to consistent state (eventual consistency)
-
each replica stores its own counter and update operations instead of global counter -> use vector clock/version to identify causality of operations among replicas
-
