Tutorials Courses Interview Prep (100 Q&A) AI Tools (50) Developer Tools (50) Tracks Pricing Plans Blog & Articles Contact Us
Open-Access Production Interview Prep

Senior & Lead Engineer Interview Mastery Hub

100 real-world, scenario-based architecture & concurrency questions designed for 5–10+ years experienced developers. Free & open for every student and engineer.

100

Real-world Q&As

100%

Scenario-Based

5-10 Yrs

Senior / Lead Depth

5 Stacks

Core Technologies

Showing 100 questions for senior interview preparation

•
Laravel Advanced & Architecture 8-10 Years (Tech Lead) Expert Production Scenario

How does Laravel Octane handle state persistence across requests, and how do you prevent catastrophic memory leaks and data bleeding in singletons?

Incident Scenario: In a high-throughput production environment running Laravel Octane with Swoole/FrankenPHP serving 10,000 req/sec, users reported seeing other users' authenticated profiles, and worker memory consumption steadily increased until pods crashed with OOM.
105 views • Direct Permalink

Root Cause Analysis: Traditional PHP-FPM vs. Long-Running Octane

Under traditional PHP-FPM, the entire application lifecycle (memory, static variables, singletons) is instantiated on request arrival and wiped completely when the request terminates (shared-nothing architecture).

Under Laravel Octane (Swoole, RoadRunner, FrankenPHP), the PHP application boots once into memory. Worker processes persist across thousands of requests. Any state attached to a singleton, static property, or service provider persists across subsequent HTTP requests from completely different clients.

Critical Failure Vectors

  1. Data Bleeding: Storing request-scoped data (like Auth::user() or tenant IDs) inside a singleton service constructor or static class property. Subsequent requests will read the prior user's cached identity.
  2. Memory Leak: Appending items into static array caches (private static array $cache = []) or listening to events without unregistering listeners.

Architectural Solution

  1. Use bindScoped Instead of singleton: Laravel Octane resets scoped bindings between requests:

    // BAD in Octane (persists across requests)
    $this->app->singleton(TenantManager::class, fn () => new TenantManager($request->header('X-Tenant-ID')));
    
    // GOOD in Octane (purged after each request finishes)
    $this->app->scoped(TenantManager::class, fn () => new TenantManager(request()->header('X-Tenant-ID')));
    
  2. Octane Warmers & Listeners: Flush state explicitly in config/octane.php listeners:

    OperationTerminated::class => [
        FlushTemporaryCaches::class,
        ResetTenantContext::class,
    ],
    
  3. Pass Callbacks or Resolvers: Instead of caching an instantiated $user in a service, pass a Closure or resolve dynamically via Auth::user().

Tags: #Octane #Swoole #Memory Leaks #Singletons #State Bleed
Modern PHP 8.x & Internals 8-10 Years (Tech Lead) Expert Production Scenario

How does the Zend Engine manage memory with Zvals, Reference Counting, and the Circular Garbage Collector in PHP 8.x?

Incident Scenario: A long-running PHP CLI daemon processing telemetry records climbed from 40MB to 2.5GB of RAM over 6 hours despite unsetting variables (`unset($record)`).
198 views • Direct Permalink

Zval Structure & Reference Counting

In PHP, variables are stored in a zval (Zend Value) struct containing:

  1. value: Union storing the primitive or pointer.
  2. u1.type_info: Type identifier.
  3. refcount: Number of variables pointing to this compound value (arrays, objects).

The Circular Reference Trap

When Object A points to Object B, and Object B points to Object A:

$a = new Node();
$b = new Node();
$a->sibling = $b;
$b->sibling = $a;

unset($a, $b); // Refcounts decrement from 2 to 1, but never reach 0!

Even after unset(), both objects remain in memory because their refcount is 1.

Solving Daemon Memory Leaks

  1. PHP Cycle Collector Buffer: The GC buffer collects potential cyclic roots (10,000 max by default).
  2. Explicit Garbage Collection Trigger:
    gc_collect_cycles(); // Forces cycle collection in loop
    gc_mem_caches();     // Releases cached memory chunks back to OS
    
  3. Weak References (PHP 8.0+): Use WeakReference so child nodes do not increment the parent's refcount:
    $this->parent = WeakReference::create($parentNode);
    
