5 ms·
Looks interesting. > The call to hello.Greet looks like a regular method call That’s a departure from how components interact in boq — an internal and widely
by dti 3y ago
Looks interesting.
> The call to hello.Greet looks like a regular method call
That’s a departure from how components interact in boq — an internal and widely used production platform that has _some_ of the features from the paper. There component interfaces _are_ RPC interfaces (e.g., Stubby / gRPC + protocol buffers), and interaction between them is possible exclusively through the component interfaces. Hence it’s very explicit at the call site that an RPC is being made (which could happen to execute locally with all the standard RPC functionality — context and deadline propagation, etc.).
RPCs looking like regular method calls sound a bit scary (easy to miss in code reviews); I wonder if enforced naming conventions + IDE + code review tool support would be enough.
Edit: it seems to require to pass a context object, so the readers won't confuse it with a local call (from https://serviceweaver.dev/ https://serviceweaver.dev/):
sum, err := adder.Add(ctx, 1, 2)
---
Also, the paper claims that most benefits come from a non-versioned serialization format:
> Most of the performance benefits of our prototype come from its use of a custom serialization format designed for non-versioned data exchange [...]
However, I don’t understand why local RPC calls have to serialize protocol buffer messages — can’t they already pass them as-is to the local handler?
(disclaimer: a googler, no internal knowledge on ServiceWeaver)
- sanderjd 3y ago> However, I don’t understand why local RPC calls have to serialize protocol buffer messages — can’t they already pass them as-is to the local handler? I didn't read the paper in enough detail to know the answer to this, but mightn't this enable different implementation languages for different components? In my experience, it's difficult to accomplish reliably that without using a language-agnostic serialization format (like proto). Even if that's the goal, it seems like a handler could determine whether it could elide the serialization depending on the implementation details of the components.
- dti 3y agoI see I may have been unclear — I was surprised they don't use protobufs (which one should be able to pass as-is without serialization to the locally-deployed component), but apparently using a custom optimized format for non-local calls is the primary motivation (not local calls with grpc requiring serialization — that shouldn't be the case). However, now that I think again about the serialization format choice, it may result in a limitation on the size of monoliths (in terms of the number of people / teams contributing to it). When the number of contributors grow, the likelihood of bugs in a binary grows, and teams adopt more elaborate qualification processes, and also become much more sensitive to binary rollbacks as a remedy to discovering bugs in prod. Then they could institute policies like all changes should be protected by a feature flag (aka an experiment). If non-versioned serialization format is used, that means that the platform cannot possibly rollback a single component. However, using versioned serialization won't be enough on its own to support per-component rollbacks — it at least requires independent component qualification (where each component is tested against "stable" versions of other components) + rollback testing to make rollbacks A2 -> B2 to A2 -> B1 safe. I wonder if it's an explicit design choice — i.e., whether Service Weaver supports monoliths up to a certain organizational size (and then you should split into separate service weaver apps)?
- arter4 3y agoIn your experience, how does this kind of approach behave with asynchronous dependencies? Let's say you start from a codebase with three portions (call them services, modules, whatever): A, B, C, D. A sends a (synchronous) remote procedure call to B, which sends a message over a message bus which is also used by C and D. C and D do not talk to each other except over the bus. It sounds like this approach would identify the remote call dependency between A and B (which could be split into different deployment units), but not the message bus usage. Or, at least, it can't identify who is subscribing to a topic where B pushes its events. As a result, you would get two deployment modules: - A - B and "everything else" Which doesn't sound right. Am I missing something?
- dilyevsky 3y ago> RPCs looking like regular method calls sound a bit scary (easy to miss in code reviews); CORBA had the same issue. The call could take 10us or 10s and no way to tell by the user. This was ofc widely considered as huge design flaw.
- fizx 3y agoThey're claiming that the runtime will figure it out for you. It wouldn't be too surprising if this is the sort of thing that an optimizing compiler or query planner could do better than a human. If not, you're probably at the scale where performance regressions are caught and rolled back at early phases of rollout. Like most magic, it's either going to make things 100x better or 100x worse, depending on how leaky the abstraction is at its current state of maturity.
- dilyevsky 3y agoI'm going to (at least I should) design my application logic very differently if I know in advance the call might take a while or timeout completely. If I'm not offered that info during development time it's just going to turn into terrible mess in production. Ain't nothing any framework can do about it if the language itself lacks the semantics to express developer's constraints.
- fizx 3y ago> local RPC calls have to serialize protocol buffer messages They don't have to, they artificially added that constraint to make the benchmarks fairer. 5ms protobuf, 2ms custom, 0.4ms in-process