Hacker News

Top stories

Live mirror
30 storiesupdated just nowView source snapshot
  1. Human brain is two separate organs, Stanford Medicine-led research finds(stanford.edu ↗)
    46comments
  2. GPT-6 Astra Solves a WWI German Radio Cipher(prinzai.com ↗)
    26comments
  3. If math is more than proof, we need to better celebrate the rest of it(terrytao.wordpress.com ↗)
    22comments
  4. San Francisco Onion Futures Company(onionfutures.com ↗)
    59comments
  5. Android 17 is the first since 3.x to add new APIs without releasing to the AOSP(grapheneos.social ↗)
    387comments
  6. Typesafe-computer-use drives a Mac toward a goal for 1/50th of a cent per step(github.com/awlevin ↗)
    33comments
  7. Science Is Open Software(jepedersen.dk ↗)
    31comments
  8. SDCC – Small Device C Compiler(sourceforge.net ↗)
    15comments
  9. Cloudflare Quick Tunnels(cloudflare.com ↗)
    275comments
  10. You can run Git on object storage if you re-make packfiles(tigrisdata.com ↗)
    9comments
  11. Why building a Rust LSP is hard(rust-glancer.github.io ↗)
    28comments
  12. NASA-IBM Lunar Foundation open-Source Geospatial AI Model(usra.edu ↗)
    2comments
  13. Saving another 100TB of RAM(cloudflare.com ↗)
    67comments
  14. How to Write with an LLM(sockpuppet.org ↗)
    320comments
  15. How OpenAI Used Its Own LLMs to Design Its Jalapeño Chip(ieee.org ↗)
    81comments
  16. The first new cat species discovered in 100 years(nationalgeographic.com ↗)
    99comments
  17. Ctenophores: Wonders of Biology(quantamagazine.org ↗)
    4comments
  18. Goroutine Leak Profiles(go.dev ↗)
    2comments
  19. OpenJev(openjev.com ↗)
    259comments
  20. Veronese's Dogs(publicdomainreview.org ↗)
    discuss
  21. Show HN: Cactus Needle 3: 8-29MB automation models can match DeepSeek V4 Flash(cactuscompute.com ↗)
    88comments
  22. Photon-Emission-Guided Laser Fault Injection Enables RP2350 Secure Debug(ledger.com ↗)
    67comments
  23. Stepfun Step 5 Preview (LLM): On AA Pareto frontier(artificialanalysis.ai ↗)
    2comments
  24. Cache-to-Cache: Direct Semantic Communication Between LLMs (2025)(arxiv.org ↗)
    12comments
  25. Minimal Phone 2(minimalcompany.com ↗)
    218comments
  26. The Farnese letter(simonklee.dk ↗)
    6comments
  27. The Case of Elias Thorne, Imaginary Man AI Chatbots Are Obsessed With(vice.com ↗)
    1comments
  28. Cyclomatic Complexity in C#(ndepend.com ↗)
    18comments
  29. Warez: The Infrastructure and Aesthetics of Piracy (2021)(archive.org ↗)
    54comments
  30. Inside ZCode: Silently uploading your Git history to the cloud(ferstar.org ↗)
    97comments

The Case of the 50ms request

284 pointsby 5y agomysteries.wizardzines.com
58 comments
5y agoHN ↗

As requested by the commenter below (now I want spoiler tags):

SPOILER FOR THE GAME

I’ve seen TCP_NODELAY all over the place before, but never known why. This was a fun way to find out.

5y agoHN ↗

hackernews feature request: spoiler tags. :)

5y agoHN ↗

echo "rnfl fcbvyre gntf!" | tr a-z n-za-m

:)

5y agoHN ↗

Thanks for pointing out this comment! Setting TCP_NODELAY seems to be the go-to / default solution for some reason (cargo-culting? not understanding the interaction with Delayed ACKs?) when there are times when Nagle’s algorithm could probably help.

5y agoHN ↗

