Databases 19 min read

Comprehensive Didi Interview Review: Redis Persistence, Data Types, Memory Issues, and System Concepts

This article summarizes a Didi second‑round interview covering Redis persistence mechanisms, data structures, memory overflow and leak concepts, thread safety, process vs thread differences, deadlock prevention, TCP/UDP distinctions, and a couple of hand‑written algorithm problems, providing detailed explanations and code examples.

IT Services Circle
IT Services Circle
IT Services Circle
Comprehensive Didi Interview Review: Redis Persistence, Data Types, Memory Issues, and System Concepts

Today I share a colleague's second‑round interview experience at Didi. The interview focused heavily on database knowledge, especially Redis, and included practical scenarios that reflect real production challenges.

1. Project Discussion

The candidate talked about their recent projects for about four to five minutes.

2. Redis Persistence Mechanisms and Characteristics

Redis offers two main persistence methods:

Snapshotting (RDB) Persistence

Redis can create a snapshot of the in‑memory data at a specific point in time. Snapshots can be backed up, copied to other servers for replication, or kept locally for restart.

Typical RDB configuration (in redis.conf ) includes:

save 900 1   # After 900 seconds (15 minutes) if at least 1 key changed, trigger BGSAVE
save 300 10  # After 300 seconds (5 minutes) if at least 10 keys changed, trigger BGSAVE
save 60 10000 # After 60 seconds (1 minute) if at least 10000 keys changed, trigger BGSAVE

AOF (Append‑Only File) Persistence

AOF provides better real‑time durability. It is disabled by default and can be enabled with:

appendonly yes

When enabled, every write command is appended to the AOF file, which resides in the same directory as the RDB file (default name appendonly.aof ).

Three AOF sync policies are available:

appendfsync always   # Write to disk on every modification (slow)
appendfsync everysec # Sync once per second (good balance)
appendfsync no      # Let the OS decide when to sync

Redis 4.0 also supports mixed persistence (RDB + AOF) via the aof-use-rdb-preamble option.

3. Redis Data Types

Supported types include strings, lists, hashes, sorted sets (skiplist), and ziplist (compressed list).

Simple Dynamic String (SDS)

Redis uses its own SDS structure instead of C‑style null‑terminated strings. It stores length and free space, enabling O(1) length retrieval and binary safety.

struct sdshdr {
    int len;   // used bytes
    int free;  // free bytes
    char buf[]; // actual data
}

List (linked list)

Implemented as a doubly linked list:

typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;
typedef struct list {
    listNode *head;
    listNode *tail;
    unsigned long len;
    void *(*dup)(void *ptr);
    void (*free)(void *ptr);
    int (*match)(void *ptr, void *key);
} list;

Lists are used for queues, pub/sub, slow‑log, etc.

Hash (dictionary)

Implemented with a hash table similar to C++ map :

typedef struct dictht {
    dictEntry **table;
    unsigned long size;
    unsigned long sizemask; // size‑1
    unsigned long used;
} dictht;

Two hash tables are kept to support incremental rehashing, and MurmurHash2 is used for key hashing.

Skiplist (sorted set)

Provides ordered set functionality with multi‑level pointers, offering O(log N) search comparable to balanced trees.

Ziplist (compressed list)

Memory‑efficient representation for small lists or hashes, storing data in a compact binary format.

4. Memory Overflow and Leak Concepts

A memory leak typically refers to unreleased heap memory. In C/C++/Go, memory allocated with malloc , new , or similar must be freed with free or delete .

Example of a Go program that eventually exhausts memory:

package main
import (
    "fmt"
    "time"
)
func main() {
    go allocateMemory()
    time.Sleep(5 * time.Second)
}
func allocateMemory() {
    var memorySlice []int
    for {
        memorySlice = append(memorySlice, 1)
        fmt.Println("Allocated memory:", len(memorySlice)*4, "bytes")
        time.Sleep(100 * time.Millisecond)
    }
}

The slice grows indefinitely until the OS terminates the process.

5. Preventing Memory Leaks

Use reference counting: increment on allocation, decrement on release, and report non‑zero counts.

Declare base class destructors as virtual in C++.

Delete arrays with delete [] instead of delete .

Always pair new with delete and malloc with free .

6. StringBuilder vs StringBuffer (Java)

StringBuffer is thread‑safe because its methods are synchronized, which incurs performance overhead.

StringBuilder is not synchronized, offering better performance in single‑threaded contexts.

7. Thread Safety

Thread safety means that concurrent accesses to shared resources do not cause data races or inconsistencies.

Common techniques:

Use synchronization primitives (e.g., synchronized , Lock ).

Employ atomic classes such as AtomicInteger , AtomicLong .

Utilize thread‑safe collections like ConcurrentHashMap , CopyOnWriteArrayList .

Avoid shared mutable state or use immutable objects.

8. Process vs Thread

A process is the basic unit of resource allocation, while a thread is the basic unit of CPU scheduling.

Process

Thread

Definition

Resource allocation unit

Execution unit

Switching

Save/restore full CPU context, page tables, etc.

Save/restore PC, registers, small stack

Owner

OS

OS

Overhead

High (address space, cache flush)

Low

Communication

IPC via OS

Shared memory (global vars)

9. Deadlock and Prevention

Deadlock occurs when two or more threads wait indefinitely for each other.

Prevention strategies include breaking one of the four Coffman conditions:

Eliminate mutual exclusion (e.g., use spooling).

Require all resources up front (break hold‑and‑wait).

Allow preemption of resources.

Impose a global ordering on resource acquisition.

10. TCP vs UDP

TCP is connection‑oriented with three‑way handshake; UDP is connection‑less.

TCP provides reliable, ordered byte streams; UDP sends discrete packets without guarantees.

TCP incurs larger header overhead (20+ bytes) vs UDP (8 bytes).

TCP supports one‑to‑one communication; UDP supports one‑to‑many and many‑to‑many.

11. Hand‑written Algorithms

The interview also included two coding problems: searching a rotated sorted array and finding duplicate elements in an array.

DatabaseRedisMemory LeakThread SafetyInterviewData Structures
IT Services Circle
Written by

IT Services Circle

Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.