← LinkedIn Interview Insights

LinkedIn·Software Engineer·Onsite - System Design / Architecture·Senior

SeniorPrefer not to say
Jun 2026

Summary

LinkedIn system design round for a software engineer role, focused entirely on designing an embedded key-value store library from scratch. The constraint of only using map-like data structures kept things interesting, and the follow-up questions on concurrency and durability made it clear they wanted depth, not just a surface-level answer.

Questions Asked (5)

Q1

Design a low-level key-value store library (like an embedded storage engine) where in-memory indexing is limited to map or dictionary-like structures. It needs O(1) average time for get, put, and delete operations.

System DesignAlgorithms & Data StructuresTechnical Trade-offs
Author's notes

This took me a second to parse because I kept thinking about distributed KV stores like Redis and had to mentally downshift to something more like RocksDB or even just a hash map with extra steps.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements (e.g., durability, concurrency, data size) and then propose a design that separates in-memory indexing (using a hash map) from persistent storage (e.g., append-only log with compaction). Explain how O(1) average time is achieved for get, put, and delete, and discuss trade-offs like memory usage and crash recovery.

Pro tip: Emphasize that while the index provides O(1) average time, worst-case O(n) can occur with hash collisions; mention techniques like consistent hashing or open addressing to mitigate. Also, highlight the importance of a write-ahead log for durability without sacrificing performance.

1. Clarify Requirements and Constraints

Ask about expected data size, persistence needs, concurrency, and performance guarantees. This shapes the design choices.

2. Design In-Memory Index

Use a hash map (e.g., Python dict, Java HashMap) to store key-value pairs or key-to-file-offset mappings. Ensure O(1) average time for get, put, delete by leveraging constant-time hash operations.

3. Design Persistent Storage

Choose an append-only log for writes and an in-memory index for reads. For deletes, use tombstones. Periodically compact the log to reclaim space.

4. Handle Concurrency and Durability

Implement locking or use concurrent data structures for thread safety. Use write-ahead logging (WAL) or fsync to ensure durability without compromising O(1) operations.

5. Discuss Trade-offs and Optimizations

Address memory overhead, worst-case hash collisions, and recovery time. Suggest optimizations like bloom filters or caching.

Key Points to Mention

  • Hash map provides O(1) average time for get, put, delete, but worst-case O(n) due to collisions.
  • Append-only log with in-memory index for persistence; tombstones for deletes.
  • Compaction to reclaim space and maintain performance.
  • Concurrency control (e.g., read-write locks) for thread safety.
  • Durability via write-ahead log (WAL) or fsync.
  • Trade-offs: memory usage vs. disk I/O, recovery time, and consistency guarantees.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

How would you make the key-value store safe for concurrent access across multiple threads?

System DesignTechnical Trade-offs
Author's notes

My first instinct was a single global lock, which I said out loud and immediately regretted.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the concurrency requirements and the expected read/write ratio, then propose a layered approach: coarse-grained locking for simplicity, moving to fine-grained or lock-free techniques for scalability. Discuss trade-offs between correctness, performance, and complexity, and mention how you would test for race conditions.

Pro tip: Mention that you would first try to avoid shared mutable state altogether (e.g., thread-local storage or immutable snapshots) before adding locks, because the fastest lock is no lock. Also, highlight that you would use stress testing and tools like ThreadSanitizer to validate correctness.

1. Clarify requirements and constraints

Ask about the expected number of threads, read/write ratio, latency requirements, and whether the store must be linearizable or can be eventually consistent. This determines the appropriate synchronization strategy.

2. Choose a synchronization strategy

Propose options: coarse-grained locking (simple but low concurrency), fine-grained locking (e.g., per-bucket locks), lock-free using atomic operations (e.g., CAS), or read-write locks. Explain when each is suitable.

3. Address common pitfalls

Discuss issues like deadlocks, priority inversion, false sharing, and memory visibility (e.g., using volatile or memory barriers). Mention how to avoid them.

4. Evaluate trade-offs

Compare performance, scalability, and complexity of each approach. For example, lock-free is faster under high contention but harder to implement and debug.

5. Testing and validation

Describe how you would test concurrency: stress tests with many threads, race detectors, and model checking. Emphasize that correctness is paramount.

Key Points to Mention

  • Mutexes and read-write locks: basic building blocks, but can become bottlenecks.
  • Fine-grained locking: e.g., lock striping or per-key locks to increase concurrency.
  • Lock-free data structures: using atomic operations like compare-and-swap (CAS) for non-blocking progress.
  • Memory consistency and visibility: ensuring changes are visible across threads (e.g., using volatile, memory barriers).
  • Deadlock prevention: lock ordering, timeouts, or lock-free approaches.
  • Performance trade-offs: contention, scalability, and overhead of synchronization.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

How would you approach durability and crash recovery for this store? What about compaction?

System DesignData Modeling
Author's notes

Write-ahead logging came up naturally and I felt okay explaining the basic idea: append to a log before applying to the in-memory map, replay on startup.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the store's requirements (e.g., write throughput, read latency, data size) and then explain how you would achieve durability through write-ahead logging and periodic snapshots, ensuring crash recovery via log replay. For compaction, describe strategies like size-tiered or leveled compaction, balancing write amplification, read amplification, and space amplification.

Pro tip: Mention that durability and compaction are tightly coupled: compaction affects recovery time and disk usage, so you must consider trade-offs like using checksums to detect corruption and designing compaction to be crash-safe with atomic file swaps.

1. Clarify requirements and assumptions

