15 ms·
Fast, Safe, and Complete(ish) Web Service in Rust
- vardump 9y agoVery exciting to see Rust gaining support lately. That said, one of the only remaining things keeping me from using it is production ready gRPC library.
- kehtnok 9y agoJust an FYI (if you want something to watch and haven't heard about it already) https://github.com/tower-rs/tower-grpc https://github.com/tower-rs/tower-grpc is in the works by the same folks building tokio and hyper etc. But yep, definitely not production ready as the README clearly states :)
- carllerche 9y agoI would say that you could start using it if: * You are ready to become an active contributor to the project. * You are brave!
- illuminati1911 9y agoReally nice article. I’ve been using rust moderately for the last 6 months and at least my experince was that once you get used to playing along with the compiler and understand the fundamental features of the language, it almost feels too good to be true. Perfect mix of high performance, safety and modern features. Slightly challenging at first, but it really is worth the initial pain.
- oromier 9y agoThis is literally every comment I see about rust. Do you guys C/P these comments?
- illuminati1911 9y ago:D At least I didn't. It was the first time I commented on Rust here on HN.
- Thaxll 9y agoWhy would you want to do that in Rust instead of Go / Java / C# since the performance is the same. When I look at code example in the article the syntax is just awful seriously, who want to write web services with that kind of syntax: time_helpers::log_timed(&log.new(o!("step" => "upsert_episodes")), |_log| { } It's just non-sense: impl<S: server::State> actix_web::middleware::Middleware<S> for Middleware { fn start(&self, req: &mut HttpRequest<S>) -> actix_web::Result<Started> { let log = req.state().log().clone(); req.extensions().insert(Extension(log)); Ok(Started::Done) } Rust is a good language but I don't see it any time soon in the web space with that syntax and the lack of mature libraries, plus the time it takes to get anything done. Where I see it is more for super optimized things like serialization and the like as libraries but not as a main program.
- adrianN 9y agoTo learn Rust? Also, where do you get that the performance is the same? I didn't see any benchmarks.
- Thaxll 9y agoIn the linked article by the OP Java is faster than Rust in every scenarios. https://www.techempower.com/benchmarks/#section=data-r15&hw=ph&test=json https://www.techempower.com/benchmarks/#section=data-r15&hw=... tbh benchmarks are not that useful, but it shows that GC languages are very fast in the web space and it's even more true when you add client -> server latency in the mix.
- staticassertion 9y agoNot in Plaintext. But yes, Java has some extremely optimized libraries for HTTP, and a great GC has a lot of advantages for this sort of benchmark I'd imagine (short lived allocations, deferred collections). That said, actix is particularly new, with room to optimize.
- seanmcdirmid 9y ago
- staticassertion 9y agoThanks for writing this. Actix is really cool but I haven't really spent the time looking into it - I was unaware of the SyncArbiter abstraction. This is a very helpful post for me.
- lmm 9y agoThe author briefly mentions Haskell but I wonder whether they've build web services with it, or with another (loosely) ML-family language (e.g. OCaml, F#, or my personal favourite Scala). An ML-style type system is a huge advantage over Ruby/JavaScript/..., but for a web service I struggle to see a real case for going to all the effort of memory ownership tracking rather than using a GCed language with the same kind of strong type system; it would be good to see a comparison from someone who's done both.
- nicoburns 9y agoI think that despite the constraints imposed by the lack of GC, Rust is seen as more approachable than more functional langauges to those coming from a C/Java/JavaScript etc background. And the only similar language with an ML type system is Swift which isn't quite there with libraries for backend stuff. Also, have you seen the sample code for Rocket based webapps? I haven't seen much nicer in any language. The async ecosystem isn't nearly as nice yet, but it should get much nicer once async-await lands.
- lmm 9y ago> Also, have you seen the sample code for Rocket based webapps? I haven't seen much nicer in any language. Had a quick look just now. Clean syntax for the implementation, but routing and parameters are relying on magic # annotations. Compare with e.g. https://doc.akka.io/docs/akka-http/current/routing-dsl/index.html#longer-example https://doc.akka.io/docs/akka-http/current/routing-dsl/index... where you can do the routing in plain old code (also async is already there).
- kbenson 9y ago> routing and parameters are relying on magic # annotations Actually, as someone almost finished with the book, that brings up an interesting point. What controls # annotations and how do you hook into them (which also answers the question of how magic they are)? If it's fairly standard and obvious how to look up, I think I might not classify them as much "magic", but truthfully, I have no idea at all. Maybe I'm just not remembering that part of the book (I did take a break for a month), or maybe I didn't make a connection that was implied?
- bluejekyll 9y agoThank you for writing/posting this! Specifically the custom bindings using Diesel. I was unaware that generic sql could be bound so easily. That’s closer to how I end up when needing to create higher performance queries. I need to take another look at Diesel now. Very nice article.
- _wc0m 9y agoI've been using 'actix-web' in anger for the last month or so and I just want to echo that it is an amazingly fast and fully-featured project. I smiled when reading this post because I absolutely recognize the euphoria of carrying out a world-changing refactor and having it work first time. If this is what the future of backend development feels like, sign me up!
- dorfsmay 9y agoHave you look at rocket etc... Curious about your decision process.
- adwhit 9y agoI like rocket a lot - practically as easy as writing flask but with glorious type-safety thrown in - but I really wanted async ('like, now') because my project will have a large number of persistent connections. I'm sure rocket will get async eventually but it looks to be some way off. In comparison to rocket, actix-web does not use codegen tricks so is not as ergonomic or as safe - e.g. it cannot statically check that the path variables that you ask for actually exist on the route - but these are things that a simple test suite easily picks up (incidentally actix-web has a nice built-in test server). Also I was a little concerned that rocket development has stalled somewhat. 26 PRs waiting at time of writing. As I recall the maintainer is teaching a Rust class as Stanford so he's most likely just very busy.
- fafhrd91 9y agoi just added extractors system. it is not released yet, i am planing to release it later this week https://actix.github.io/actix-web/actix_web/struct.Route.html#method.with https://actix.github.io/actix-web/actix_web/struct.Route.htm...
- aschampion 9y agoFor async, also worth considering Gotham: https://gotham.rs/ https://gotham.rs/ I only have minimal experience with it, since I've also eventually chosen actix-web for all my projects so far due to its simplicity.
- masklinn 9y agoReally nice introductory article, though some of the more… axiomatic assertions, are iffy. > If it’s possible to build more reliable systems with programming languages with stricter constraints, what about languages with the strongest constraints? I’ve skewed all the way to the far end of the spectrum and have been building a web service in Rust Bit overselling it, that introduction would work better for something like ATS or possibly Idris. Rust has its strictness, but it's not exactly "you must prove this recursion terminates"-strict > Synchronous operations aren’t as fast as a purely asynchronous approach This is misleading. Synchronous sequences are generally faster than asynchronous ones because yielding and getting scheduled back has a non-zero overhead (this is regularly re-discovered, most recently by the developers of "better-sqlite": https://news.ycombinator.com/item?id=16616374 https://news.ycombinator.com/item?id=16616374). Async operations are a way to increase concurrency when your synchronous sequence would just be waiting with its thumb up its ass (e.g. on a network buffer filling or on a file read completing), so you can provide more service over the same wallclock time by (hopefully) always using CPU time.
- nicoburns 9y agoIn other words, for data-bound processing (such as most web services), async approaches are faster (specifically they have greater throughput).
- lomnakkus 9y agoI'm confused about your "greater throughput" comment. Generally one achieves maximal throughput by maximizing parallelism (not plain concurrency!) and letting each individual core/CPU run its job to completion while ignoring everything else (even interrupts, as far as applicable). Async is generally associated with lower latency. Can you expound?
- Chyzwar 9y agoYou can keep pushing bytes as you get them from async operations. In my nodejs am making 20000 DB queries and I can push data to connected clients when any these get completed. In the threaded code, you need to get a window of time and memory. In my Java, I have a max heap size of 8gb and I can maybe create up to 8k threads. When making 20000 DB queries only 8k is being executed where most of these are waiting for the query to complete or CPU time.
- Shoothe 9y ago> It’d be fair to say that I could’ve written an equivalent service in Ruby in a tenth of the time it took me to write this one in Rust. Ha, I had the same feeling when I needed to create a simple REST service that'd just process a request using command line tools. Seems easy but Rust's tooling is full of rough edges. Code completion sometimes works sometimes doesn't, cargo cannot install dependencies only (without building source) so it's not good for Dockerfile layers, etc. etc. Borrow checker is not bad at all for people that worked with languages with explicit memory management (where you do ownership tracking in your head anyway). Long story short I spent 2 days working on the service and had 80% done but figured out the rest would take twice as much if I want this to be production quality. I scraped the project and rewritten it in node, using one or two dependencies in 2 hours. I'll be trying Rust again surely and I'm glad that articles like this one exist!
- rabidferret 9y agoJust wanted to mention that your usage of `sql_query` is exactly how it's meant to be used, and exactly where I would reach for it. Great article!
- hardwaresofton 9y agotldr; - it was hard for me to determine which rust web framework I should be using, since I want something light like flask. best resource was https://github.com/flosse/rust-web-framework-comparison https://github.com/flosse/rust-web-framework-comparison Very recently I've taken a tour around the Rust web server ecosystem, and I think it's way too hard to find one to pick. The author mentions actix-web[0], and mentions how fast it is, but it's actually right below hyper[1], which I find to be simpler, because it doesn't bring in the whole actor frame work thing. Hyper builds on Tokio[2] which introduces the usual event loop paradigm that we're used to in other languages (which AFAIK is the fastest way to write web servers to date). There's also great talk[3] that introduces the choices that tokio makes that are somewhat unique. Here's what I want out of a web framework: - express like-interface (func(req,resp,next) pattern provies just the right amount of freedom/structure IMO) - good routing (plus: decorators/a fairly ergonomic way to specify routes) - reasonable higher-level interfaces to implement (I want to implement an interface, and be able to receive things like logging, tracing, grpc/thrift/whatever transports for free, good interfaces are what make writing reusable stuff like that possible) Here's what I found about the various frameworks that exist out there: - Rocket.rs[4]: Seems to do too much (I tend towards building APIs), rocket is closer to django/rails than it is to flask/sinatra. - Gotham.rs[5]: Seems perfect, but falls flat on the feature front, half the stuff on the landing page are features of rust, not the library. Doesn't seem to have enough batteries included, for example there's currently work being done on streaming request bodies (https://github.com/gotham-rs/gotham/issues/189 https://github.com/gotham-rs/gotham/issues/189), that's not a issue I want to run into. - Iron.rs[6]: The oldest of the bunch, but also very very fast (which I discovered actually browsing rocket's issues[7]), not based on hyper, and also not actively maintained. I had no idea which of these to use, or how to find ones I've missed, then I stumbled upon this amazing resource: https://github.com/flosse/rust-web-framework-comparison https://github.com/flosse/rust-web-framework-comparison. However, when you look at that comparison, it's really suspicious how much of actix-web has filled out, which is often indicative of something written from one point of view (like when people have comparison pages, and one option seems to just have "everything"). And again, like I said actix seems to be doing too much, I don't really want to utilize the actor model, I just want a relatively fast, ergonomic simple library with the most basic batteries included. BTW, everyone keeps raving about type safety and I wonder why people don't give Haskell more of a go. If Rust gives you the type safety equivalent to a shield, haskell is a phalanx. I've never felt more safe and protected by my types than when I write Haskell -- it's relatively fast, memory safe, has fantastic concurrency primitives, and though it can be tough to optimize (which comes to down to optimizing for lower amounts of GCs like most other memory managed languages), it's pretty fast out of the gate. I use servant (https://haskell-servant.readthedocs.io/ https://haskell-servant.readthedocs.io/) and love it. [0]: https://github.com/actix/actix-web https://github.com/actix/actix-web [1]: https://hyper.rs/ https://hyper.rs/ [2]: https://tokio.rs/ https://tokio.rs/ [3]: https://www.youtube.com/watch?v=4QZ0-vIIFug https://www.youtube.com/watch?v=4QZ0-vIIFug [4]: https://rocket.rs/ https://rocket.rs/ [5]: https://gotham.rs/ https://gotham.rs/ [6]: http://ironframework.io/ http://ironframework.io/ [7]: https://github.com/SergioBenitez/Rocket/issues/552 https://github.com/SergioBenitez/Rocket/issues/552
- ComputerGuru 9y agoI love rust, but to be honest, until the nightmare that is tokio/futures is fixed with native async/await and better compiler error messages, a strongly typed language like C# with those features natively present is my choice for web services. It addresses all the author’s issues with Ruby and JS, and is still orders of magnitude faster than those options (though admittedly not as fast as a C or rust option).
- deleted 9y ago[deleted]