Tags: #Zend Engine #Zval #Garbage Collection #Memory Management #Internals
MySQL Tuning, Indexing & Concurrency 8-10 Years (Tech Lead) Hard Production Scenario

How does the InnoDB B+Tree Index work internally, and why does Leftmost Prefix Rule dictate composite index column ordering?

Incident Scenario: A query `WHERE status = "active" AND created_at >= "2026-01-01" AND user_id = 500` was doing a full table scan across 30 million rows despite having an index on `(created_at, status, user_id)`.
133 views • Direct Permalink

Why B+Tree Needs Leftmost Prefix Rule

In an InnoDB B+Tree, index keys are sorted lexicographically based on the order of columns defined in the index: (ColA, ColB, ColC).

  • If a query filters on ColB without ColA, the B+Tree root cannot branch because ColB is only sorted within duplicate values of ColA.
  • Range Queries Stop Index Filtering: Once a range operator (>, <, BETWEEN, >=) is evaluated, subsequent columns in the composite index cannot be used for B+Tree traversal.

Fixing the Slow Query

Because created_at used a range operator (>=), placing it first broke index lookups for status and user_id.

Optimal Composite Index Column Order:

  1. Exact equality matches with highest cardinality first: user_id
  2. Equality match: status
  3. Range match last: created_at
ALTER TABLE orders ADD INDEX idx_user_status_created (user_id, status, created_at);

Query execution time drops from 8.5 seconds (full scan) to 0.8 milliseconds (index seek).

Tags: #MySQL #InnoDB #B+Tree #Composite Index #Leftmost Prefix
PostgreSQL Enterprise & Performance 8-10 Years (Tech Lead) Expert Production Scenario

How does PostgreSQL Multi-Version Concurrency Control (MVCC) manage Tuple Visibility (`xmin`, `xmax`), and why does Table Bloat happen?

Incident Scenario: A table with 10 million rows that undergoes 500,000 updates daily grew from 2GB to 45GB on disk, causing query slowdowns even though total row count stayed constant.
550 views • Direct Permalink

PostgreSQL MVCC Mechanics

Unlike MySQL InnoDB which overwrites data pages and creates rollback segments in Undo Logs, PostgreSQL MVCC creates a new row version (tuple) on every UPDATE and marks the old tuple as dead by recording the committing transaction ID in xmax.

  • Readers never block writers, and writers never block readers.
  • Table Bloat: If dead tuples are not reclaimed, physical table and index disk files continue to grow indefinitely.

Remediation:

  1. Tune autovacuum parameters for high-churn tables:
    ALTER TABLE orders SET (
        autovacuum_vacuum_scale_factor = 0.05,
        autovacuum_vacuum_cost_limit = 2000
    );
    
  2. Reclaim bloated disk space online without locking reads/writes via pg_repack.
Tags: #PostgreSQL #MVCC #xmin/xmax #Table Bloat #VACUUM
System Design, Redis & Distributed Systems 10+ Years (Principal / Architect) Expert Production Scenario

How does the Redis Redlock Algorithm provide Fault-Tolerant Distributed Locking across independent Redis nodes?

Incident Scenario: A financial settlement system running on 5 distributed microservice nodes needed to acquire mutually exclusive locks without relying on a single Redis master point-of-failure.
45 views • Direct Permalink

Why a Single Redis Master is Insufficient for Strict Distributed Locking

In a standard Master-Replica Redis setup, replication is asynchronous. If the master crashes immediately after granting a lock before replicating to replicas, the promoted replica can grant the exact same lock to a second client, causing catastrophic double-execution.

The Redlock Algorithm Workflow

  1. Client initializes $N$ independent Redis master nodes (e.g. $N=5$).
  2. Client gets current millisecond timestamp $T_1$.
  3. Client attempts to acquire the lock sequentially across all $N$ instances using identical key, random unique value, and TTL (e.g. 10s) with a short timeout (e.g. 50ms) per node.
  4. Client computes elapsed time $Elapsed = T_2 - T_1$.
  5. Lock Acquisition Success: If the client acquired the lock on majority of nodes (>= 3 out of 5) AND $Elapsed < TTL$, the lock is valid for $ValidityTime = TTL - Elapsed$.
  6. Failure & Rollback: If client failed to acquire on majority, it immediately sends an unlock script (Lua EVAL) to all instances, even those where it thought acquisition failed.
