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.
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
Interesting. Thanks for sharing
[0] Why take hundreds of photos of Honda Civics in red, green, blue, and black when you already have a dozen in white?
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.
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.)
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.
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.
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.
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!
- 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.
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 idea(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...
See also:
* Microservices
* "Web scale"
* Kubernetes
* Cloud computing
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.)
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 ;)
If you want to see how I did it, view source and search "gaslight".
(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.)
> 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.
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.
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. :)
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 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?
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!”
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.
Impractical, yet possible ways to store data is an exciting satire genre for me now.
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.
> 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.
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...
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.
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.