I ran into an interesting variation of this where we shouldn't have had any problems with small packets, but it turned out we had having jumbo frames enabled in AWS (which seems to be a default now). Together with gzip, you can actually have a bit of trouble filling up a packet, which will then be delayed by the commonly mentioned interaction with delayed ACKs.

5y agoHN ↗

A few months ago there had been multiple articles about this behaviour but i really don‘t remember the details anymore. Does anyone know a writeup with a detailled explanation to understand how it is happening and tests to see whether your systems are affected?

5y agoHN ↗

There’s 5 links once you finish the puzzle

5y agoHN ↗

A couple bugs in this game, I wanted to SSH onto the client, took me to the server instead.

5y agoHN ↗

It does ssh you to the client -- the text is wrong.

5y agoHN ↗

Pretty fun puzzle, but this kind of debugging is alien to me. Without going into too much detail, it's pretty easy to see something suspect is going on, and this hunch can be easily tested. This debugging tour takes you to strace, wireshark, all sorts of other low level debugging techniques, when really all you had to do was simulate the client with curl -d and the problem would have been pretty obvious.

And in this case the more complicated debugging tools didn't even explain anything. As the last page says, the answer is kind of a leap. If you already knew about this problem curl would have solved it immediately, and if you didn't you'd still be baffled even after knowing exactly why the stack traces are the way they are.

5y agoHN ↗

How would using curl -d make the problem obvious?

5y agoHN ↗

Ok, I think that would have helped me learn that the client can some how trigger the bug but I don't think it would have allowed me to narrow it down to flushHeaders.

5y agoHN ↗

There is no such thing as flushing a TCP socket which is why that function jumped out at me. curl would have confirmed the server isn't misbehaving. Googling flushHeaders shows it's a node implementation specific thing and the docs explain that it has to do with the way node buffers http headers. Which makes sense because you don't want to call socket.send() for every http header you add to your request. But you also don't want to send() in between your headers and the body, because then you violate TCP package size expectations.

5y agoHN ↗

flushHeaders() is there to have a simple bug to find. In real world cases, tools like tcpdump and strace are essential, and I think this is a nice way to teach about how these tools can be used.

5y agoHN ↗

That's the first thing I wanted to do after seeing the JS; since it was a simple request / response, check to see if it's a problem with the client vs the server by replacing the client with a known good piece of code. This effectively bisects the search space without first diving into low-level details.

5y agoHN ↗

Exactly. If anyone has ever seen The Price Is Right, this is the optimal strategy for the “higher / lower” game: cut the options in half each time.

5y agoHN ↗

I had to read this remark a couple of times before I realised it's suggesting a curl debugging trace is somehow more definitive and less complicated than tcpdump, despite it being a TCP issue.

For those of us who grew up reading W.R.Stevens, that might seem absolutely back-to-front. Not only that, curl ain't gonna help you diagnose the next one, which is a Path MTU Discovery issue, or the one after that, which is an undervoltage on the DRAM refresh controller. It might, however, be helpful in nailing that HTTP/2 prefetch request connection upgrade bug.

Mechanical sympathy means feeling every part of the machine, right down in your bones.

5y agoHN ↗

To be fair, it was much simpler to develop and retain fluency in tcpdump when your interfaces were physical and your protocols weren't encrypted.

5y agoHN ↗

It is a lot nicer to tcpdump/wireshark when you can see everything, but most of the patterns of bad behavior are visible with encrypted data too.

Of course it's not as easy as it used to be / there's a lot more hurdles.

Encryption as you mentioned; although if you control the client or the server, you can often log keys and decrypt with wireshark, but it's a lot of steps, and you don't get helpful feedback to find mistakes.

NIC offloading means the OS doesn't necessarily see packets as they are on the wire. Segmentation offload means you may see larger packets than are on the wire, and checksum offload often makes sent packets show as errors but they're fine on the wire. If the NIC mutilates the packet, that's hard to debug.