Tags: #Redis #Redlock #Distributed Locks #High Availability #Consensus
Laravel Advanced & Architecture 5-8 Years (Senior) Hard Production Scenario

How do you prevent Deadlocks when processing concurrent financial transactions or inventory deductions across multiple queue workers in Laravel?

Incident Scenario: During a Flash Sale with 50 concurrent queue workers processing checkout jobs, MySQL threw repeated "Deadlock found when trying to get lock; try restarting transaction" (Error 1213), causing failed orders and duplicate inventory deductions.
294 views • Direct Permalink

Why Deadlocks Occur in Concurrent Workers

A deadlock occurs when Worker A holds a lock on Resource 1 and requests Resource 2, while Worker B holds a lock on Resource 2 and requests Resource 1. Neither can proceed.

Battle-Tested Remediation Strategy

  1. Strict Ordering of Locks: Always sort entity IDs before acquiring database row locks (lockForUpdate):

    // Sort items by ID so all workers acquire locks in the exact same sequence
    $itemIds = collect($cartItems)->pluck('product_id')->sort()->values();
    
    DB::transaction(function () use ($itemIds) {
        $products = Product::whereIn('id', $itemIds)->lockForUpdate()->get();
        // Deduct inventory safely
    }, 5); // 5 retries on deadlock
    
  2. Atomic SQL Decrements: Instead of SELECT -> calculate in PHP -> UPDATE, perform atomic database decrements:

    $affected = DB::table('products')
        ->where('id', $productId)
        ->where('stock', '>=', $quantity)
        ->decrement('stock', $quantity);
    
    if ($affected === 0) {
        throw new OutOfStockException("Insufficient inventory.");
    }
    
  3. Redis Atomic Distributed Lock (Redlock / Mutex): Prevent queue workers from touching the same wallet simultaneously:

    use Illuminate\Support\Facades\Redis;
    
    Redis::throttle("wallet-lock:{$userId}")
        ->block(10)
        ->allow(1)
        ->every(1)
        ->then(function () use ($userId, $amount) {
            // Execute transaction safely
        });
    
Tags: #Transactions #Deadlocks #Pessimistic Locking #Queues #Concurrency
Modern PHP 8.x & Internals 5-8 Years (Senior) Medium Production Scenario

Explain PHP 8.4 Asymmetric Visibility, Property Hooks, and Constructor Property Promotion.

Incident Scenario: Refactoring a monolithic domain model with 40 getters/setters and boilerplate validation logic to clean, modern PHP 8.4 syntax.
295 views • Direct Permalink

1. Asymmetric Visibility (PHP 8.4)

Allows a property to be publicly readable but privately or protectedly writable:

class User
{
    public private(set) string $status = 'pending';

    public function activate(): void
    {
        $this->status = 'active'; // Allowed inside class
    }
}

$user = new User();
echo $user->status; // Allowed: readable
// $user->status = 'banned'; // FATAL ERROR: cannot modify private(set) property outside

2. Property Hooks (PHP 8.4)

Replaces repetitive getters and setters with direct property hooks:

class Product
{
    public string $title;

    public string $slug {
        get => Str::slug($this->title);
    }

    public float $price {
        set (float $value) {
            if ($value < 0) throw new InvalidArgumentException("Price cannot be negative");
            $this->price = round($value, 2);
        }
    }
}
Tags: #PHP 8.4 #Property Hooks #Asymmetric Visibility #OOP
MySQL Tuning, Indexing & Concurrency 10+ Years (Principal / Architect) Expert Production Scenario

Explain InnoDB Locking Modes: Record Locks, Gap Locks, and Next-Key Locks, and how they prevent Phantom Reads.

Incident Scenario: Under `REPEATABLE READ` isolation level, two concurrent transactions inserting users with IDs between 10 and 20 resulted in lock wait timeouts and deadlocks.
277 views • Direct Permalink

The Three InnoDB Row Lock Types

  1. Record Lock: Locks the physical index record itself (e.g. WHERE id = 5 FOR UPDATE).
  2. Gap Lock: Locks the gap between index records (or before the first / after the last) to prevent other transactions from inserting new rows in that gap.
  3. Next-Key Lock: A combination of a Record Lock on the index record plus a Gap Lock on the gap preceding it.

Why MySQL Uses Next-Key Locks by Default

Under the default REPEATABLE READ isolation level, MySQL uses Next-Key locking to solve the Phantom Read problem (preventing another transaction from inserting a new row that matches your query's range before you commit).

Reducing Lock Contention:

Switching transaction isolation to READ COMMITTED (with binlog_format=ROW) disables Gap Locks except for foreign key constraint checks and duplicate key checks.

Tags: #InnoDB Locks #Gap Locks #Next-Key Locks #Phantom Reads #Transactions
PostgreSQL Enterprise & Performance 5-8 Years (Senior) Hard Production Scenario

How do GIN (Generalized Inverted Index) and GiST indexes optimize high-speed JSONB queries and Full-Text Search in PostgreSQL?

Incident Scenario: Searching for arbitrary keys and nested tags inside a 20-million-row JSONB column was taking 6.8 seconds per query.
394 views • Direct Permalink

GIN with jsonb_path_ops

Standard GIN indexes every key and value. For direct JSON path containment queries (@>), jsonb_path_ops produces an index that is 3x smaller and faster:

CREATE INDEX idx_user_metadata_gin ON users USING GIN (metadata jsonb_path_ops);

-- Optimized query uses GIN index seek
SELECT * FROM users
WHERE metadata @> '{"subscription": {"plan": "enterprise", "status": "active"}}';

Execution time drops from 6.8s to 1.2ms.

Tags: #PostgreSQL #JSONB #GIN Index #jsonb_path_ops #Full Text Search
System Design, Redis & Distributed Systems 8-10 Years (Tech Lead) Hard Production Scenario

Explain the 3 High-Scale Cache Failure Patterns: Cache Avalanche, Cache Breakdown (Dog-Piling), and Cache Penetration, with mitigations.

Incident Scenario: During Black Friday, a major e-commerce backend crashed because 50,000 product cache keys with identical 1-hour TTLs expired at the exact same second.
316 views • Direct Permalink

1. Cache Avalanche (Mass Simultaneous Expiration)

  • Problem: Millions of keys expire at the same instant; massive traffic rushes to the DB.
  • Solution: Add Random TTL Jitter:
    $ttl = 3600 + rand(0, 600); // 60 to 70 minutes randomized expiration
    

2. Cache Breakdown / Dog-Piling (Hot Key Expiry)

  • Problem: A single viral product key expires; 20,000 concurrent requests miss simultaneously.
  • Solution: Distributed Mutex Lock or Background Pre-warming / Stale-While-Revalidate.

3. Cache Penetration (Non-Existent Keys Attack)

  • Problem: Malicious requests query non-existent IDs (id = -9999), bypassing cache and hitting DB on every request.
  • Solution:
    1. Cache Empty Objects / Nulls with short TTL (e.g. 60 seconds).
    2. Bloom Filter: Use Redis Bloom filter to determine in $O(1)$ whether an ID could possibly exist before querying database.
Tags: #Cache Avalanche #Cache Breakdown #Cache Penetration #Bloom Filter #Redis
Laravel Advanced & Architecture 8-10 Years (Tech Lead) Hard Production Scenario

How does the Laravel Service Container resolve dependencies using Reflection, and what are the performance trade-offs in large applications?

Incident Scenario: A large enterprise SaaS app with 800+ service classes was experiencing high latency on cold boots. Profiling via Blackfire showed 35% of request time was spent in `Illuminate\Container\Container::resolve()`.
253 views • Direct Permalink

How Container Resolution Works

  1. When you request a class (e.g. app(PaymentService::class)), if no binding exists, the container checks isBuildable($concrete).
  2. It instantiates ReflectionClass($concrete).
  3. It inspects getConstructor() and iterates through parameters via ReflectionParameter.
  4. It recursively resolves parameter typehints from the container or defaults until the dependency graph is fully satisfied.

Optimization Strategies for Large Applications

  • Service Provider Deferral: Use \Illuminate\Contracts\Support\DeferrableProvider so large service providers are only loaded when their bound service is explicitly requested.
  • Route & Config Caching: php artisan route:cache, php artisan config:cache avoids repetitive reflection scans on routes and controllers.
  • Explicit Bindings: Direct closures ($this->app->bind(Service::class, fn () => new Service(...))) skip reflection overhead entirely.
Tags: #Service Container #Reflection #Dependency Injection #Performance
Modern PHP 8.x & Internals 8-10 Years (Tech Lead) Hard Production Scenario

How does the JIT (Just-In-Time) compiler in PHP 8.x work, and why does it benefit CPU-heavy tasks but not typical database-heavy web apps?

Incident Scenario: A tech lead enabled JIT in production expecting an immediate 5x speedup for a REST API, but observed only a 2% improvement in response time.
737 views • Direct Permalink

How PHP JIT Compiles Code

  1. Traditional PHP with OPcache: PHP source code is parsed into Abstract Syntax Tree (AST) -> Compiled into Opcodes -> Executed by the Zend VM bytecode interpreter.
  2. JIT (Tracing / Function JIT): Identifies frequently executed opcode paths ("hot spots") and translates those opcodes directly into raw machine code (x86_64 or ARM CPU instructions), bypassing Zend VM.

Why Web Apps See Minimal Gains

  • Typical web applications are I/O-bound (waiting on MySQL network queries, Redis reads, filesystem, external HTTP calls).
  • JIT accelerates CPU-bound mathematical computation, image rendering, 3D matrix math, and machine learning tokenization, where PHP spends 90%+ time in pure CPU instructions.
Tags: #JIT #Compiler #OPcache #CPU bound vs IO bound #PHP Internals
MySQL Tuning, Indexing & Concurrency 5-8 Years (Senior) Hard Production Scenario

How do you optimize deep pagination (`SELECT * ... LIMIT 5000000, 20`) on large tables with 100M rows?

Incident Scenario: An API endpoint paginating through 50 million audit log records timed out (504 Gateway Timeout) when users accessed page 50,000.
187 views • Direct Permalink

Why LIMIT 5000000, 20 is Slow

MySQL must scan, read from disk, and discard all 5,000,000 preceding rows before returning the 20 requested records.

Solution 1: Cursor-Based Pagination (Seek Method) - FASTEST

Instead of offset, filter by the last seen ID:

SELECT * FROM audit_logs
WHERE id < 45000000
ORDER BY id DESC
LIMIT 20;

Direct B+Tree seek, runs in 0.4 milliseconds on any page number.

Solution 2: Deferred Join (Late Row Lookup)

If random page offset jumps are required, use a covering index subquery:

SELECT a.* FROM audit_logs a
JOIN (
    SELECT id FROM audit_logs
    ORDER BY created_at DESC
    LIMIT 5000000, 20
) AS sub ON a.id = sub.id;

The inner subquery scans only the memory-efficient index tree without fetching heavy row columns until the final 20 IDs are found.

Tags: #Pagination #LIMIT OFFSET #Deferred Join #Cursor Pagination
PostgreSQL Enterprise & Performance 8-10 Years (Tech Lead) Hard Production Scenario

How does PgBouncer Connection Pooling operate in Transaction Mode vs. Session Mode, and what PostgreSQL features break in Transaction Mode?

Incident Scenario: Switching PgBouncer to `pool_mode = transaction` reduced database CPU load by 60%, but developers reported intermittent errors with Prepared Statements and Temporary Tables.
404 views • Direct Permalink

PgBouncer Pool Modes Comparison

  • Session Mode: A client holds a dedicated backend PostgreSQL connection for the entire lifetime of its socket.
  • Transaction Mode: A backend PostgreSQL connection is assigned to a client ONLY for the duration of a single transaction and returned to the pool immediately upon COMMIT or ROLLBACK.

Features Incompatible with Transaction Mode:

  1. Session-level Prepared Statements (unless using PgBouncer 1.21+ with named prepared statement support).
  2. SET SESSION / LISTEN / NOTIFY.
  3. Temporary Tables (they disappear when connection changes).
  4. DISCARD ALL / DEALLOCATE ALL.
Tags: #PgBouncer #Connection Pooling #Transaction Mode #Prepared Statements
System Design, Redis & Distributed Systems 8-10 Years (Tech Lead) Hard Production Scenario

Compare Rate Limiting Algorithms: Token Bucket, Leaky Bucket, Fixed Window Counter, and Sliding Window Log/Counter.

Incident Scenario: Designing an enterprise API gateway protecting downstream microservices from traffic spikes while allowing legitimate burst traffic.
471 views • Direct Permalink

Comparison Matrix

Algorithm Pros Cons Ideal For
Token Bucket Allows bursts up to bucket capacity, smooth refills Memory state tracking required API Gateways (Stripe / GitHub style)
Leaky Bucket Guarantees constant, smooth output rate Discards bursts if queue full Egress traffic shaping
Fixed Window Low memory Boundary spikes (2x burst at window edges) Basic IP throttling
Sliding Window Counter Prevents boundary spikes, memory efficient Approximate calculation High-scale tier limiting

Sliding Window Lua Script in Redis

local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])

