Hacker Newsnew | past | comments | ask | show | jobs | submit | ahuang's commentslogin

(I work at Quill). We've found threading to work really well with teams as small as 3. (2, probably not.) In professional contexts, conversations tend to be about specific topics -- someone posts a GitHub issue, bug report, feature discussion, etc, vs say a more social conversation that is less structured.

It's a way to keep track of the conversations you're having instead of a stream of consciousness (with multiple conversations interleaved) that is often times what people find in a channel. Once you shift to using threads, you sort of unlock a lot of things: revisiting old conversations via search, restarting conversations becomes trivial (all the context is right there!), managing your notifications (per conversation instead of per message now), quickly catching up on what you missed vs. sifting through hundreds of messages.

We're mostly solving for teams bigger than 3, but, we think it's really important that it does scale down to small teams.


> We've found threading to work really well with teams as small as 3. (2, probably not.) I

For what it's worth, my company is (unfortunately) very chat-heavy, and I use threads in two person conversations fairly often. Sometimes conversations branch off of other conversations.


I'm pretty sure the GP was referring to total team size, not the number of participants in any particular conversation.


Sure, I'm not just talking about participants in a conversation either (with the possibility of a wider audience). Even in DMs, I use threads plenty. Sometimes someone asks multiple questions not realizing that they'll branch off significantly, and threads are a tidy way to address that. I don't see why habits relevant to a DM wouldn't generalize to teams of that size too (in which case you're always DMing).


(I work at Quill.) Quill definitely has some similarities to a forum/message board in that it's slightly more structured -- but it's very much chat at it's core.

What we've found is when a group gets large and/or complex enough, they end up graduating to creating a team and using the channels/threads model.


> Your regular conversations are absolutely yours -- your messages by default are encrypted in transit and at rest.

(I work at Quill too). Yes, absolutely! That is just table stakes when it comes to security for your messaging experience.


I think the main issue is it seems really one-sided and the intent was to be snarky, vs educational. I posted a comment here detailing some ways to work around some of the pitfalls. I think if she devoted more time in the article to solutions vs. complaining, her points would come across more productively.


I think this conflates a poor implementation of a webserver with python/gunicorn/gevent being bad. There are a few (easy) things to do to avoid some of the pitfalls she encountered:

> A connection arrives on the socket. Linux runs a pass down the list of listeners doing the epoll thing -- all of them! -- and tells every single one of them that something's waiting out there. They each wake up, one after another, a few nanoseconds apart.

Linux is known to have poor fairness with multiple processes listening to the same socket. For most setups that require forking a process, you run a local loadbalancer on box, whether it's haproxy or something else, and have each process listen on its own port. This not only allows you to ensure fairness by whatever load balance policy you want, but also lets you have healthchecks, queueing, etc.

>Meanwhile, that original request is getting old. The request it made has since received a response, but since there's not been an opportunity to flip back to it, the new request is still cooking. Eventually, that new request's computations are done, and it sends back a reply: 200 HTTP/1.1 OK, blah blah blah.

This can happen whether it's an os threaded design or a userspace green-thread runtime. If a process is overloaded, clients can and will timeout on the request. The main difference is in a green-thread runtime it's about overloading the process vs. utilizing all threads. Can make this better by using a local load balancer on box and spreading load evenly. It's also best practice to minimize "blocking" in the application that causes these pauses to happen.

>That's why they fork-then-load. That's why it takes up so much memory, and that's why you can't just have a bunch of these stupid things hanging around, each handling one request at a time and not pulling a "SHINYTHING!" and ignoring one just because another came in. There's just not enough RAM on the machine to let you do this. So, num_cpus + 1 it is.

Delayed imports (because of cyclical dependencies) is bad practice. That being said, forking N processes is standard for languages/runtimes that can only utilize a single core (python, ruby, javascript, etc.).

This is not to say that this solution is ideal -- just that with a small bit of work you can improve the scalability/reliability/behavior under load of these systems by quite a bit.


Not always ;). As someone with experience managing mongo at scale, this really speaks volumes to the amount of effort needed to make it not do the wrong thing. And even then, there are unknown unknowns like this that can pop up at any time.


gRPC isn't a requirement for response streaming (as is quoted as one of the main reasons for doing the migration). That can all be achieved with http/json using chunked encoding. In fact, that's what the gRPC-gateway (http/json gateway to a gRPC service) does https://github.com/grpc-ecosystem/grpc-gateway.

gRPC adds bi-directional streaming which is not possible in http, but the use cases for that are more specialized.


Sure, the actual transfer will be streamed, but most JSON clients wait for the entire response before firing your callback. As far as I know there isn't even a commonly used spec for partially reading a JSON document.


Generally its the upper 32k ports that are ephemeral, and if your churn more than that per minute in connections, you'll run into that TIME_WAIT issue.

Hacky way to get around that is to enable tcp_tw_reuse which will let you reuse ports, but it can be risky if you get a SYN from the previous connection that happens to lineup with segment number of the current connection (which will close your connection). Shouldn't happen often, and if you can tolerate a small amount of failure is an easy way to get around this limit.

[0] http://blog.davidvassallo.me/2010/07/13/time_wait-and-port-r...


For benchmarking loopback connections, addressing really shouldn't be an issue, as you have an entire /8-subnet to split between your client(s) and server(s) (127.0.0.0/8). You would need some logic to set up eg 10.000 listening servers, and 1000.000 clients to get it working, and at some point you'd probably run into memory or other limits.

I'm a little surprised some simple googling didn't turn up any examples of this - I'm sure someone have tried it out in order to do some benchmarking of high-performance network servers/services?

Apparently ipv6 changes this to a single (loopback) address, but then again, with ipv6 you can use entire subnets per network card.


> Hacky way to get around that is to enable tcp_tw_reuse which will let you reuse ports, but it can be risky if you get a SYN from the previous connection that happens to lineup with segment number of the current connection (which will close your connection)

Actually Linux will fall back to using TCP timestamps to distinguish between different connections. Ironically people will disable timestamps too to "fix" other issues[1] which also break PAWS[2] and may cause the issue you describing.

[1] It can break with some NAT and some load balancers. Actually the way I learned about tcp_tw_reuse was when we plugged in a new load balancer. We tested everything worked fine, but as soon as we sent production traffic many connections took few seconds to complete. Took 2 weeks to find the cause and looking at packet dumps. Turns out that the issue was that the load balancer was set up in active-active configuration, so different connections had different timestamps. This caused Linux to get confused and ignore some packets. Turned out one of managers wanted to make everything performant and copied some sysctls (that included tcp_tw_reuse and tcp_tw_recycle) from Internet without much though. After restoring the setting everything worked flawlessly.

[2] https://en.wikipedia.org/wiki/Transmission_Control_Protocol#...


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: