JoachimSchipper
Joined 17 years ago
Joined 17 years ago
Yes, associative arrays work well. I think it should even be possible to use bash associative arrays. But at that point you're no longer doing classic sh - awk is basically halfway to Perl. (And pretty awesome.)
In detail, for input "foo bar FOO qux FOO foo", we convert to
[1 foo, 2 bar, 3 foo, 4 qux, 5 foo, 6 foo]
(with newlines instead of commas, obviously), then sort by word (then line number) to
[2 bar, 1 foo, 3 foo, 5 foo, 6 foo, 4 qux]
at which point the uniq invocation gives <count> <first_line> <word>, i.e.
[1 2 bar, 4 1 foo, 1 4 qux]
albeit with an ugly mix of tabs and spaces. One final sort by <first_line> gives us
[4 1 foo, 1 2 bar, 1 4 qux]
and then it's just a matter of formatting the output:
[foo 4, bar 1, qux 1]
The generally-useful point is that the classic shell utilities really do work pretty well if you're operating within their paradigm, which isn't "throw everything in a hash table". (That's the paradigm of later scripting languages.)
tr < README.md --complement --squeeze-repeats '[:alpha:]' '\n' \
| tr A-Z a-z \
| nl \
| sort --key=2,2 --key=1,1n \
| uniq --skip-fields=1 --count \
| sort --key=2,2n \
| awk '{ print $3, $1 }'
(Where the final awk papers over the fact that we're mixing tabs and spaces here; obviously, awk is also good at doing the accumulation step, but uniq --count suffices here.)(I originally posted the above as a comment on lobste.rs, on this same article.)
I agree that less-than-milspec equipment should survive being installed in a home, but... this fiber didn't. https://news.ycombinator.com/item?id=46572962 seems to be relevant.
Thanks for writing this up! It was a very interesting read about a part of networking that I don't get to seriously touch.
That said: I'm sure you guys have thought about this a lot and that I'm just missing something, but "why can't every proxy probe every [worker, not application]?" was exactly one of the questions I had while reading.
Having the workers being the source-of-truth about applications is a nicely resilient design, and bruteforcing the problem by having, say 10k proxies each retrieve the state of 10k workers every second... may not be obviously impossible? Somewhat similar to sending/serving 10k DNS requests/s/worker? That's not trivial, but maybe not _that_ hard? (You've been working on modern Linux servers a lot more than I, but I'm thinking of e.g. https://blog.cloudflare.com/how-to-receive-a-million-packets...)
I did notice the sentence about "saturating our uplinks", but... assuming 1KB=8Kb of compressed critical state per worker, you'd end up with a peak bandwidth demand of about 80 Mbps of data per worker / per proxy; that may not be obviously impossible? (One could reduce _average_ bandwidth a lot by having the proxies mostly send some kind of "send changes since <...>" or "send all data unless its hash is <...>" query.)
(Obviously, bruteforcing the routing table does not get you out of doing _something_ more clever than that to tell the proxies about new workers joining/leaving the pool, and probably a hundred other tasks that I'm missing; but, as you imply, not all tasks are equally timing-critical.)
The other question I had while reading was why you need one failure/replication domain (originally, one global; soon, one per-region); if you shard worker state over 100 gossip (SWIM Corrosion) instances, obviously your proxies do need to join every sharded instance to build the global routing table - but bugs in replication per se should only take down 1/100th of your fleet, which would hit fewer customers (and, depending on the exact bug, may mean that customers with some redundancy and/or autoscaling stay up.) This wouldn't have helped in your exact case - perfectly replicating something that takes down your proxies - but might make a crash-stop of your consensus-ish protocol more tolerable?
Both of the questions above might lead to a less convenient programming model, which be enough reason on its own to scupper it; an article isn't necessarily improved by discussing every possible alternative; and again, I'm sure you guys have thought about this a lot more than I did (and/or that I got a couple of things embarassingly wrong). But, well, if you happen to be willing to entertain my questions I would appreciate it!
Still, it's nice to have at least some modern data; https://www.usenix.org/legacy/event/sec08/tech/full_papers/h... is awesome and has much more extensive measurements, but machines from 2007 are somewhat less relevant today.
Using an encoding that (like Protobuf) has multiple representations for a message may cause you problems if you switch implementations - sha256(encode(msg)) might yield different hashes on different implementations of encode().
But the main risk is an encoding that has multiple interpretations of a single encoding (e.g. sha256(encode("admin", "true")) == sha256(encode("admint", "rue"))), and Protobuf (can be unserialized, and thus) doesn't have that problem.
(In return, note that Cap 'n Proto's A -> D message makes it more obvious how A figures out whether the operation succeeded; I'm not quite sure how that works in the proposed diagram. I suppose the proposed system actually puts all messages in a system-wide database, which does solve the problem.)