← Amazon Interview Insights

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

Senior
May 2026

Summary

Amazon system design round for a software engineering role. The whole thing was one big design question about memory management and it went deep fast, covering OS internals, concurrency, multi-tenancy, and ops concerns all in one shot.

Questions Asked (7)

Q1

Design an in-process memory usage monitor that switches an application between NORMAL and DEGRADED modes based on configurable thresholds, with hysteresis to prevent flapping between states.

System DesignTechnical Trade-offs
Author's notes

This is where I spent most of the session.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements: what memory metric (heap, RSS), thresholds, and mode behaviors. Then design a state machine with hysteresis using separate high and low thresholds, and discuss implementation details like sampling, thread safety, and integration points. Finally, address trade-offs such as latency, overhead, and configurability.

Pro tip: Emphasize that hysteresis prevents flapping by requiring the metric to cross a lower threshold to return to NORMAL, and consider adding a debounce time to avoid transient spikes. Also, mention that the monitor should be lightweight and non-blocking to avoid impacting application performance.

1. Clarify Requirements and Constraints

Ask about the memory metric (e.g., heap usage, RSS), how thresholds are configured, and what actions DEGRADED mode triggers. Confirm whether the monitor runs in-process and any performance constraints.

2. Design the State Machine with Hysteresis

Define two thresholds: high (to enter DEGRADED) and low (to return to NORMAL). Use a state variable and ensure transitions only occur when the metric crosses the respective threshold, optionally with a debounce period.

3. Implement Sampling and Monitoring

Choose a sampling strategy (e.g., periodic polling using a scheduled executor) and a memory metric source (e.g., Runtime.getRuntime() or MemoryMXBean). Ensure thread safety and minimal overhead.

4. Integrate with Application Modes

Define how mode changes propagate (e.g., via callbacks, listeners, or a shared state object). Discuss how the application reacts to DEGRADED mode (e.g., shedding load, reducing cache size).

5. Discuss Trade-offs and Edge Cases

Address trade-offs: sampling frequency vs. overhead, threshold tuning, handling memory spikes, and ensuring the monitor itself doesn't cause memory issues. Consider configurability and testing.

Key Points to Mention

  • Hysteresis: separate high and low thresholds to prevent rapid state flapping.
  • Debounce or cooldown period to avoid transient spikes triggering mode changes.
  • Choice of memory metric: heap vs. non-heap, used vs. committed, and how to obtain it (e.g., MemoryMXBean).
  • Thread-safe implementation: use atomic variables or synchronized blocks for state transitions.
  • Low overhead: sampling frequency and lightweight checks to avoid performance impact.
  • Configurability: thresholds and sampling interval should be externally configurable (e.g., via properties or environment).

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

Q2

How would you design the API surface for this system, specifically setThresholds, getState, and registerCallbacks, and what actions should trigger on mode transitions like cache eviction, request rejection, or batch slowdown?

API & IntegrationsSystem Design
Author's notes

I talked through the callback registration pattern and mentioned thread safety concerns around concurrent callback invocation.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the system's purpose and the roles of the three API methods, then propose a clean, consistent interface design that separates configuration, state querying, and event subscription. Finally, map each mode transition to concrete, idempotent actions that balance performance, correctness, and operational safety.

Pro tip: Emphasize idempotency and observability: make setThresholds safe to call repeatedly, and ensure every transition emits metrics and logs so you can debug production issues. Also, consider versioning the API to allow future evolution without breaking clients.

1. Clarify requirements and context

Ask questions to understand the system's scale, consistency needs, and what 'mode' means (e.g., normal, degraded, overload). Identify who calls these APIs and how often.

2. Design the API signatures

Define clear, minimal signatures: setThresholds(thresholds) returns success/error; getState() returns current mode and metrics; registerCallbacks(callbacks) accepts a map of transition handlers. Use idempotent, thread-safe designs.

3. Define mode transitions and triggers

Specify the states (e.g., NORMAL, EVICTING, REJECTING, SLOWDOWN) and the conditions that cause transitions, such as error rate, latency, or queue depth exceeding thresholds.

4. Map actions to transitions

For each transition, decide the concrete actions: cache eviction (e.g., LRU eviction of cold entries), request rejection (e.g., return 429 with Retry-After), batch slowdown (e.g., increase batch interval or reduce batch size). Ensure actions are reversible when returning to normal.

5. Address cross-cutting concerns

Discuss idempotency, error handling, concurrency, observability (metrics, logs, tracing), and how to test transitions (e.g., chaos engineering). Mention backward compatibility and versioning.

Key Points to Mention

  • Idempotent and thread-safe API design, especially for setThresholds and registerCallbacks.
  • Clear separation of concerns: configuration vs. state query vs. event subscription.
  • Mode transition triggers based on metrics like error rate, latency, and resource utilization.
  • Concrete actions: cache eviction policies (LRU, LFU), request rejection with proper HTTP status codes, and batch slowdown strategies.
  • Observability: emit metrics and logs on every transition for debugging and alerting.
  • Graceful degradation and recovery: ensure actions are reversible and the system can return to normal mode.

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

Q3

Compare different approaches to sampling memory usage across Linux and macOS: polling process RSS, using OS memory-pressure notifications, and reading container or cgroup signals. What are the tradeoffs?

Technical Trade-offsSystem Design
Author's notes

Honestly the cgroup part tripped me up.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by framing the problem: you need to monitor memory usage across Linux and macOS, considering portability, accuracy, overhead, and responsiveness. Then compare the three approaches (polling RSS, OS memory-pressure notifications, cgroup signals) across dimensions like accuracy, latency, overhead, and platform support. Conclude with a recommendation that balances trade-offs for the specific use case, such as using cgroup signals in containers and memory-pressure notifications on macOS for proactive management.

Pro tip: Mention that polling RSS is simple but can miss spikes and has overhead, while memory-pressure notifications are more efficient but platform-specific; cgroup signals are essential in containerized environments but require Linux. Emphasize that the best approach often combines methods for robustness.

1. Clarify requirements and constraints

Identify the goal: are you monitoring for debugging, autoscaling, or OOM prevention? Consider portability, overhead, latency, and accuracy needs.

2. Describe polling process RSS

Explain how it works: periodically read /proc/[pid]/statm or use psutil. Discuss trade-offs: simple, cross-platform, but high overhead if frequent, can miss short spikes, and RSS includes shared memory.

3. Describe OS memory-pressure notifications

Cover Linux (e.g., PSI, cgroups v2 memory.pressure) and macOS (dispatch sources, memory pressure events). Trade-offs: low overhead, event-driven, but platform-specific and may not give per-process details.

4. Describe container/cgroup signals

Explain reading cgroup v1/v2 memory.stat, memory.events, or memory.pressure. Trade-offs: accurate for containers, low overhead, but Linux-only and requires cgroup access.

5. Synthesize and recommend

Compare across dimensions and suggest a hybrid approach: e.g., use cgroup signals in containers, memory-pressure notifications on macOS, and fallback to polling for per-process detail. Highlight that the choice depends on the environment and goals.

Key Points to Mention

  • Polling RSS: cross-platform but overhead, latency, and shared memory inclusion; can miss spikes.
  • Memory-pressure notifications: event-driven, low overhead, but platform-specific (Linux PSI, macOS dispatch sources) and may lack per-process granularity.
  • Cgroup signals: precise for containers, low overhead, but Linux-only and require cgroup v2 for best features.
  • Trade-offs: accuracy vs. overhead, latency vs. responsiveness, portability vs. platform-specific optimizations.
  • Hybrid approaches: combine methods for robustness, e.g., cgroup signals for containers, memory-pressure for host, polling for detailed per-process metrics.
  • Amazon context: consider scalability, cost, and integration with existing monitoring systems like CloudWatch.

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

