Skip to content

Gift - Wish (SSOT)

This story demonstrates the SSOT (Single Source of Truth) pattern: how KakaoTalk Gift’s wish list became Actionbase’s first production deployment.

The wish list feature in KakaoTalk Gift allowed users to save gifts they wanted to receive. The existing architecture looked like this:

flowchart LR
    App[Application] --> MySQL[(MySQL)]
    MySQL --> Batch[Spring Batch]
    Batch --> Redis[(Redis)]
  • MySQL stored the wish data and served forward queries (get, scan, count by user)
  • Spring Batch aggregated reverse counts (how many users wished each product)
  • Redis cached the reverse counts for fast reads

This worked well initially. But as traffic grew, we hit scaling walls:

  • Table size grew beyond comfortable limits
  • Keeping data consistent between MySQL and Redis became complex

We considered sharding MySQL. But sharding brings its own complexity—shard key management, cross-shard queries, operational overhead. Actionbase got the chance to prove itself here.

We didn’t flip a switch. The migration happened in careful stages over several months.

flowchart LR
    App[Application] -->|write| Existing[Existing System]
    App -->|write| AB[(Actionbase)]
    App -->|read| Existing

First, we added Actionbase as a write target alongside the existing system (MySQL + Redis). Reads still came from the existing system.

For historical data, we:

  1. Dumped the MySQL table
  2. Bulk-loaded into Actionbase
  3. Replayed the WAL to catch up with writes that happened during the dump

Note: The migration pipeline (bulk loading) is currently internal. Open source release is in progress — see Roadmap.

This gave us a consistent snapshot without downtime.

For one month, we compared:

  • MySQL dumps (source of truth)
  • Actionbase CDC-based snapshots

The data matched. We had confidence in consistency.

flowchart LR
    App[Application] -->|write| Existing[Existing System]
    App -->|write| AB[(Actionbase)]
    App -->|read| Existing
    App -.->|shadow read| AB

Next, we added shadow reads to Actionbase—calling it but not using the results. This validated that Actionbase could handle production traffic patterns without affecting users.

flowchart LR
    App[Application] -->|write| Existing[Existing System]
    App -->|write| AB[(Actionbase)]
    App -->|read| AB

After confirming traffic handling, we switched reads to Actionbase. At this point, Actionbase became the source of truth. The existing system remained as a backup—if anything went wrong, we could roll back instantly.

Months later, with no issues, we removed the old system entirely:

flowchart LR
    App[Application] --> AB[(Actionbase)]

No more batch jobs. No more consistency issues. Just Actionbase.

  • Gradual migration reduces risk. Dual write, then dual read, then cutover. Each stage validates the next.
  • Keep rollback paths open. We maintained the existing system for months after the cutover. Peace of mind matters.
  • WAL replay enables zero-downtime bulk loads. Dump, load, replay—no data loss.

This pattern became the template for source-of-truth migrations at Kakao.