IT Operations, Service Management, and Support Questions
Running IT operations and technical support as a service function: ITSM/ITIL practices, service delivery, ticketing and change management, and tiered support with defined escalation paths from support to engineering. Covers operational and support metrics, service-level objectives, support tooling and remote support at scale, day-to-day operations optimization, and the service-management workflows and handoff mechanics that keep enterprise IT running predictably. The steady-state operations-and-support discipline, distinct from acute incident response.
Design a Kubernetes rollback system that safely handles deployments with associated database schema changes. Requirements: support 10k deployments/day, allow aborting rollouts, minimize downtime, and ensure schema compatibility when rolling back or forward. Describe deployment strategy, migration patterns, and safety checks before rollback.
Sample Answer
Requirements & constraints:
- 10k deployments/day → highly automated, low-latency pipelines
- Abortable rollouts, minimal downtime
- Safe schema compatibility when rolling forward/back
High-level approach:
- Use GitOps-driven CI/CD (ArgoCD/Flux) + Kubernetes Deployments and CRD-managed Rollout objects (e.g., Argo Rollouts or Flagger) to control canary/blue-green and support aborts.
- Decouple code deploy from irreversible schema migrations. Enforce backward/forward-compatible migrations.
Deployment strategy:
- Canary-first with progressive traffic shift:
- Deploy new pods behind a Rollout CRD with phases: 1%, 5%, 25%, 75%, 100% over automated metrics checks.
- Automatic abort on SLO breaches, error spike, or custom health probes. Manual abort option in UI/CLI to rollback to previous ReplicaSet.
- Blue-green for major incompatible changes:
- Spin up green environment, run full integ & smoke tests, switch service selector/ingress atomically. Rollback = switch back.
Schema migration patterns:
- Phase 0 (Backwards compatible): Add new columns/nullable fields, additive indexes; deploy code that can read old/new columns.
- Phase 1 (Dual-read/write or feature-flagged writes): App writes both old and new columns or toggles writes via feature flags. Reads prefer new column if present.
- Phase 2 (Cleanup): After verifying no reads depend on old schema, remove old fields.
- For irreversible migrations (e.g., destructive ALTER), use blue-green + shadow-migration with data-copy to new table/schema and cutover.
Safety checks before rollback:
- Schema compatibility verification: run automated compatibility checks (liquibase/flyway dry-run plus custom rules) ensuring rollback target schema is compatible with current code path.
- Migration revertability marker: every migration must declare reversible? true/false; if irreversible, require blue-green and manual approval.
- Pre-rollback dry run: simulate rollback on a staging DB snapshot or use read-only shadow verification to detect broken FK/index constraints.
- Safety gates in CD: require passing canary metrics, DB sanity checks (row counts, migration status), and feature-flag state before allowing automated rollback.
- Backups & quick restore: automated consistent DB backups (logical and physical) and tested restore playbooks; store migration metadata versioning.
Operational considerations:
- Observability: request latency, error rate, DB errors, schema drift alerts, and migration metrics exposed to rollout controller.
- Automation: webhook-triggered aborts from monitors; automatic rollback if healthchecks fail for N minutes.
- Rate limits: batch deployments per team to avoid DB migration storms; use migration queues and leader election for running migrations.
- Runbooks & guardrails: RBAC on who can force irreversible rollback; chaos-tested rollback procedures.
This design balances speed (canaries), safety (compatibility checks, backups), and operational control (abort/blue-green for risky changes).
Implement or outline an algorithm (in Go or Python) that merges event timelines from multiple machines into a causally consistent order. Machines have clock skew and can miss events. Use Lamport timestamps or vector clocks in your design, explain the data structures, and show a small test example demonstrating ordering and limitations.
Sample Answer
To merge event timelines into a causally consistent order, use vector clocks to capture causality precisely (Lamport timestamps give partial order but can't detect concurrency as well). Approach: each machine tags events with its vector clock; the merger collects events and orders them by vector-clock partial order using topological sort: event A precedes B if A.v <= B.v and A.v != B.v. Concurrent events (incomparable) can be ordered deterministically by tie-breaker (machine ID, Lamport timestamp, or wall clock).
- Approach summary
- Each node maintains a vector clock (map[nodeID]int).
- On local event: increment own counter, attach copy of vector clock.
- On send/receive: merge vectors (element-wise max) and increment.
- Merger receives event records (eventID, nodeID, vectorClock, payload).
- Build DAG edges: for every pair (a,b), if a.v <= b.v and a.v != b.v then edge a->b.
- Topologically sort DAG; break ties deterministically.
- Python reference implementation (simple, O(n^2) comparisons):
from collections import defaultdict, deque
import functools
def leq(vc1, vc2):
# return True if vc1 <= vc2 element-wise
nodes = set(vc1)|set(vc2)
le = True
eq = True
for n in nodes:
a = vc1.get(n,0); b = vc2.get(n,0)
if a > b: return False, False
if a < b: eq = False
return True, eq
def build_order(events):
# events: list of dicts {'id','node','vc','payload'}
n = len(events)
id_index = {e['id']:i for i,e in enumerate(events)}
indeg = [0]*n
adj = [[] for _ in range(n)]
# build edges a->b if a.v <= b.v and not equal
for i,a in enumerate(events):
for j,b in enumerate(events):
if i==j: continue
le, eq = leq(a['vc'], b['vc'])
if le and not eq:
adj[i].append(j); indeg[j]+=1
# Kahn's topo sort with deterministic tie-breaker by (node,id)
q = deque(sorted([i for i in range(n) if indeg[i]==0],
key=lambda i:(events[i]['node'], events[i]['id'])))
out=[]
while q:
u=q.popleft(); out.append(events[u])
for v in adj[u]:
indeg[v]-=1
if indeg[v]==0:
q.append(v)
q = deque(sorted(q, key=lambda i:(events[i]['node'], events[i]['id'])))
if len(out)!=n:
raise RuntimeError("Cycle detected (shouldn't happen with vector clocks)")
return out
# small test
e1 = {'id':'e1','node':'A','vc':{'A':1},'payload':'A1'}
e2 = {'id':'e2','node':'B','vc':{'B':1},'payload':'B1'}
e3 = {'id':'e3','node':'A','vc':{'A':2,'B':1},'payload':'A2_receive_from_B'}
events=[e1,e2,e3]
for e in build_order(events):
print(e['id'], e['node'], e['vc'], e['payload'])
- Key concepts
- Vector clocks capture causality: A -> B iff A.v < B.v.
- Topological sort yields a causally consistent total order (preserves "happened-before").
- Complexity
- Building edges: O(n^2 * m) where m=#nodes in clocks (often sparse).
- Topo sort: O(n + e).
- Edge cases & limitations
- Missing events: if some events never arrive, partial order still valid for received events.
- Skew/clock: vector clocks don't rely on physical clocks.
- Scalability: vector clocks grow with cluster size; comparisons O(m). For many nodes, use dotted version vectors, version vectors with pruning, or use Lamport + additional metadata to reduce size.
- Deterministic tie-breaker imposes arbitrary ordering for concurrent events; application must decide acceptable policy.
Operational notes for SRE
- Ensure reliable event transport (retries, idempotence) to avoid missing events.
- Consider compaction of vector clocks for long-running systems.
- Monitor vector clock growth and merge frequency; expose metrics and alerts when vector sizes exceed thresholds.
The central monitoring/alerting stack is down during an ongoing incident. You have no dashboards. Outline a prioritized plan to triage service health and coordinate response using alternate data sources (host-level metrics, application logs, synthetic checks, network monitoring). Include how to keep stakeholders informed and how to bring monitoring back safely.
Sample Answer
Situation: Central monitoring/alerting (Grafana/Prometheus/Alertmanager) is down during an active incident and dashboards/alerts are unavailable. We must triage service health, coordinate responders, and restore monitoring without causing noise or blind spots.
Prioritized plan
- Triage & scope (first 5–10 min)
- Appoint Incident Commander and scribe; notify on-call rotation/channel with “monitoring-down” flag.
- Quickly enumerate critical SLO-bearing services and any customer-facing degradation reports.
- Use alternate telemetry (parallel tasks)
- Host-level metrics: SSH to representative hosts, run top/htop, vmstat, iostat, df, free to check CPU/memory/disk. Example: ssh host && sudo sar -u 1 3.
- Application logs: Tail recent logs (journalctl -u service -n 200, kubectl logs --since=10m) and grep for errors/exceptions/timeouts.
- Synthetic checks: Run health endpoints and transactions from multiple locations (curl -sS https://service/health; perform a checkout flow against staging/production stub) to validate functional paths.
- Network monitoring: Use ping/traceroute, ss/netstat, and load balancer / VPC flow logs to detect connectivity or DNS issues.
- Dependency checks: Verify downstream services (DB, cache) reachable (psql, redis-cli PING).
- Prioritize remediation actions
- If host resource exhaustion: restart services, scale up replicas, or divert traffic.
- If dependency failures: fallback to read-only mode, circuit-breaker, or failover DB.
- If networking/DNS: switch to secondary DNS/load balancer rules.
- Communication cadence
- Initial notification within 5 min with scope and owner.
- Status updates every 15 min (or sooner for escalations) on incident channel and to stakeholders: summary, actions in progress, next steps, ETA.
- Use a short public incident page if customer-visible, and update it every 30–60 min.
- Bring monitoring back safely
- Identify root cause (storage, collector crash, DB corruption, network).
- Restore collectors/ingesters in isolation (bring up read-only Prometheus instances or a temporary pushgateway) to avoid ingesting backlog spikes.
- Reconnect exporters one-by-one and validate metrics for a subset of services.
- Re-enable alerting incrementally: mute noisy alerts, re-enable low-noise high-priority alerts first, monitor for flapping.
- Rebuild dashboards from backups or regenerate essential panels; keep a pared-down “health” dashboard (host metrics, key app metrics, synthetic check results).
- Post-incident
- Run a blameless postmortem: timeline, root cause, gaps (e.g., single point of failure), and concrete mitigations (HA for monitoring, secondary alert path, runbooks).
- Implement improvements: automated synthetic fallback, alerting on monitoring health, runbook for being “monitoring-down”.
Key principles: act fast, focus on customer-impacting services, parallelize investigation, communicate frequently and clearly, and restore observability incrementally to avoid alert storms.
Compare metrics, logs, and traces for diagnosing intermittent, distributed failures. For each method give an example incident where it is the primary source of truth, explain how they complement each other, and discuss instrument overhead, sampling trade-offs, and data retention decisions for forensic value.
Sample Answer
Metrics, logs, and traces each play distinct but complementary roles diagnosing intermittent distributed failures.
Metrics
- What: Aggregated numeric time series (rates, latencies, error counts).
- Example incident: A customer-reported spike in 5xx rate for Service A every night between 02:00–02:15. Metrics (per-minute error rate, P95 latency) first reveal the recurring pattern and correlation with traffic/CPU.
- Strength: Fast detection, alerting, easy to aggregate and slice.
- Overhead: Low (periodic aggregation); cardinality explosion if high-label cardinality is allowed.
- Retention: Keep long-term (months) at coarse granularity for trend/forensics; keep high-resolution short-term (days/weeks).
Logs
- What: Event-level, textual records with context and stack traces.
- Example incident: The nightly spike’s root cause is an intermittent NullPointer thrown by a rare code path when a malformed payload arrives. Logs from affected instances contain the exception and payload ID — primary evidence for root cause.
- Strength: Rich context for forensic proof and debugging.
- Overhead: High if unfiltered; storage & ingestion costs grow rapidly.
- Sampling/Filtering: Index and retain full logs for error-level entries and sampled info/debug entries. Use redaction and structured logging to make queries efficient.
- Retention: Keep error/exception logs longer (months); debug traces short-lived unless tied to SLO breach.
Traces
- What: Distributed request-context spans showing causal call paths and timings.
- Example incident: Intermittent 500s only happen when request path hits Service B → C → D and a specific downstream call times out. A trace shows the exact span where the latency spike occurs and which downstream endpoint returned a malformed response.
- Strength: Pinpoints where latency/error occurs across services and provides per-request timeline.
- Overhead: Moderate to high per-request; can add significant latency/CPU if full sampling.
- Sampling trade-offs: Use adaptive sampling — keep all error traces, higher sampling for tail latency, probabilistic for normal traffic. Tail-based sampling preserves valuable outliers while limiting volume.
How they complement each other
- Workflow: Metrics detect anomalies and trigger alerts → traces surface causal path and timing for representative requests → logs supply payloads, stack traces, and environment context to confirm root cause. Metrics guide where to look; traces show how; logs show why.
Instrument overhead, sampling, and retention — practical guidance
- Instrumentation: Prefer lightweight metrics (histograms, counters) and structured logs. Offload heavy processing (e.g., JSON formatting) asynchronously.
- Sampling: Implement multi-tier sampling: keep 100% of errors, tail-based sampling for high latencies, reservoir/probabilistic sampling for normal requests. Ensure trace IDs propagate so sampled traces can be linked to logs/metrics.
- Retention: SLO-driven policy: retain high-fidelity data around incidents and breaches longer. Maintain aggregated metrics for long-term capacity planning. Archive logs/traces for compliance or extended forensics but move to cheaper cold storage with indexed pointers.
- Trade-offs: More retention and full sampling improve forensic power but cost storage, CPU, and query time. Use targeted instrumentation (feature flags for verbose logging), dynamic sampling, and burst buffers during incidents to capture needed data without constant overhead.
Final principle: design observability so metrics give early, low-cost signals; traces provide cross-service causality; logs provide definitive forensic proof. Tune sampling and retention by SLO risk, cost, and incident history.
Draft a parameterized YAML-style playbook/pseudocode for automating an incident runbook that: (1) creates a ticket, (2) collects latest logs from affected services, (3) runs predefined health checks, (4) attempts a safe restart of a service, and (5) posts results to a Slack channel. Show how you would parameterize for service name, environment, and escalation level.
Sample Answer
Approach: Use a parameterized YAML playbook (Ansible-style pseudocode) that accepts service_name, environment, escalation_level. Steps: create ticket, fetch logs, run health checks, attempt safe restart with checks & retries, post results to Slack and escalate if failures persist.
# incident_runbook.yml
vars:
service_name: "{{ service_name }}" # e.g., "auth-service"
environment: "{{ environment }}" # e.g., "prod", "staging"
escalation_level: "{{ escalation_level }}" # e.g., "pager", "email", "none"
ticket_priority_map:
prod: high
staging: medium
tasks:
- name: Create incident ticket
action: ticket_create
args:
title: "Incident: {{ service_name }} degraded in {{ environment }}"
description: "Automated runbook started"
priority: "{{ ticket_priority_map[environment] }}"
register: ticket
- name: Collect latest logs from affected hosts
action: fetch_logs
args:
service: "{{ service_name }}"
env: "{{ environment }}"
tail: 500
retries: 3
delay: 5
register: logs
- name: Run predefined health checks
action: run_health_checks
args:
service: "{{ service_name }}"
env: "{{ environment }}"
checks:
- readiness_probe
- latency_check
- error_rate
register: health
- name: Evaluate health and decide restart
when: health.status != "healthy"
block:
- name: Attempt safe restart (graceful) with drain
action: service_restart
args:
service: "{{ service_name }}"
env: "{{ environment }}"
method: graceful
max_wait: 60
register: restart_result
retries: 2
delay: 10
- name: If graceful fails, attempt force restart
when: restart_result.status != "ok"
action: service_restart
args:
service: "{{ service_name }}"
env: "{{ environment }}"
method: force
register: restart_result_force
- name: Compile runbook results
set_fact:
summary:
ticket: "{{ ticket.id }}"
logs_excerpt: "{{ logs.path }}"
health: "{{ health }}"
restart: "{{ restart_result | default(restart_result_force | default({})) }}"
- name: Post results to Slack channel
action: slack_post
args:
channel: "#incidents-{{ environment }}"
message: |
Incident {{ ticket.id }} for {{ service_name }} ({{ environment }})
Health: {{ health.status }}
Restart: {{ summary.restart.status }}
Logs: {{ summary.logs_excerpt }}
- name: Escalate if not recovered and escalation_level set
when: summary.restart.status != "ok" and escalation_level != "none"
action: notify_oncall
args:
level: "{{ escalation_level }}"
ticket: "{{ ticket.id }}"
details: "{{ summary }}"
Key points:
- Parameterized inputs for service, env, escalation.
- Safe restart: graceful first, forced fallback, retries and delays.
- Idempotent tasks and registers for traceability.
- Include log tailing and health checks before/after restart.
- Escalation driven by escalation_level.
Unlock Full Question Bank
Get access to all 43 IT Operations, Service Management, and Support interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.