Q4

How would you extend this system to support multi-tenant memory budgets where individual components register their own limits and the system enforces them independently?

System DesignTechnical Trade-offs
Author's notes

Good question to get.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the current system architecture and the requirements for multi-tenant memory budgets, then propose a design where each component registers its memory limit with a central budget manager that enforces limits independently. Discuss trade-offs such as isolation, fairness, and overhead, and explain how you would handle enforcement, monitoring, and failure scenarios.

Pro tip: Emphasize tenant isolation and fairness—Amazon cares deeply about not letting one tenant impact others. Also, mention how you would handle enforcement without introducing single points of failure or significant latency.

1. Clarify Requirements and Constraints

Ask questions to understand the current system, tenant definition, memory budget granularity, enforcement strictness, and performance requirements.

2. Design Registration and Budget Management

Propose a central budget manager where components register their limits, and the manager tracks usage per tenant and component.

3. Enforcement Mechanism

Describe how limits are enforced independently, e.g., via quotas, throttling, or rejection, and how to handle overages without affecting other tenants.

4. Monitoring and Adaptation

Explain how to monitor memory usage, alert on violations, and dynamically adjust budgets if needed, ensuring observability.

5. Trade-offs and Failure Handling

Discuss trade-offs between strict enforcement and flexibility, and how to handle failures like budget manager downtime or component misbehavior.

Key Points to Mention

  • Tenant isolation to prevent noisy neighbor issues
  • Centralized vs. decentralized budget management and trade-offs
  • Enforcement strategies: hard limits, soft limits, and throttling
  • Scalability and performance impact of enforcement
  • Monitoring, alerting, and auditing for compliance
  • Failure modes and graceful degradation

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

Q5

What is your strategy for testing this system, including load tests, fault injection, and validating that threshold crossings and mode transitions behave correctly under concurrency?

System DesignTechnical Trade-offs
Author's notes

I talked about deterministic unit tests with a fake clock and injectable memory sampler, then property-based tests for threshold logic, then load tests that artificially inflate reported memory.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the system's critical components and failure modes, then outline a layered testing strategy that covers unit, integration, and end-to-end tests. Emphasize how you simulate realistic load and inject faults to validate threshold crossings and mode transitions under concurrency, using tools like chaos engineering and load testing frameworks.

Pro tip: Tie your testing strategy to business impact: explain how each test type mitigates specific risks (e.g., revenue loss from downtime) and how you automate and integrate tests into CI/CD for continuous validation.

1. Identify critical paths and failure modes

Map out the system's key components, dependencies, and potential failure points, especially those involving thresholds and mode transitions. Prioritize testing based on business impact and likelihood of failure.

2. Design a layered testing approach

Define unit tests for individual components, integration tests for interactions, and end-to-end tests for full workflows. Include specific tests for threshold logic and mode transitions under normal and edge conditions.

3. Plan load and stress testing

Use tools like JMeter or Locust to simulate expected and peak loads, measuring latency, throughput, and error rates. Validate that thresholds trigger correctly under load and that mode transitions remain stable.

4. Incorporate fault injection and chaos engineering

Introduce failures (e.g., network latency, service crashes) using tools like Chaos Monkey to test resilience. Verify that the system gracefully handles faults and that threshold crossings and mode transitions behave correctly under concurrent failures.

5. Automate and monitor in production

Integrate tests into CI/CD pipelines for continuous validation. Implement canary deployments and production monitoring to detect issues in real-time, with rollback strategies for safe releases.

Key Points to Mention

  • Concurrency testing: use tools like JMeter or Gatling to simulate concurrent users and verify thread safety of threshold logic.
  • Fault injection: leverage chaos engineering principles to test system behavior under failures, ensuring graceful degradation.
  • Threshold validation: test boundary conditions (e.g., just below/above threshold) and ensure correct triggering under load.
  • Mode transition testing: verify state changes are atomic and consistent, especially during concurrent operations.
  • Observability: instrument metrics, logs, and traces to monitor threshold crossings and mode transitions in real-time.
  • Automation: integrate tests into CI/CD and use canary releases to catch regressions early.

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

