Anything can be a message queue if you use it wrongly enough
xeiaso.net
xeiaso.net
We were previously working on a chat system called Envolve (https://www.envolve.com), that was 'Facebook Chat for any website'. A game that was using us for in-game chat created channels, used display: none on them, and passed game state through the chat.
We scratched our head, asked them why, and learned they wanted to focus on the frontend, not to deal with realtime message passing.
This led us to create a 'headless version' of our chat infra (re-written in Scala) that became the Firebase Realtime Database.
Just avoid the "not invented here" syndrome.
The antithesis of this is the contract model, when a client comes to you and asks you to make something specific, rather than describing what they need. In this case they are almost always wrong. They’ll rarely admit it unless you show them some amazing alternative, though.
Requirements = a set of problems to be solved. More often you get handed a diagram of a 12” tall Stonehenge sketched on a napkin with exceeding confidence that it will be 12 feet tall.
Then they yell at you for doing what they said.
(Probably not a real quote, and probably not even accurate.)
/s but maybe only half
What's interesting to me is that the oldest streets (ignoring the Main Street) in the local small town are the widest, because they needed to be able to turn around a team of horses and a carriage/wagon even when other wagons are parked on the side. The newer streets (but still 1940-50s) around are narrower because they didn't have to accommodate that.
A lot of the times this might be wrong but I think the interesting part is how that request gets handled.
In either case, the customers aren't stupid but instead are using the language and paradigm they are familiar with to describe their needs. Ford did indeed provide a faster/better horse, because the horse was the main means of non-human motive force in the US.
The technologist's job is to understand the universal of possible solutions and to understand the customer's needs and goals, which often includes interrogating and parsing the customer's language/worldview, and craft a product that achieves those needs/goals (and doesn't introduce negatives that overwhelm the benefits).
It is correct that "Requirements = a set of problems", and therefore it does not make sense at all to repeatedly ask the client for a technical solution instead of asking for the problems to solve, and then be surprised that the client does not talk about problems anymore.
We recently got a support call from an upset client. A recent change had broken their integration, halting production.
This lead to some head scratching on our side, as we couldn't figure out what integration they were talking about.
Turned out they had paid some consultant quite a lot to script some tool similar to AutoHotkey to transfer data from their order system to our system. It would emulate copy pasting fields, tabbing along.
Our recent update had introduced a new field, thus screwing it all up.
As an aside, the "integration" used half an hour to transfer a single order due to how it did its work. An XML would have taken seconds tops.
It happens quite a bit - people solve the problem they have with what they know.
Webscraping will rise again.
At this point, wasn't banning him in the cards?
(Humans will really adapt anything into a weapon, including human lives themselves, especially in a total war)
* Poor Japanese fighter aircraft design philosophy (weak armoring, no emphasis on pilot survival).
* Poorly trained pilots (all the veteran, experienced pilots are dead because see above).
* Poorly maintained aircraft (insufficient supplies and manpower).
* Insufficient ordnance (insufficient supplies and manpower).
* Insufficient fuel stores (so a one-way sortie out was all they could afford).
* Insufficient food and drink (a pilot going out to kamikaze is one less mouth to feed).
* Fanatical and delusional military brass.
The Japanese predicted they were going against "dumb" timer-based anti-aircraft, which was probably two orders of magnitude less accurate and less effective, where their weak armoring would have been a good approach: if you think it will take 200 shots to bring down your planes, fielding twice as many units that could each be brought down by one lucky direct hit makes great sense. But if it only takes two shots, you need to be able to survive the shrapnel.
The strategy they put in motion in 1942 suddenly became obsolete in 1943, and it was too late to pivot.
If people CAN do something with your tool, they will.
The moment you say "yeah, no one is stupid enough to do that", they will.
Be ready for it!
One of the craziest cases of this I've seen was with a web-based survey application I was the principal engineer on in the mid to late 2000's. A big feature we implemented was the ability to create surveys to support multiple languages. To make translation easier for our customers to translate surveys outside of the application, there were ways to export/import the text strings as well as a standalone screen that allowed finding and editing them. Both of these were made easier by the fact that the strings had semantic identifiers like "/survey/question/choice" or similar.
Since this functionality worked so well, we also used it internally for all text in the application. As a convenience, both the import/export and edit screen were capable of editing these strings. One customer figured this out and, due to the naming, was easily able to identify the text for all screens and dialogs. They ended up completely modifying the application interface through this interface by editing text, adding HTML elements, and injecting CSS blocks. They added descriptive tutorial text, guides for users, and branded the application well beyond built-in functionality. It was pretty amazing.
Also, you can actually make it cost competitive if the object you store is the last n milliseconds of packets instead of one packet each. So, instead of incurring two API calls per packet, you incur two API calls per minimum buffering time. If S3 is zero-rated for any ingress/egress then you get “infinite” bandwidth for 4.22$ * 3 (for the active case) = 12.66$ a day if you are willing to accept 500 ms minimum latency, or ~600$ a day at a more reasonable 10 ms. If you are saturating even just a 1 Gb link for a whole day that is ~10,000 GB which would be ~700$ via the blessed channel, so you could very well come out ahead.
You could do even better if you out-of-band signal the readiness so you do not need to poll while idle. Then you only incur a cost while actively transmitting so as long as you average 1 Gb/s on the channel you should be coming out even or ahead with minimal latency impact.
> You could do even better if you out-of-band signal the readiness so you do not need to poll while idle.
S3 and its clones have "object lifecycle notifications", where you can be informed by a push-based mechanism whenever a new object is put into the bucket.
But — what do you have to do, to get these notifications?
Subscribe to a real message queue, that S3 puts these notifications into.
So using it here would be somewhat cheating ;)
Interesting. Thanks for sharing
https://learn.microsoft.com/en-us/azure/azure-sql/database/f...
If you want something that works "well enough" I'd say it's a reasonable choice.
Can't really think of a better way to ensure that a message is always sent if the DB transactions succeeds and is never sent if the DB transaction fails
Great talk on it from Citus Con 2022:
Queues in PostgreSQL | Citus Con: An Event for Postgres 2022 -- https://www.youtube.com/watch?v=WIRy1Ws47ic&list=PLlrxD0Htie...)
Citus is a horizontal scale out extension for postgres -- imagine the power of those two things together!
JK you don't have to imagine:
https://www.citusdata.com/blog/2018/01/24/citus-and-pg-partm...
https://github.com/starqueue/starqueue
The code is in there for Postgres, MS SQL and MySQL (which all support SKIP LOCKED) though at some point I abandoned all but Postgres.
If I was to write another message queue then I wouldn’t use a database, I’d use the file system based around Linux file moves, which are atomic. What I really want is a message queue that is fast and requires zero config, file based message queues are both…. better than a database.
[0] https://github.com/gchq/Bailo/tree/main/lib/p-mongo-queue
I found almost all message queues to be horribly complex to configure, debug and run. Even database queues require a lot of config, relative to using the file system.
I did actually write a file system based message queue in Rust and it instantly maxed out the disk at about 30,000 messages a second. It did about 7 million messages a second when run as a purely RAM message queue but that didn’t use file system at all.
It depends what you’re doing of course… running a bank on a file system queue wouldn’t make sense.
A fast message queue should be a tiny executable that you run and you’re in business in seconds, no faffing around with even a minute of config.
I just hate configuration in general.
Did you try an in-memory filesystem through tmpfs?
Bank transfers are done by a text file sent over FTP (file transfer protocol; circa 1971)
https://orientalbank.com/assets/Pdfs/ach/ACH_ORIGINATION_AGR...
Shouldn't a message send be worst case a CAS. It really seems like all the work around garbage collection would have some use for in-memory high speed queues.
Are you familiar with the LMAX Disruptor? Is is a Java based cross thread messaging library used for day trading applications.
I've experimented with using the file system for storing configuration data where each config value is a single file. Nested structures just use directories. The name of the file is the field name. The file extension is a hint about the data type contained within (.txt is obvious, but I also liked .bool). Parsing data is trivial. I don't need any special viewing or editing tools, just a file manager and text editor. You can see when a specific config value was changed by checking the file update time. You don't have to load the whole configuration just to access one field. And you could conceivably TAR up the whole thing if you wanted to transmit it somewhere.
I use it to configure little sub-projects in my personal website. I really like it, but I shudder to think of the complaining I'd hear from other developers if I ever used it in a work project, just because it's not whatever they've ever seen before and would require a moment of two of thinking on their behalf to get over ingrained habits.
Not a bad idea at all, but perhaps re-inventing a very old wheel?
[UI]
DarkMode=1
Theme=solarized
[Options]
Indent=4
InventMode=tabs
Whereas this file system config would have individual files per value. <user-home>/.config/<app-name>/UI/DarkMode.bool --> 1
It's a single byte file. You read the entire file contents and if it's not zero, it's true. The existence of the file tells you whether or not to use a default value. An INI file would have to be fully parsed before we know whether it contains a value for that config value. <user-home>/.config/<app-name>/UI/Theme.txt --> solarized
You read the entire file contents, trim leading and trailing whitespace and toLower for good measure if you want, then validate against your list of installed themes. Done. No goofy JSON or YAML parser in site.And what reinvention is there? If you're just using a system that already exists, you're not reinventing anything.
However, and this is a big drawback, once you have too many config files and you start reading and writing from different processes, you get into bottleneck situations quickly.
First of all, if you have multiple processes trying to read/write the same config, that's kind of suspect, and if file I/O is a bottleneck for your config system, that's a different suspicious situation. Why are your processes writing to the config so... often?
But regardless, I can't see how those problems get immediately better by storing that config in a single file. If anything, having it split across multiple files would improve the situation, as different processes that might only be concerned with different sections of the config won't need to wait on file locks from process unrelated to their concerns.
Anyway it’s an elegant idea. Silly to have dozens of config file formats when the fs already has everything it needs. We have xattr too.
The flaw on the OS level is that it is hard to get everyone to change. For new apps not a problem, and any performance concerns are no longer an issue for config.
If you want to reach people who can actually help, you probably want to check this link:
[0] Why take hundreds of photos of Honda Civics in red, green, blue, and black when you already have a dozen in white?
Inasmuch as you trust your db's locking correctness it eliminates the concurrency issues. You can very naively have n workers pulling jobs from a queue not stepping on each-other.
Hell, if it’s not an RDBMS then it’ll be Redis (at a much greater expense for a managed instance). I’ve seen that setup in the Ruby world far more often than using a dedicated message queue.
It's a perfectly apt message queue, just a bit heavyweight. But if it's "light enough", it comes "for free" with many OSes.
As long as you keep it internal-only, get a reliable server that doesn't do any anti-spam shit (AKA, nothing from MS or any other large company), doesn't use some unreliable proprietary database (again no MS), and have a reliable journaled disk, your only important failure mode will be losing disks. That's an easy failure mode to deal with.
You also need to add misbehaving clients on your list of things not to use with a message-queue, just opening the queue's folder on Outlook to inspect it may be enough to completely corrupt it (Outlook will happily reorder, even rewrite, header fields of incoming messages, replicate messages to infinity, or who knows what else).
I'd be worried to have a message queue that is compatible with such a cursed ecosystem and transport protocol.
It was so old that the 1u case started to droop in the middle. (it was an sparc something or other with real SCSI ultra 320 drives in them)
I fill in the order form and post it. They mail back an invoice.
I fax the order form, they fax back an invoice.
My computer sends the order form in a structured way over email.
My computer sends the order form in a structured way over http.
And that's why many large telcos and banks still use ebXML in their B2B transactions. It's fundamentally the same business process and logic it's always been, with glacially slow improvement in performance over time.
It basically evolved from when applications from their original customer facing site were emailed and manually entered into the back-office system by a human. They were looking to automate this with a minimum of changes to too many of the moving parts at once, so I reformatted the sent email to contain an XML payload so the new back-office automation could read and process it (and in a pinch, a human could still review any problem applications) using Java's mail APIs.
Things evolved, the front-end web site got replaced with a Wordpress site, but the email message queue kept working for a long time. In the last year or so it was getting more and more onerous though. Reconciling information between the front-end and the mail box showed not all emails were being delivered, and authentication to gmail was becoming more and more of a burdensome moving target.
I just recently replaced the whole thing with an API call made from the back-office to the Wordpress site to access the stored data. (The original site didn't store, just emailed, which was why this was not an option historically.)
If you want to see how I did it, view source and search "gaslight".
https://youtube.com/watch?v=JcJSW7Rprio
It's better to go in unspoiled so I won't reveal any details.
...of course if that's all there were to it it wouldn't be interesting, but I won't reveal what the rest is as per your suggestions. :)
Something like: read the 54th line of this file hosted at xx address.
Then a submission could look like:
1. FTP a file to a server with the address.
2. the server reads the file and spins up a VM.
3. The VM polls an endpoint to download code to pull the address.
4. The code downloads the file and splits it into a single file per line.
5. A script loads all the files into an array and accesses array[53] to get the answer.
...you get the ideaSee also:
* Microservices
* "Web scale"
* Kubernetes
* Cloud computing
(You could use ethernet hops, they just didn't score points, so say you had some ethernet-to-whatever bridge, only the 'whatever' segment would count.)
Over the years, we saw physical proof that a T1 circuit would in fact run over barbed wire, we had a human-in-the-loop following a DDR-esque stream of arrows to stomp on a pad that encoded data from one hop to the next, we had a writable RFID tag stuck to the front bumper of an R/C car that would drive back and forth between readers...
Notacon was a hack-tech-art-music-demoscene conference in Cleveland, Ohio that ran from 2003 to 2014. I knew some of the organizers and got heavily involved in volunteering and setup for the event.
The drive from my home north of Detroit to Cleveland is a couple hours, so I carpooled with another Michigander making the trip, a guy who ran large parts of the campus network at MSU. I was in telecom, mostly slinging SONET networks at the time, he was mostly Ethernet, but adjacent to a lot of other technologies. We spoke just enough of each other's language to have a lot to learn from each other.
One year (I think it was 2005) in the car, we got to talking about transport networks, and lamenting the fact that "traceroute hides all the fun stuff"; it only shows IP-aware hops that decrement the TTL, and there could be thousands of miles of glass and hundreds of pieces of equipment, which considered the IP traffic to be "payload" and thus would never dare to alter it, between two hops that show up in a traceroute. (Plenty of otherwise-bright LAN engineers might naïvely assume that a packet leaves their router in Chicago and just arrives at another router in Denver because there was just a long, long piece of glass between them -- I think a lot of people have inflated ideas of fiber's capabilities because they're ignorant of the dozens of payload-transparent transport nodes and repeaters handling their circuit between the hops they see.)
"Wouldn't it be fun", we mused, "to somehow shine some light on all those other networks that aren't IP, aren't ethernet, aren't visible to the normal user?" And as the miles ticked by, Anything but Ethernet was born. We proposed it to Notacon's organizers, who gleefully encouraged us to take it and run with it. I'm not sure how it ended up being mostly my baby, but I ran around and found sponsors for prizes, spent the year needling potential contestants into actually building the crazy stuff they verbalized while couched in hypotheticals, and then emceed the chaos when the conference weekend and judging time came around.
This was pre-hackerspace, when all our nerd energy for the year was focused on one or two insane weekends (many of us also attended Penguicon or Defcon). So, extra cycles were less likely to be otherwise spoken for, and a few folks were highly motivated by the contest's appreciation of perverse, obscure, flashy, and MacGuyvered hacks.
My greatest regret looking back on the whole thing is that I didn't put more emphasis on recording and documenting the insanity. That wasn't valuable at the time -- it existed in and for a short-duration event -- but it would be amazing to look back on more of it now.
On the topic of message queues, I wonder if anyone ever designed a mechanical, asynchronous hardware IPC mechanism based on tape. Imagine: an endless-loop tape that stretches between a "sender" tape-drive on one machine, and a "receiver" tape-drive on another machine; with each tape drive locally tensioning the tape as it passes through, but letting it hang slack outside the drive; with two tape-width buffer boxes in between the two drives, for taking up the slack; and where each tape-drive has a strain gauge on its input-end capstan.
With this design, you'd never need to seek the tape (backward, at least) — the receive head would just read the tape forward at whatever speed it could until it ran out of slack in the tape (i.e. blocked on read); and the send head would write the tape forward at whatever speed it could until it ran out of slack (i.e. blocked on write.) The tape itself would be a literal, physical ring buffer.
- You’ll want writers to create a temp file and then rename it into place; otherwise your reader might pick up a file that’s only half-written. (POSIX rename() is atomic within a filesystem.)
- It’s also helpful to have an `in_process` folder, and a cronjob to send alerts if a task sits in that place too long. That way you can quickly catch crashes and other failures.
- You can have multiple readers; they cooperate by rename()ing the input file into in_process/ before they start working on it, and ignoring ENOENT (which indicates some other process got to it first).
- This pattern is great for loosely-coupled systems. In my case I was importing orders into a system that ran very slowly; once a reliable import queue was available new use cases kept presenting themselves, and it was very easy to add them; since the API was just “write a file in the correct format”, individual scripts could be written in whatever way was easiest for the particular task at hand. (It helped that the input format hadn’t changed in a couple decades; if it had needed changing a lot you’d want a more structured system. But this is the same as any distributed systems interface design.)
I wonder if the system is still in place. Last time I checked the Jenkins folder was occupying 270 GB (!) of the 10 TB shared FS, most likely because FS block size was 1 MB.
I wrote some VBScript that wrote a locking folder into a sub-folder in a network folder, then launched VNC targeting the proper VM. When VNC was closed, the script would complete and delete the locking folder. That let us know what was available and when. I always thought it was hacky, but at ~60 lines it's incredibly simple and has never really failed.
Impractical, yet possible ways to store data is an exciting satire genre for me now.
The Cardio rate control library is cool, https://pkg.go.dev/within.website/x/cardio this library would be a great problem for using a neural net to model a PID loop.
https://www.semanticscholar.org/paper/A-Design-of-FPGA-Based...
https://www.semanticscholar.org/paper/Self-Tuning-Neural-Net...
ok, what the good parts of the internet used to be like.
I also love that its highlights an AWS dark pattern. more, more I say.
> <Cadey> Hello! Thank you for visiting my website. You seem to be using an ad-blocker. I understand why you do this, but I'd really appreciate if it you would turn it off for my website. These ads help pay for running the website and are done by Ethical Ads. I do not receive detailed analytics on the ads and from what I understand neither does Ethical Ads. If you don't want to disable your ad blocker, please consider donating [snip] or sending some extra cash to [snip] or [snip]. It helps fund the website's hosting bills and pay for the expensive technical editor that I use for my longer articles. Thanks and be well!
Given latency and bandwidth differences, that's like saying that it's slightly slower to transport water by driving standard, 1-gallon jugs between the US east and west coasts than it is to transport it a few miles using a tanker truck.
On second thought it seems likely that some charlatan has already years ago raised a couple of millions in an ICO for such a project. “We’re making the entire Internet web3-compatible!”
Someone submit it as "IPv8" immediately.
IPv4?
But seriously, I appreciate that the blog was written using IPv6, not some other old and deprecated legacy tech.
How can something be reduced over 100% What is it that they actually mean here?
I like that they started out by talking about $0.07/G cost and went through the whole exercise before pointing out what immediately came to mind for me when they started pushing bytes in and out of S3.
In contrast, what’s where on the stack can often be (and often must be) known statically by the compiler and accessed directly, even moved entirely out of memory and into a register. (It’s possible to do this with suitably constrained dynamic allocations, but the optimization is much harder.)
Or cross-Country... as in two Countries that are geoblocked from one another...
>"This lets you have a worker in us-east-1 communicate with another worker in us-west-1 without having to incur the high bandwidth cost per gigabyte when using Managed NAT Gateway."
Simplified algorithm for bypassing geoblock via the above method:
1) Select a cloud storage provider (could be any cloud storage provider or shared persistent storage platform; doesn't necessarily need to be Amazon/S3) that works or does business in two countries, Country A and Country B, where normal IP traffic is geoblocked between Country A and Country B.
2) Use shared cloud storage objects/buckets/rows (call them whatever you will, "keyed persistent storage discrete thingies" for lack of a better term!) as the article suggests, to emulate IP traffic between user A in Country A and user B in blocked country B...
3) Combined with a P2P or other front end app that knows how to use this method of communication (along with code stubs, such that people could customize it to their own cloud storage provider or platform) if/when normal country-to-country IP communication is blocked for whatever reason (zombie apocalypse? <g>) could make a powerful future P2P communications tool, for lawful purposes...
Anyway, great article!
It updated or created an entry for each call. But if a buffer was already in the queue, it would write the most recent one into the existing slot. This had the effect of reducing the load by the multiple of the update rate. So if you had clients sending save game payloads every 30s and your queue depth is 2.5mins, then your write rate to disk is 1/5. I think.
But memcached wasn't Redis, this was pre-Redis, and memcached could have evicted any of those keys at any time. We gave it lots of space, it never GCd, we never needing to fix it. The game slide from above the fold and wasn't fun enough to be viable long term.
One of my proudest Scotty Engineering moments.
The content is not only relevant and hilarious, but I'd much rather personal blogs like this keep being updated instead of seeing the the sterile Medium or LinkedIn Pulse versions, usually written to impress future employers.
Zany visuals, doing things with your friends just because you can and writing up detailed accounts of it to share with everyone is the quintessential hacker culture. If Hackers' Cyberdelia was set in the 2020s, no doubt Mara would fit in.
I want to keep hacker culture alive by not accepting the gentrification of it. Hacker culture is queer, neurodiverse, furry, weaboo, and more. As a philosopher of the arts, that is the kind of culture I want to create more of. Not platitudes on LinkedIn. I want to create the kind of culture that celebrates art for the sake of art.
I may be "cringe", but I am free.
Words to live by, words to die for.
Please keep posting bangers!
I wonder if this part is satire, if so, how come? I definitely feel it should be much less.
I've been trying to play with the constants over the years to make the read time estimate more "accurate", but it's a tough nut to crack in general. So I can go over my numbers more accurately, how long did it take you to read it?
> In Linux, you can create a TUN/TAP device to let applications control how network or datagram links work. In essence, it lets you create a file descriptor that you can read packets from and write packets to. As long as you get the packets to their intended destination somehow and get any other packets that come back to the same file descriptor, the implementation isn't relevant. This is how OpenVPN, ZeroTier, FreeLAN, Tinc, Hamachi, WireGuard and Tailscale work: they read packets from the kernel, encrypt them, send them to the destination, decrypt incoming packets, and then write them back into the kernel.
(Edit: this comment made more sense when it was replying to a different complaint about the article; the parent comment seems to have been edited in the interim.)
Read (egress) packets from the TUN/TAP device.
Serialize them, assign sequence numbers, and upload them to S3.
On the recieve side, poll for newer objects (packets) in S3.
Write them to your TUN/TAP device.
---
Here, the TUN device is a router using S3 as gateway.
The meat of the article is how to create that tunnel using S3 for data transfer instead of using a more traditional VPN service.
Not that it ain't perfect like it is.
dunno if the effort would be worth it; but I'm thinking of people like me who read th eBOFH stories and decided they needed to learn more, to understand them properly. "First hit free, kids!"
> For four years, the database message queue formed the backbone of DigitalOcean’s technology stack.
The lesson I got from that article is that a database messaging system got them very far and was simple.