Java Interview Simulation: Solving the Architecture Challenges of a Hotel Pricing System
This article walks through a detailed Java interview simulation where the candidate designs a high‑throughput hotel pricing service, covering business decomposition, Kafka event‑driven pipelines, cache‑aside consistency, HikariCP tuning, fault‑tolerant microservices, multi‑region disaster recovery, and AI recommendation gray‑release strategies.
The interview begins with a business‑level analysis of a hotel pricing platform, where the candidate breaks the end‑to‑end flow into five modules—supplier collection, price ingestion, real‑time cache, aggregation & routing, and monitoring—explaining why each module isolates failures, enables independent scaling, and aligns with Spring Boot multi‑module projects.
In the second round the focus shifts to Kafka. The candidate proposes an idempotent producer using enable.idempotence=true, acks=all, and a composite partition key hotelId|roomType to guarantee ordering per hotel‑room. Configuration snippets are provided for Spring Kafka:
spring:
kafka:
producer:
properties:
enable.idempotence: true
acks: all
linger.ms: 5
batch.size: 32768The design also includes a dead‑letter queue for failed messages and a consumer strategy that uses manual offset commits after successful processing.
The third round addresses data consistency. The candidate chooses a Cache‑Aside pattern: writes go to MySQL within a local transaction, then an outbox event is published to Kafka; a consumer updates Redis. Versioned keys ( priceId_version) and optimistic locking ensure that stale updates are rejected. Sample SQL for atomic stock reservation is shown:
UPDATE room_stock SET available = available - :qty
WHERE hotel_id = :hid AND room_type = :rt AND available >= :qty;During the fourth round the candidate tunes HikariCP. Key parameters such as maximum-pool-size: 60, minimum-idle: 10, connection-timeout: 30000, and max-lifetime: 1800000 are justified with a formula based on DB max connections and expected concurrency. Monitoring metrics (activeConnections, threadsAwaitingConnection, connectionTimeoutCount) are listed for early detection of pool exhaustion.
The fifth round explores stability and microservice governance. Layered protection is described: gateway‑level token‑bucket rate limiting, Resilience4j circuit breakers and bulkheads on critical services, and read‑only fallback to Redis when the database is saturated. The order of degradation under a 10× traffic spike is detailed, from immediate gateway throttling to gradual service fallback.
In the sixth round the candidate mitigates cache avalanche and penetration. A three‑tier cache (Caffeine L1, Redis L2, Bloom filter) is combined with random TTL jitter, async cache rebuild guarded by a distributed lock, and monitoring of cache_miss_rate and redis_used_memory. Pseudocode for the lock‑protected rebuild is included.
if (!redis.exists(key)) {
if (acquireLock("rebuild:"+key)) {
value = db.load();
redis.set(key, value, ttl);
releaseLock();
} else {
return fallbackOrWait();
}
}The seventh round designs an active‑active disaster‑recovery architecture. Traffic is routed by DNS/Gateway to the nearest region; Kafka MirrorMaker2 provides bidirectional topic replication; MySQL uses GTID‑based asynchronous master‑master replication with city‑based sharding; Redis employs async master‑slave sync with periodic checksum reconciliation. Lag monitoring (<500 ms) and Snowflake IDs guarantee idempotency across regions.
The eighth round introduces an AI recommendation service built with Spring AI and LangChain4j. Model versions are stored in Nacos; gray‑release is controlled by Spring Cloud Gateway rules that split traffic (e.g., 10 % to the new model). Sentinel time‑limiter and circuit breaker provide immediate fallback to cached recommendations, and Prometheus metrics (CTR, conversion rate) drive automatic rollback if the new model underperforms.
Finally, the ninth round ensures the core pricing API remains fast even when the AI service is slow. The AI call is made asynchronously with CompletableFuture and an orTimeout(800, TimeUnit.MILLISECONDS) guard; on timeout a cached recommendation is returned, while the async task still publishes results to Kafka for later updates.
CompletableFuture<AIResult> aiFuture = CompletableFuture.supplyAsync(() ->
aiService.getRecommendation(userId))
.orTimeout(800, TimeUnit.MILLISECONDS)
.exceptionally(ex -> fallbackResult());Together these steps illustrate a complete, production‑ready design that balances low latency, strong consistency, scalability, and observability.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ubiquitous Tech
A ubiquitous public account for pirate enthusiasts, regularly sharing curated experiences, tech learning, and growth insights. Currently publishing articles on AI RAG customer service, AI MCP technology, and open-source design. Personal free Knowledge Planet: Awakening New World Programmer.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