-- Remove timestamps older than current sliding window
redis.call('ZREMRANGEBYSCORE', key, '-inf', now - window)
local current_count = redis.call('ZCARD', key)

if current_count < limit then
    redis.call('ZADD', key, now, now)
    redis.call('EXPIRE', key, window)
    return 1 -- Allowed
else
    return 0 -- Blocked (HTTP 429)
end
Tags: #Rate Limiting #Token Bucket #Sliding Window #Redis Lua #API Gateway
Laravel Advanced & Architecture 10+ Years (Principal / Architect) Expert Production Scenario

How do you execute Zero-Downtime database migrations on tables with 50+ million rows without locking writes in production Laravel?

Incident Scenario: Running `php artisan migrate` to add a new column and composite index on a 60-million-row `orders` table locked the table for 18 minutes, resulting in HTTP 504 Gateway Timeouts across the entire checkout funnel.
806 views • Direct Permalink

Root Cause

Standard ALTER TABLE statements in MySQL can acquire exclusive metadata locks (MDL), blocking all incoming INSERT/UPDATE operations until the table rewrite finishes.

Safe Migration Patterns

  1. Online DDL with Algorithm=INPLACE, Lock=NONE:
    ALTER TABLE orders ADD COLUMN fulfillment_status VARCHAR(30) DEFAULT 'pending',
    ALGORITHM=INPLACE, LOCK=NONE;
    
  2. The Expand/Contract (Blue-Green Schema) Pattern:
    • Step 1 (Expand): Add the new column as NULLABLE (instant operation).
    • Step 2 (Dual-Write): Write to both old and new columns via model events or repository layer.
    • Step 3 (Backfill in Background Queues): Chunk existing 60M rows with a queue worker in batches of 5,000 using ID-based cursor pagination.
    • Step 4 (Switch Reads): Deploy code pointing all read queries to the new column.
    • Step 5 (Contract): Drop the old column after zero dependencies remain.
  3. Use GitHub's gh-ost or Percona pt-online-schema-change: Creates an ghost shadow table, triggers/binlog replays changes, and performs an atomic table swap without holding locks.