It's not easy to run packet captures on mobile devices. If you can't get tcpdump on the device, you can't get captures from the client side of your cellular data. A lot of people don't have a network router they can run tcpdump on either, and if not, they can't get the client side of wifi data either.

5y agoHN ↗

This is great. Julia Evans has some great content in general, she's really good at explaining complex topics in an engaging and accessible way.

5y agoHN ↗

All due respect, this is a neat advertisment for the "storytelling" Javascript library she is using, but I learn much more by reading W R Stevens' books. There is more to TCP/IP than what one can do through Berkeley sockets. Plus reading Stevens' books does not require Javascript.

5y agoHN ↗

Error: <<you-said>>: error within widget contents (Error: cannot find a closing tag for HTML <pid>)

This hints to a possible XSS and/or code injection (not completely quoted input). Input was "strace -s128 -f -p <pid>" , as an answer to "how do you strace server process"

5y agoHN ↗

That was exceptionally fun. I thought I had the answer but I was completely wrong. I shouldn't have stopped the debugging and rush to the solution. Unfortunately it is a game, and it allowed me to do it.

To me this seems pretty obscure and you debug pretty deep into and outside of your application. One part of me thinks of this as Somebody Else's Problem, but definitively makes me rethink it as a SEP and something devs should know about. Specially in time critical/real time systems.

5y agoHN ↗

Really nice game/tutorial.

The best job interview I ever had was framed like this. The interviewer told me there was a bug in the system and had a stack of pages he'd printed out that would provide successive clues as to what caused it. I could ask them questions, in effect using the interviewer as a search engine/debugger.

It was the closest an interview has ever come to simulating the day-to-day of a web developer.

5y agoHN ↗

I've said it before and will say it again: One code review or debugging session gives an interviewer more actionable information than an effectively unbounded number of logic puzzles.

5y agoHN ↗

January 3, 2032.

For several years now, programming has been a required course for all grade-school students.

The tech field is flooded with talent, and it is virtually impossible to get a job.

The technical interview has grown at an unbounded rate.

An aspiring engineer walks into the interview room, freshly shaven. He sits down, cracks his knuckles, takes a long sip from his branded thermos.

Waits.

And then it begins. The interview.

10, 100, 1000 logic puzzles. Faster than seems possible, he recites answers memorized from algoexpert.io.

Cut to a wide shot. Speed up time. Stubble, then a beard, appear on his face. The sun rises and sets, and yet he dare not sleep.

Eventually, he forgets language, reason, civilization, coffee. The touch of his baby son's skin, although he's not such a baby anymore.

He grunts, diagrams, and whiteboards. That's all his life is now.

"Ok, well thank you very much! You'll hear from us soon," Says the interviewer. The sounds are foreign to the engineer, but he is lead out of the office and onto the bright street. His car sits there, rusted.

The interviewer motions the next candidate inside.

He doesn't hear from them.

5y agoHN ↗

I got it straight away, but I have a telecoms engineering and networking background. This just goes to show how poorly networking is taught in most courses (as are databases), and specially in boot camps. Self-taught programmers are also very unlikely to be exposed to this kind of topic.

One thing that was not offered as an option was to use a packet analyzer like tcpdump or Wireshark, even though that is the most reliable and systematic way to get to the bottom of many performance problems. You'd think the popularity of the network tab in Chrome's dev tools would make this less scary.

5y agoHN ↗

I was afraid of using tcpdump until I learned that the ip and tcp packet has a very specific structure. I had to use tcpdump+wireshark for debugging recently and it felt like having a mini-superpower.

5y agoHN ↗

If you're talking about the game, then there is the option to use tcpdump directly on the client.

5y agoHN ↗

Oh, OK, I didn't see it and I went straight to "GUess the problem" or whatever it was called.

5y agoHN ↗

The interesting thing for me is that I would suspect most devs including myself would assume that if the request takes 50ms, that's how long it takes (because networks!).

I wonder how many of us are able to judge how long something should take? Not me, except anecdotally.

5y agoHN ↗

