今日已更新 339 条资讯 | 累计 19899 条内容
关于我们

标签:#systemdesign

找到 66 篇相关文章

AI 资讯

Want to Go Deeper?

Your LLM bill is exploding because 70% of user queries are semantically identical, yet your traditional cache ignores them completely. Even worse, if you implement semantic caching poorly, a single bad actor can poison your entire AI model's knowledge base, leading to incorrect or malicious responses for legitimate users. The Cost of Redundancy in LLM Systems Imagine running an AI-powered customer support chatbot for an e-commerce platform. Users frequently ask things like, "What's your return policy?", "How can I send this item back?", or "Do you offer refunds if I'm not satisfied?". To an LLM, these are distinct prompts, each triggering an expensive API call to OpenAI or Anthropic, costing you dollars per thousand tokens. On the surface, it looks like individual requests. But structurally, they all ask the same question with a similar intent. Your traditional HTTP cache, which relies on exact string matches, sees "What's your return policy?" and "How can I send this item back?" as entirely different requests. It misses the semantic similarity. So, for every variation of the same question, you're making a full LLM inference call. If 50-70% of your user queries fall into these semantically redundant categories, your LLM costs skyrocket. For a system handling millions of requests daily, this can quickly turn a profitable product into a money pit, all while adding unnecessary latency for your users. Semantic Caching: The "Fast Path" for LLMs Semantic caching solves this by moving beyond exact string matches. Instead of looking for an identical prompt, it looks for prompts that mean the same thing. It works by converting incoming user prompts into numerical vector representations (embeddings) and then performing a similarity search against a cache of previously embedded prompts and their corresponding LLM responses. Here's the workflow: USER PROMPT | v [ EMBEDDING MODEL ] -- Transform Prompt to Vector (e.g., [0.1, 0.5, -0.2, ...]) | v [ VECTOR DATABASE / CACHE ] | +--

2026-06-04 原文 →
AI 资讯

System Design - 6.CAP Theorem & PACELC, CAP Theorem & PACELC: The Most Important Trade-off in Distributed Systems

The Theorem That Changed How We Think About Databases In 2000, Eric Brewer stood at a conference and proposed a conjecture that would reshape distributed systems forever: "You can only guarantee two of these three properties at the same time: Consistency, Availability, and Partition Tolerance." Two years later, Seth Gilbert and Nancy Lynch proved it mathematically. It became known as the CAP Theorem — and every distributed system architect since has had to wrestle with it. It sounds abstract. But once you understand it, you'll never look at a database choice the same way again. You'll understand why Amazon DynamoDB and Google Spanner make opposite architectural choices. You'll know why your bank uses PostgreSQL while Twitter uses Cassandra. Let's break it down from first principles. The Three Properties C — Consistency Every read receives the most recent write, or an error. There's only one version of the truth — all nodes agree. Not the same consistency as ACID . CAP consistency (linearizability) means every read reflects the latest write across all nodes. ACID consistency means transactions don't violate database constraints. Different concepts, same confusing word. A — Availability Every request receives a non-error response — though it might not be the most recent data. The system is always up and answering. Note: "Available" in CAP doesn't mean "fast." It means "responds without error." A system that always returns a (possibly stale) answer is Available. P — Partition Tolerance The system continues operating even when network messages between nodes are lost or delayed. A partition is when part of your distributed system can't communicate with another part. The Unavoidable Truth: P Is Not Optional Here's the insight that makes CAP actually useful: In any real distributed system, partitions will happen. Networks fail. Cables get cut. Data centers lose connectivity. AWS regions go down. Since you must tolerate partitions (or have a single-server system, which does

2026-05-31 原文 →
AI 资讯

Append-only doesn't mean what you'd hope

Event sourcing gets sold on immutability. You don't update, you don't delete, you only append, so the history is permanent. It mostly isn't. The events are immutable because your code agrees not to touch them, not because anything actually stops it. Underneath they're still rows in Postgres, and rows have a DBA with write access. A migration that "cleans up" old data. A 2 a.m. query run against the wrong connection. A backup restored with slightly different bytes in it. Change one of those rows and a replay won't blink. The aggregate rebuilds, the projections rebuild, everything looks fine. Usually the first person to notice is a customer whose balance is off, and by then the trail is cold. Chain each event into the next The trick is small. Give every row two extra columns: a hash of its contents, and the hash of the row before it. #1 AccountOpened prev=00000… hash=70be4f… │ ▼ #2 AmountDeposited prev=70be4f… hash=796018… │ ▼ #3 AmountWithdrawn prev=796018… hash=6a0260… The hash is SHA-256(previousHash || json(payload)) . Nothing exotic. The point is that each hash depends on the one before it. Edit a payload and its hash stops matching. Rewrite that hash to cover for the edit, and now the next row's pointer is wrong. You can't fix one without breaking the next. About forty lines of it Appending an event hashes it together with the previous one: public HashChainedEntry Append ( object payload ) { var previousHash = _entries . Count == 0 ? GenesisHash : _entries [^ 1 ]. Hash ; var hash = ComputeHash ( previousHash , payload ); var entry = new HashChainedEntry ( _entries . Count + 1 , payload , previousHash , hash ); _entries . Add ( entry ); return entry ; } internal static byte [] ComputeHash ( byte [] previousHash , object payload ) { var payloadJson = JsonSerializer . SerializeToUtf8Bytes ( payload , payload . GetType ()); var combined = new byte [ previousHash . Length + payloadJson . Length ]; Buffer . BlockCopy ( previousHash , 0 , combined , 0 , previousHash .

