Live data from Hacker News

Saving 100 terabytes of memory by optimizing 1.1.1.1's DNS cache

blog.cloudflare.com

221–230 of 303 posts

Re: Saving 100 terabytes of memory by optimizing 1.1.1.1's DNS cache

#221
post #153

Earlier quoted context omitted.

I wish more programming languages implemented record types as seen in databases, where dynamically sized fields are packed into a contiguous area of memory. The CloudFlare manually implemented a clumsy version of this. Wouldn’t it be nice for the compiler to manage this for you in the same way that your database engine does when it saves a “row”?

> dynamically sized fields are packed into a contiguous area of memory Are you able to explain this? Do you mean an N sized array where each entry is either a value or a pointer to a value where the 'pointed-to' values are after the end of the array? I'm trying to underatnd how you'd do this without having to parse M-1 elements to get the Mth entry if you did a [{size0, value0}, ....., {sizeN, valueN}] arrangement

There are various ways of implementing this, someone from a C programming background mentioned on option where the heap-allocated record objects aren't fixed size structs, but instead the allocated space is dynamically sized and the struct is just a prefix.

So logically you'd have the equivalent of:

    struct FooRecord {
        int fixed_sized_field;
        char some_other_field;
        string first;
        string last;
        string title;
    }
Physically the compiler would generate something like:

    struct FooRecord {
        long __length__;
        int fixed_sized_field;
        char some_other_field;
        char* first;
        char* last;
        char* title;
    }
Where 'first', 'last', and 'title' are sequentially stored after the struct in the heap memory.

There are variants of the above, of course. Instead of pointers the compiler could use lengths, offsets, or a pointer to the end of the variable length field -- this works because the beginning of the first field is at a fixed offset, and then pairs of pointers delimit the rest.

You can rely on the heap allocator to track the "__length__" instead, or you can encode it into the record explicitly to make "dynamic sized copies" simple.

Windows APIs generally work this way! You create a buffer, put a length in the first field, and then the API call writes a fixed-sized prefix followed by the dynamic-sized fields into the buffer. The 'length' is replaced too, so you know how many bytes to copy out without having to understand the structure.

Database engines go one step further and pack multiple "records" into a single "row". They typically store the fields "packed" at the start of the row with 16-bit length or offset markers at the end for the various dynamic sizes.

Something like:

    fixed_sized_field // Row #0
    some_other_field
    first
    last
    title
    fixed_sized_field // Row #1
    some_other_field
    first
    last
    title
    ... empty space ...
    next_offset      // always populated
    row#1_title_offset
    row#1_last_offset
    row#1_first_offset
    row#1_offset
    row#0_title_offset
    row#0_last_offset
    row#0_first_offset
    row#0_offset  // typically the constant zero

The idea here is that every length is the difference between pairs of sequential offsets. I.e. row#1_title has length (next_offset-row#1_title_offset).

Re: Saving 100 terabytes of memory by optimizing 1.1.1.1's DNS cache

#222
post #68

This is the right way to deliver software. Produce working product first, validate the idea, stabilize the business, start generating profit, and then you can start optimizing your costs. In fact optimization is by far the easiest part of the process because there are many system programming experts on this HN thread who consider these optimizations to be trivial.

Its a yes if you do not know the domain space, query patterns well enough and also if the cost of optimization or time for optimization may have detrimental impact to business. In this case it most likely means that the crowd in the room did not anticipate much on this in early phases and no one in the room pointed these things out. The irony is that these performance and disk numbers are heavily discussed as a part…

The fact that it took them 4 months to roll out does not mean this is the hard part: it's simply a coordinated rollout with incremental, staggered deployments and rate-limited migrations.

Changing data structures with that approach just takes its time as you avoid lock-step updates between components. Sure, by definition this type of development and deployment complexity is hard.

However, what I found the hardest is pushing engineers to adopt this evolutionary data structures mindset, and unless you do that right for the full team, someone will sneak in a backwards-incompatible change that blows the entire effort up.

So it is hard, but primarily for different-mindset-needed, and only then for technical complexity.

Re: Saving 100 terabytes of memory by optimizing 1.1.1.1's DNS cache

#223

Earlier quoted context omitted.

The way I usually prevent having to scale out to a bazillion systems is never getting more than 10 users.