Ask about the store's expected write volume, read patterns, data size, and consistency needs to tailor durability and compaction strategies.

2. Design durability mechanism

Propose a write-ahead log (WAL) for atomicity and durability, with configurable fsync policies, and periodic snapshots to bound recovery time.

3. Outline crash recovery process

Explain how to replay the WAL from the last snapshot, handle partial writes with checksums, and ensure idempotent recovery.

4. Choose compaction strategy

Select a compaction approach (e.g., leveled, size-tiered, or hybrid) based on workload, and describe how it merges SSTables and removes tombstones.

5. Address trade-offs and optimizations

Discuss how compaction impacts write/read/space amplification, and how to make compaction crash-safe (e.g., atomic manifest updates).

Key Points to Mention

  • Write-ahead logging (WAL) with configurable fsync for durability
  • Periodic snapshots/checkpoints to reduce recovery time
  • Checksums (e.g., CRC32) to detect corruption in WAL and SSTables
  • Compaction strategies: size-tiered vs. leveled, and their trade-offs
  • Crash-safe compaction using atomic file renames and manifest updates
  • Tombstones and garbage collection during compaction

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

How would you add TTL or key expiration to this store, and what are the tradeoffs of different expiration strategies?

System DesignTechnical Trade-offs
Author's notes

Lazy expiration vs background sweep.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the store's architecture (in-memory, disk-based, distributed) and the requirements for TTL (e.g., precision, scale, memory overhead). Then propose a concrete design, such as lazy expiration with periodic active sweeps, and discuss tradeoffs of different strategies (lazy vs. active vs. hybrid) in terms of CPU, memory, and latency.

Pro tip: Tie the expiration strategy to LinkedIn's scale and latency requirements—e.g., mention that a hybrid approach balances memory reclamation with CPU overhead, and that you'd monitor expiration rates to tune the active sweep frequency.

1. Clarify requirements and constraints

Ask about the store's type (in-memory, persistent, distributed), expected key count, TTL precision needs, and acceptable latency/memory overhead. This ensures your design fits the context.

2. Propose a basic TTL mechanism

Describe storing an expiration timestamp with each key and checking it on access (lazy expiration). Mention that this is simple but can leave expired keys in memory if never accessed.

3. Introduce active expiration

Explain adding a background process that periodically samples and removes expired keys. Discuss how to tune the sampling rate and frequency to balance CPU usage and memory reclamation.

4. Compare expiration strategies

Contrast lazy, active, and hybrid approaches. Highlight tradeoffs: lazy minimizes CPU but risks memory bloat; active reclaims memory but adds CPU overhead; hybrid balances both but adds complexity.

5. Address edge cases and optimizations

Discuss handling of large TTLs, clock skew in distributed systems, and potential use of approximate expiration (e.g., Redis's probabilistic expiration). Mention monitoring and tuning as key operational aspects.

Key Points to Mention

  • Lazy expiration: check TTL on access, simple but can cause memory leaks if keys are not accessed.
  • Active expiration: background sweeper, reclaims memory but consumes CPU; need to tune frequency and batch size.
  • Hybrid approach: combine lazy and active for balanced performance, as used in Redis.
  • Tradeoffs: memory vs. CPU vs. latency; precision vs. overhead; simplicity vs. scalability.
  • Distributed considerations: clock synchronization, consistency of expiration across nodes, and potential for stale reads.
  • Monitoring and tuning: track expired key ratio, memory usage, and CPU load to adjust expiration parameters dynamically.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

How would you test this key-value store library?

System DesignAlgorithms & Data Structures
Author's notes

I went unit tests for basic put/get/delete correctness, then concurrency stress tests with multiple goroutines hammering the same keys, then fault injection for crash recovery.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the library's API, expected behavior, and non-functional requirements. Then outline a layered testing strategy covering unit, integration, and performance tests, focusing on correctness, concurrency, and scalability. Conclude by discussing how you would automate and integrate these tests into CI/CD.

Pro tip: Emphasize testing for concurrency and consistency, as key-value stores often face race conditions and data corruption under load. Also, mention property-based testing to uncover edge cases beyond typical unit tests.

1. Clarify Requirements and Scope

Ask about the library's API, expected operations (get, put, delete, range queries), consistency guarantees, and performance targets. This ensures your testing strategy aligns with actual use cases.

2. Design Unit Tests for Core Functionality

Test individual operations in isolation, covering normal cases, edge cases (empty keys, large values), and error conditions (invalid inputs, missing keys). Use mocking for external dependencies.

3. Plan Integration and System Tests

Test interactions between components, such as persistence, replication, and network communication. Include end-to-end tests simulating real-world usage patterns.

4. Address Non-Functional Testing

Design tests for performance (throughput, latency), scalability (horizontal scaling), and reliability (failover, recovery). Use tools like JMeter or custom benchmarks.

5. Automate and Integrate into CI/CD

Set up automated test suites to run on every commit, with reporting and alerts. Include stress tests in nightly builds to catch regressions.

Key Points to Mention

  • Concurrency testing: simulate multiple threads/processes to detect race conditions and ensure thread safety.
  • Consistency models: verify strong vs. eventual consistency guarantees under different scenarios.
  • Fault injection: test behavior during network partitions, node failures, and disk errors.
  • Performance benchmarks: measure throughput, latency, and resource utilization under varying loads.
  • Property-based testing: use tools like QuickCheck to generate random inputs and verify invariants.
  • Data integrity: ensure no data loss or corruption after crashes or restarts.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.