2026-05-30 原文 →
AI 资讯

Java LLD: Designing a Thread-Safe Parking Lot with Strategy Pattern

Java LLD: Designing a Thread-Safe Parking Lot with Strategy Pattern Designing a parking lot is a staple of Java LLD and machine coding interviews, yet most candidates fail to write production-grade code. As an ex-FAANG interviewer, I've seen countless designs fall apart under concurrent traffic or when asked to support multiple slot allocation algorithms. If you're prepping for interviews, I've been building javalld.com — real machine coding problems with full execution traces. The Mistake Most Candidates Make Monolithic locking on the entire ParkingLot class: Using a global synchronized keyword on the entry method, which serializes all gate entries and destroys system throughput. Hardcoding slot-finding logic: Mixing spatial layout algorithms (like nearest-to-entrance or smallest-available-fit) directly inside the ParkingLot or Gate classes, violating the Open-Closed Principle. Thread-safety as an afterthought: Relying on raw List<Slot> iterations without synchronization, causing race conditions where multiple cars are assigned to the exact same physical slot. The Right Approach Core mental model: Decouple capacity management from slot selection by using a Semaphore for gate-keeping and the Strategy Pattern for thread-safe slot allocation. Key entities: ParkingLot , Gate , Slot , Vehicle , ParkingStrategy ( SmallestFitStrategy , NearestEntranceStrategy ), and StrategyFactory . Why it beats the naive approach: It isolates concurrency concerns (preventing overbooking) from business rules (how we choose a slot), making the system highly performant and easily extensible. The Key Insight (Code) public class EntryGate { private final Semaphore semaphore ; private final ParkingStrategy strategy ; public EntryGate ( int capacity , ParkingStrategy strategy ) { this . semaphore = new Semaphore ( capacity ); this . strategy = strategy ; } public synchronized Ticket park ( Vehicle vehicle ) { if (! semaphore . tryAcquire ()) throw new ParkingFullException (); Slot slot = strat

2026-05-29 原文 →
AI 资讯

Why I'm Building Decision Systems Instead of Prediction Systems

Most software projects focus on producing outputs. Most AI projects focus on producing predictions. But real organizations don't operate on outputs or predictions alone. They operate on decisions. A decision has consequences. A decision creates risk. A decision consumes resources. A decision changes the future state of a system. Over the last few months, I've been studying and building systems around a simple question: How can we make decisions more explainable, auditable, and repeatable? This led me toward concepts such as: event-driven architectures decision logging risk evaluation pipelines audit trails feedback loops operational intelligence systems Instead of asking: "Can we predict what will happen?" I'm becoming more interested in asking: "Can we explain why a decision was made?" and "Can we reproduce that decision six months later?" Current areas I'm exploring: Financial decision systems Risk infrastructure Event-driven architectures Blockchain compliance workflows Operational intelligence platforms One of the projects I'm currently building is an Event-Driven Decision Logging System (EDDL), designed to explore how organizations can record, audit, and replay critical decisions over time. Still learning. Still building. Still refining my understanding of how complex systems operate under uncertainty. Looking forward to sharing the journey here. systemsdesign #architecture #backend #fintech #softwareengineering #eventdriven #riskmanagement

2026-05-29 原文 →
AI 资讯

Read-Modify-Write isolation in NoSQL: the distributed-lock hell.

In part 1 , the single-document case was easy. In part 2 , two documents brought Write Skew, and we saw that even a native ACID transaction — snapshot isolation — lets it through. So teams reach for the reflex fix: a distributed lock — Redis-based, often a Redlock-style implementation. Acquire a lock on a key, do your Read → Modify → Write, release. On paper, you've finally serialized the critical section — operationally, at least. In practice, you've stepped on three mines. 1. Network latency Every guarded transaction now makes extra round-trips to Redis — before and after hitting your NoSQL store. You've doubled your coordination surface and taken a hard dependency on a second system being up, reachable, and fast on the hot path of every write. The "fast" database is now gated by the lock service. And the coupling bites harder than the average latency suggests: every Redis tail-latency spike becomes your write-latency spike — your p99 inherits Redis's p99 — and if Redis fails over mid-transaction, the lock you think you're holding can effectively vanish on the new primary, dropping you straight into the corruption case below. 2. Deadlock You can dodge deadlock entirely with a single coarse lock — but then every writer serializes on it, and you've thrown away the very concurrency you reached for NoSQL to get. So to keep throughput you go fine-grained, one lock per resource — and the moment an invariant touches more than one key (across this series, it always does), deadlock is back on the table: Transaction A locks key X, then needs Y. Transaction B locks Y, then needs X. Both block until timeout or intervention. The textbook cure — real deadlock detection, maintaining a wait-for graph across every lock holder and breaking cycles as they form — is a distributed-systems project in its own right: not something you bolt onto a cache you reached for precisely to save engineering time. So nobody builds it. Instead teams impose a standing discipline: always acquire locks

2026-05-28 原文 →