The art of premature optimizations

And yet when Prof. Donald Knuth wrote that in 1974 paper[1] it was in this context:

> "The improvement in speed from Example 2 to Example 2a is only about 12%, and many people would pronounce that insignificant. The conventional wisdom shared by many of today's software engineers calls for ignoring efficiency in the small; but I believe this is simply an overreaction to the abuses they see being practiced by pennywise-and-pound-foolish programmers, who can't debug or maintain their "optimized" programs. In established engineering disciplines a 12% improvement, easily obtained, is never considered marginal"

also:

> "In the late 1960's we witnessed a "software crisis", which many people thought was paradoxical because programming was supposed to be so easy. As a result of the crisis, people are now beginning to renounce every feature of programming that can be considered guilty by virtue of its association with difficulties. Not only go to statements are being questioned; we also hear complaints about floating-point calculations, global variables, semaphores, pointer variables, and even assignment statements. Soon we might be restricted to only a dozen or so programs that are sufficiently simple to be allowable"

In a recent comment I mentioned a youtube interview with Rico Mariani, a performance engineer from Microsoft, and he said that he often got called into projects approaching their deadlines and not meeting their performance goals.

In one anecdote he spent a couple of hours with a team and showed how their design could never meat the goal even with the fastest disks, CPUs, memory, and network. And commented how strange it is if they had spent a day at the start of the project whiteboarding out the design against hardware specs at the start of the project - and avoided months of wasted effort - that would be called "premature optimization".

[1] https://dl.acm.org/doi/pdf/10.1145/356635.356640

Re: Saving 100 terabytes of memory by optimizing 1.1.1.1's DNS cache

#224

We're finally seeing more appreciation for this kind of engineering. Not everything needs to be solved by throwing more hardware at the problem

With memory costs soaring due to AI bubble, this type of engineering has become "profitable".

Re: Saving 100 terabytes of memory by optimizing 1.1.1.1's DNS cache

#225

Earlier quoted context omitted.

Enterprise means it has SSO and a support contract

It means you are paying for a support contract. Whether you actually have one time will tell.

Only seasoned engineers will understand you are not joking.

Re: Saving 100 terabytes of memory by optimizing 1.1.1.1's DNS cache

#226
post #44

Earlier quoted context omitted.

Rob Pikes 5 Rules of Programming: Rule 1. You can't tell where a program is going to spend its time. Bottlenecks occur in surprising places, so don't try to second guess and put in a speed hack until you've proven that's where the bottleneck is. Rule 2. Measure. Don't tune for speed until you've measured, and even then don't unless one part of the code overwhelms the rest. Rule 3. Fancy algorithms are slow when n is…

> Data structures, not algorithms, are central to programming So you agree that they should've designed the system to use the appropriate data structure from the beginning?

Rule 5 is superseded by Rules 1 & 2. Without the measurements to back it up, you're chasing phantoms.

Re: Saving 100 terabytes of memory by optimizing 1.1.1.1's DNS cache

#227
post #44

Earlier quoted context omitted.

> Data structures, not algorithms, are central to programming So you agree that they should've designed the system to use the appropriate data structure from the beginning?

Rule 5 is superseded by Rules 1 & 2. Without the measurements to back it up, you're chasing phantoms.

Rules 1&2 are about speed, not memory. But also, what do you think the issue with measurement is in this case??

Re: Saving 100 terabytes of memory by optimizing 1.1.1.1's DNS cache

#230
post #135

Earlier quoted context omitted.

Quite. I was a VMware fanboi (25+ years, man and boy) I still look after a few VMware estates and a lot of Proxmox ones (that used to run VMware). Hilariously, VMware is described as "enterprise class", which I can only conclude means MVP and a bit wanky. Today I repaired a Proxmox HA + Ceph node using boring old normal Linux skills and as it turns out I have 30 years of those. Part way through a remote v8 to 9 upgra…

When I was first getting into software dev, I thought 'enterprise' meant 'industrial grade', 'powerful', 'high-performing'. Then I actually met some enterprise software, and realised that it means 'expensive', 'bespoke', 'one-off', and usually 'janky'.

"Enterprise" mainly describes the sales and support process, not the nature of the product itself. That said one does influence the other.
Post reply on HN