Q6

How do you handle concurrency and thread safety in this design, and what are the failure modes if the monitoring thread itself crashes or stalls?

System DesignAlgorithms & Data Structures
Author's notes

Went with a single writer/multiple reader model using a read-write lock around state.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by outlining the concurrency model (e.g., locks, actors, lock-free structures) and how it ensures thread safety for shared state. Then, discuss the monitoring thread's lifecycle, including how it detects and recovers from crashes or stalls, and enumerate the failure modes and their impact on the system.

Pro tip: Emphasize that the monitoring thread should be treated as a critical component with its own health checks and failover mechanisms, and that its failure should not cascade to the main system. Mention using a watchdog or heartbeat mechanism to detect stalls and trigger recovery.

1. Describe the concurrency model

Explain how shared resources are protected (e.g., mutexes, read-write locks, atomic operations, or message passing) and why this choice is appropriate for the workload.

2. Detail thread safety mechanisms

Discuss specific techniques to avoid race conditions, deadlocks, and data corruption, such as lock ordering, immutability, or thread-local storage.

3. Explain monitoring thread design

Describe the monitoring thread's responsibilities, how it interacts with the main system, and how it is isolated to prevent interference.

4. Analyze failure modes

Enumerate what happens if the monitoring thread crashes or stalls: e.g., missed alerts, resource leaks, or system degradation, and how the system detects and recovers from these.

5. Propose mitigation strategies

Suggest ways to make the monitoring robust, such as watchdog timers, redundant monitors, or external health checks, and discuss trade-offs.

Key Points to Mention

  • Use of locks, semaphores, or lock-free data structures for thread safety
  • Deadlock prevention techniques (e.g., lock ordering, timeouts)
  • Monitoring thread isolation and resource limits
  • Watchdog or heartbeat mechanism to detect stalls
  • Redundancy and failover for the monitoring thread
  • Impact on system availability and data consistency if monitoring fails

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

Q7

How would you handle configuration persistence and rollback for threshold settings that are updated at runtime?

System DesignTechnical Trade-offs
Author's notes

I blanked for a second here near the end of the session.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements: how often thresholds change, the need for atomic updates, and rollback expectations. Then propose a design that separates configuration storage from application logic, using a versioned, transactional store with audit trails and a rollback mechanism. Finally, discuss trade-offs between consistency, availability, and complexity, aligning with Amazon's leadership principles.

Pro tip: Emphasize the importance of idempotent updates and safe rollback to avoid cascading failures, and mention how you would test the rollback path in production-like scenarios.

1. Clarify Requirements

Ask about update frequency, consistency needs, rollback triggers, and who can change thresholds. This shows you don't jump to solutions.

2. Design Persistence Layer

Propose a versioned configuration store (e.g., DynamoDB with versioning, or a database with audit logs) that supports atomic updates and maintains a history of changes.

3. Implement Runtime Updates

Describe how the application fetches and caches configuration, with a mechanism to detect changes (e.g., polling, pub/sub) and apply them without restart.

4. Rollback Strategy

Explain how to revert to a previous version: either by restoring a snapshot or by applying a compensating change, ensuring the rollback is atomic and logged.

5. Discuss Trade-offs and Monitoring

Cover trade-offs like consistency vs. latency, and mention monitoring/alerting for configuration changes and rollback events.

Key Points to Mention

  • Versioning and audit trails for configuration changes
  • Atomic updates and transactional guarantees
  • Caching and cache invalidation strategies
  • Rollback mechanisms (snapshot vs. compensating transactions)
  • Monitoring and alerting for configuration drift
  • Trade-offs between consistency, availability, and complexity

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