Tags: #Database Migrations #Zero Downtime #MySQL Online DDL #Large Tables
Modern PHP 8.x & Internals 10+ Years (Principal / Architect) Expert Production Scenario

How do PHP Fibers work under the hood, and how do they differ from full async threads (Go Goroutines / Node.js Event Loop)?

Incident Scenario: Architecting an asynchronous HTTP crawler in PHP capable of downloading 500 web pages concurrently without spawning 500 blocking PHP-FPM processes.
748 views • Direct Permalink

Fibers: Full-Stack Stackful Coroutines

A Fiber in PHP 8.1+ represents an interruptible function with its own call stack:

  • Can be paused (Fiber::suspend()) and resumed ($fiber->resume()) from anywhere in the call hierarchy.
  • Cooperative Multitasking: Unlike OS threads, Fibers do NOT run in parallel across CPU cores. They yield execution cooperatively.
$fiber = new Fiber(function (): void {
    $value = Fiber::suspend('paused state');
    echo "Resumed with: {$value}\n";
});

$result = $fiber->start(); // Returns 'paused state'
$fiber->resume('new value'); // Outputs: Resumed with: new value

Framework Ecosystem

Fibers provide low-level primitives utilized by async engines like Revolt, Amphp v3, and ReactPHP to eliminate "callback hell" while keeping synchronous-looking code.

