Zero Downtime Migration

2 posts

line4 min readCurated summary

One Million Events per Second: Implementing End-to-End Encryption with Apache Kafka in the LINE App

LINE handles billions of messages daily, including highly sensitive personal data. While Kafka already provides TLS, authentication, and authorization, those controls do not protect message contents stored in brokers from privileged access. LY Corporation therefore introduced Kafka client-to-client end-to-end encryption, keeping payloads encrypted from producers through consumers while supporting large-scale traffic, flexible consumers, and minimal overhead. ## Limits of Kafka’s Existing Security Model - TLS protects data in transit between clients and brokers. - SASL authenticates clients before they connect. - ACLs control which users or groups can publish to or consume from topics. - These mechanisms primarily control access and communication channels; broker-stored payloads may still exist in plaintext. - End-to-end encryption adds a defense-in-depth layer by encrypting data at production and decrypting it only at authorized consumers. ## Record-Level Encryption - LY Corporation chose record-level rather than batch-level encryption. - Batch encryption offers better compression and lower CPU overhead, but would require modifying Kafka client internals because standard extension points operate at the record level. - Record encryption works with Kafka interceptors, serializers, and deserializers without modifying existing Kafka clients. - Using standard APIs also improves compatibility with future Kafka upgrades, despite somewhat larger messages and reduced compression efficiency. ## DEK–KEK Key Architecture - Payloads are encrypted with a symmetric AES-GCM data encryption key (DEK). - The DEK is encrypted with an ECC-based key encryption key (KEK), using ECIES and the `secp521r1` curve. - KEKs are managed through a key management service (KMS). - Producers use the KEK’s public key, while authorized consumers obtain the private key from KMS. - This hybrid approach: - Avoids the high cost of encrypting large payloads with asymmetric cryptography. - Keeps message size effectively independent of the number of consumers. - Separates encryption and decryption permissions according to the least-privilege principle. ## Encrypted Kafka Message Structure - **Key:** The existing Kafka message key remains unchanged for partitioning. - **Header:** Contains the KEK identifier and the DEK encrypted with that KEK. - **Body:** Contains the payload encrypted with the DEK. - Embedding metadata directly in each message avoids dependencies on external databases or caches. - Consumers identify the appropriate KEK, decrypt the DEK, and then decrypt the payload. ## Producer and Consumer Architecture ### Producer Encryption - Interceptors generate or select the DEK and place the encrypted DEK in the message header. - A wrapper serializer encrypts the serialized payload with the DEK. - The interceptor and serializer share the DEK through `ThreadLocal`, since they run on the same thread. - DEKs are cached for a limited period rather than regenerated and re-encrypted for every message, reducing asymmetric cryptographic overhead. ### Consumer Decryption - Consumers retrieve authorized private KEKs from KMS. - The deserializer reads the encrypted DEK from the header, decrypts it with the private KEK, and decrypts the payload. - Consumers cache encrypted-DEK/plain-DEK pairs, allowing repeated messages from the same producer to bypass redundant DEK decryption. - The existing deserialization process is wrapped so decryption occurs before normal deserialization. ### KMS Operations - Topic owners generate and register KEK key pairs. - Producers retrieve public keys, while authorized consumers retrieve private keys. - New consumers must request access to the private key and receive approval from the topic owner. - KMS manages key distribution, access control, and key rotation. ## Scaling Optimizations ### Shared KEKs - Assigning a unique KEK to every consumer would cause message headers to grow with the consumer count. - This would reduce Kafka batch sizes and increase network, CPU, and memory usage, especially for topics reaching up to one million messages per second. - Multiple consumers therefore share a single KEK, keeping the header size constant. - The trade-off is reduced per-consumer key isolation, mitigated through: - KMS authorization controls. - Mandatory periodic key rotation. - Centralized key management by the topic owner. ### Zero-Downtime Migration - During migration, encrypted and plaintext messages must coexist. - The consumer deserializer checks whether encryption metadata exists: - If headers are present, it decrypts the message. - If headers are absent, it processes the message using the existing plaintext path. - The migration sequence is: - Deploy compatible consumers first. - Enable producer encryption after all consumers support both formats. - Monitor the plaintext-message ratio and complete the migration once it reaches zero. - Producer encryption is intended to be enabled progressively rather than switched to 100% immediately, reducing the risk of unexpected performance or cryptographic failures. ## Practical Conclusion Kafka’s built-in security controls should be supplemented with payload-level encryption when brokers handle highly sensitive data. A record-level AES-GCM design combined with DEK–KEK key wrapping, KMS authorization, caching, shared KEKs, fallback processing, and gradual rollout provides a practical balance between confidentiality, scalability, and operational continuity.

Read original(opens in new tab)
naverOriginal article

Smart Store Center's Zero- (opens in new tab)

Smart Store Center successfully migrated its legacy platform from Oracle to MySQL to overcome performance instability caused by resource contention and to reduce high licensing costs. By implementing a "dual write" strategy, the team achieved a zero-downtime transition while maintaining the ability to roll back immediately without data loss. This technical journey highlights the use of proxy data sources and transaction synchronization to ensure data integrity across disparate database environments. ## Zero-Downtime Migration via Dual Writing * The migration strategy relied on "dual writing," where all Create, Update, and Delete (CUD) operations are performed on both the legacy Oracle and the new MySQL databases. * In the pre-migration phase, Oracle served as the primary source for all traffic while MySQL recorded writes in the background to build a synchronized state. * Once data was fully migrated and verified, the primary traffic was shifted to MySQL, with background writes continuing to Oracle to allow for an instantaneous rollback if performance issues occurred. * This approach decoupled the database switch from application deployment, providing a safety net against critical failures that a simple redeploy could not fix. ## Technical Implementation for JPA * To capture and replicate queries, the team utilized the `datasource-proxy` library, which allowed them to intercept Oracle queries and execute them against a separate MySQL DataSource. * To prevent MySQL write failures from impacting the primary Oracle transactions, writes to the secondary database were managed using `TransactionSynchronizationManager`. * By executing MySQL queries during the `afterCommit` phase, the team ensured that the primary service remained stable even if the secondary database encountered errors or performance bottlenecks. * The transition required modifying JPA Entity configurations, such as changing primary key generation from Oracle Sequences to MySQL’s `IDENTITY` (auto-increment) and adjusting `columnDefinition` for types like `text`, `longtext`, and `decimal`. ## Centralized MyBatis Strategy * To avoid modifying thousands of business logic points in a 10-year-old codebase, the team sought a way to implement dual writing for MyBatis at the architectural level. * The implementation focused on the MyBatis `Configuration` and `MappedStatement` objects to capture SQL execution without requiring manual updates to individual repository interfaces. * This centralized approach maintained the purity of the business logic and ensured that the dual-write logic could be easily removed once the migration was fully stabilized. For organizations managing large-scale legacy migrations, the dual-write pattern combined with asynchronous transaction synchronization is a highly recommended safety mechanism. Prioritizing the isolation of secondary database failures ensures that the user experience remains unaffected while technical validation is performed in real-time.