I used to work in an overseas office and quickly learned the ping times to the other branches worldwide so got a “feel” for how long things should take. 10/10 would recommend

5y agoHN ↗

SPOILER ALERT

I answered "req.flushHeaders()" but surprisingly it doesn't accept that as a cause, even though the headers would be sent with the initial packet and should improve the latency.

5y agoHN ↗

In the solution section, one of the answers is about preventing the message being split into two packets.

5y agoHN ↗

This was fun and a lesson to look at the code first before jumping into tcpdump/tracing

5y agoHN ↗

Nice, but not perfect:

``` You said: "strace -p $(ps aux| grep server.py| grep -v "grep"| awk -F ' ' '{print $2}')".

To strace the server, first you need to find its PID. You know that the program is called server.py. ```

5y agoHN ↗

It doesn't actually check your answer. You're supposed to check your answer against the game yourself

5y agoHN ↗

Loved it! Although it didn’t give a comprehensive answer on how to preventively solve the problem on any platform. Is there one? Or should software developers just stick to one way or another like some kind of an unspoken rule?

5y agoHN ↗

grr.. I felt stupid going through the puzzle.. but I was looking at that flushHeaders call and thought that might be a problem - simply because I never call that.

5y agoHN ↗

Knowledge of delayed ack and nagle's algorithm wasn't necessary to solve.

The explanation didn't mention the flushHeaders call, which is apparently the fix. I didn't run any tests, just looked at the JS and figured that sending 2 packets is worse than sending 1 w.r.t. latency.

It's also a pretty strong intuition that the client side tends to have issues, since the server is usually well-tested and standardized. Also, very often people are measuring wrong, so checking the JS to be sure the time recorded is accurate is also important.

https://nodejs.org/api/http.html#http_request_flushheaders

5y agoHN ↗

Agree, this knowledge is unnecessary.

The first thing I did was use curl to check if it's a client or server problem.

Then I looked at the code and immediately noticed the unnecessary flush call, the unnecessary loading of the whole file in memory and the unnecessary fs.stats.

5y agoHN ↗

There's a huge difference between solving an instance of a problem and understanding the problem. Enough commits of "this seems to fix the problem" and the codebase becomes really hard to work with.

5y agoHN ↗

It's not reasonable to expect that developers understand how everything works. There are billions of lines of code deployed that work for reasons that the developers either don't know or only think they know.

In this case, in my judgement, you only need to know about the delayed-ack/Nagling concepts if there's a engineering requirement to keep the flushHeaders call, and the 50ms latency is a dealbreaker (i.e. not merely a curiosity). Even then, it's not clear how to fix unless you can disable one of those features.

5y agoHN ↗

Based on the description, guessed 'nagle' without any debugging. Not sure if it implies I was right or wrong, but it explained Nagle's algorithm.

Asked what to do about it and typed 'tcpnodelay'. It replied it wasn't smart and asked me to click a button.

Feels pretty basic to anyone who's ever really touched TCP in code.

5y agoHN ↗

"Also, the Linux kernel doesn't always enable delayed ACKs -- to reproduce this I actually had to write a Python program that explicitly turns them on. I haven't been able to find a clear explanation of exactly when delayed ACKs are used."

Delayed ACKs can be enabled on Linux kernels 3.11+ with ip(8).

  ip route change ROUTE quickack 1

On MacOS and Windows, delayed ACKs can be configured through sysctl and the registry, respectively.

Delayed ACKs may be used in response to congestion.

For example, in bulk, i.e., non-interactive, transfers with large packets, delayed ACKs can be useful.

This is covered in Chapters 15 (15.3) and 16 of Stevens' TCP/IP Illustrated Vol. 1.

This draft suggests delayed ACKs are useful during TLS handshake.

https://tools.ietf.org/id/draft-stenberg-httpbis-tcp-03.html

Also, socat allows for setting TCP options via setsockopt. No need to write a new program.

5y agoHN ↗

   ip route change ROUTE quickack 1 dev STRING