Tags: #Fibers #Async PHP #Coroutines #Concurrency #EventLoop
MySQL Tuning, Indexing & Concurrency 5-8 Years (Senior) Hard Production Scenario

How do you interpret MySQL `EXPLAIN ANALYZE` output to diagnose `Using filesort` and `Using temporary`?

Incident Scenario: An analytical query grouping and sorting orders was spilling to disk (`Using temporary; Using filesort`), consuming 100% disk I/O.
505 views • Direct Permalink

Diagnosing EXPLAIN ANALYZE

  • Using filesort: MySQL cannot use an index to satisfy the ORDER BY clause and must perform an extra sorting pass in memory (sort_buffer_size) or on disk.
  • Using temporary: MySQL creates an internal temporary table (in RAM or disk) to hold intermediate results, common with GROUP BY and DISTINCT on non-indexed columns.

Remediation:

  1. Create a composite index covering both the filter and the order:
    CREATE INDEX idx_merchant_created ON orders (merchant_id, created_at DESC);
    
  2. When query runs WHERE merchant_id = 5 ORDER BY created_at DESC, MySQL reads pre-sorted index nodes directly without filesort or temporary tables.
Tags: #EXPLAIN ANALYZE #filesort #Temporary Table #Performance
PostgreSQL Enterprise & Performance 5-8 Years (Senior) Hard Production Scenario

When should you use BRIN (Block Range Index) over B-Tree indexes for massive Time-Series and Log tables?

Incident Scenario: A B-Tree index on a 500-million-row `event_logs.created_at` table consumed 22GB of RAM. The server suffered memory starvation.
632 views • Direct Permalink

Why BRIN Indexes Are Revolutionary for Append-Only Data

For data inserted chronologically (where physical disk block ordering matches column value order), a BRIN index stores only the minimum and maximum value for each physical page range (e.g. 128 pages):

  • Index Size: BRIN index consumes only 50MB compared to 22GB for B-Tree (a 99.7% reduction).
CREATE INDEX idx_logs_created_brin ON event_logs USING BRIN (created_at);
Tags: #BRIN Index #B-Tree #Time-Series #Memory Optimization
System Design, Redis & Distributed Systems 10+ Years (Principal / Architect) Expert Production Scenario

How do you design a Real-Time Notification System delivering to 10M concurrent users with WebSockets and Redis Pub/Sub?

Incident Scenario: A flash notification must be pushed to 10 million active web and mobile users within 3 seconds of a global event announcement.
548 views • Direct Permalink

Architectural Blueprint

[Client Socket] ---> [Load Balancer / Nginx] ---> [WebSocket Gateway Cluster (Node/Go/Reverb)]
                                                          ^
                                                          | Redis Pub/Sub Cluster / Kafka
                                                          |
                                                 [Notification Service]

Core Architecture Components:

  1. Stateful Connection Nodes: Gateway instances maintain persistent TCP socket connections and keep a local in-memory lookup map of user_id -> [socket_fd_1, socket_fd_2].
  2. Channel Partitioning in Redis Pub/Sub: Broadcast messages are partitioned by tenant or topic channels (broadcast:global vs user:12345).
  3. Backpressure & Drop Policies: If a client's TCP socket buffer is saturated, drop non-critical status updates to prevent memory exhaustion on the gateway node.
Tags: #WebSockets #Redis Pub/Sub #Kafka #System Design #Scaling