Possible Java to Rust switch for a securities trading platform


#1

Hi All,

I work for a financial institution and we are a group of about 10 programmers that develop and maintain a very high throughput low latency trading platform built in Java. We have been stung by the Java GC and multi threading bugs a few times and we are also in the business of continously trying to make our code run faster.

Apart from BAU work I have been searching around trying to find a speedier alternative to Java and came across Rust recently. So now I want to do a proof of concept Rust implementation of some core parts of our App to see if we gain anything by possibly switching. Its a personal project atm but who knows in future I might be able to convince my team to switch if the experiment goes well…

As some one coming from java background who has read about Rust for a bit and never really coded anything serious in it I had a few questions for the more experienced here. I would be very grateful if some of you could take the time to answer some/all of these. Any links etc or your personal experiences shared would be much appreciated.

  • What is the support like for high throughput low latency (ideally)Non blocking multi threaded code?

  • I understand that Rust itself is just core language and it depends on 3rd party libraries mainly imported through Cargo. Are there any sort of QA checks on these 3rd party libraries before they are published? How can we tell which ones are relatively mature and which ones arent ?

  • What is the support for creating GUI’s in Rust similar to Java swing or FX?

  • My code will probably create lots and lots of new short lived objects. Think about a million+ per sec. In java world we rely on gc compaction … what is the support in rust for avoiding Memory fragmentation ? Is that an issue I should even be concerned about?

  • Support for high performance network connectivity similar to Java NIO ?

  • Support for FIX protocol … for e.g. an open source equivalent of quickfixj … if there isnt one then can we interoperate with quickfixj from the java land ? or quickfix from the C++ land ?

  • Support for mature, efficient and reliable data structures similar to java collections ?

  • Support for an ORM library such as hibernate ? If there isnt one then is there a lower level alternative such as jdbc in Rust Core?

  • Benchmarking support similar to JMH ?

  • logging support for e.g. log4j … high performance logging ?

  • Floating point precision library such as Java BigDecimal etc ? As we are dealing with money we cannot afford to have rounding errors etc.

  • Please forgive me for using Java oriented terminology. Happy to explain further if needed.

Many Thanks,
Ali


#2

Rust’s concurrent collections aren’t as rich as the Java ecosystem. However, Rust mostly encourages message passing between threads rather than shared mutable memory. But perhaps you can expand a bit more on this question.

Right now there’s no good way to easily know the quality of a crate - you have to investigate it yourself. After being around the Rust community for a while you’ll know which crates are considered high quality and production viable.

Don’t know the GUI area to well in Rust but it doesn’t seem as mature as other platforms at the moment. There are GUI libs/bindings though.

Not sure how you get low latency in Java with that allocation rate :slight_smile:. In Rust, if these objects are tied to an execution thread, then you’d create them on the stack. If you’re truly allocating that many values that need to live across requests/thread stacks then you’d want to employ a pool/arena. Low latency and alloc rates like that don’t play well together.

Tokio is fairly similar to Netty. It’s still in design flux however. But you could use it in production.

I recall coming across a Rust FIX lib but not sure of its quality or maturity.

Rust stdlib has your basic stuff. Which ones in particular do you need?

Some of these exist. Diesel is a popular one.

This is roughly cargo bench ... - not as rich as JMH, I believe.

Logging exists and there’s a log4j like backend. Not sure of its performance however.

Bignum crates exist but I don’t know of their quality as compared to Java’s BigDecimal. Again, these types go against high throughout and low latency.

I personally think Rust is a great choice to build trading platforms if you’re ready to build some infrastrucure/lower levels of the stack yourself. If there are C APIs you can bind to them fairly easily via Rust’s FFI. But the landscape is not as rich as C++ or Java for the time being.


#3

For network we have futures+tokio and for data structures and utilities you can take a look at crossbeam.

No, there is no checks and there is crates of varying quality. Usually a lot can be said by how popular crate is, number of crates which depend on it, documentation quality, and how much activity is in its repository.

I would say GUI field is still quite underdeveloped in Rust. Your best bet will be probably GTK or even web-GUI.

Most of the objects should be placed on the stack if possible and Rust is quite friendly here. As for heap, jemalloc (default Rust allocator) is relatively good with handling a lot of small allocations, but it’s hard to compare its performance to Java GC.


#4

The following is Oracle Hotspot specific but extends to some other JVM impls too.

Java will allocate faster than jemalloc because the GC allocation routines are integrated with JIT compilers. In addition, small objects will be allocated out of thread local alloc buffers (TLAB) and those are pointer bumps. The problems will come when GC is invoked for reclaim, as that’s where you pay the piper :slight_smile:. What’s slow and unpredictable is the reclaim phase - allocations are very fast.


#5

What is the support like for high throughput low latency (ideally)Non blocking multi threaded code?

There is Tokio and futures crate, generally it still work in progress.

I understand that Rust itself is just core language and it depends on 3rd party libraries mainly imported through Cargo. Are there any sort of QA checks on these 3rd party libraries before they are published? How can we tell which ones are relatively mature and which ones arent ?

Use your own judgement, there is no vetting of any sort. Some crate are closely related to rust core team, but most aren’t.

What is the support for creating GUI’s in Rust similar to Java swing or FX?


Generally its not Rust strong point yet.

My code will probably create lots and lots of new short lived objects. Think about a million+ per sec. In java world we rely on gc compaction … what is the support in rust for avoiding Memory fragmentation ? Is that an issue I should even be concerned about?

Run a benchmark to find out, but this is so niche usecase that you may need to figure out you own way of dealing with this.

Support for high performance network connectivity similar to Java NIO ?

You probably want Tokio/Mio, though Java NIO covers range of topics that are considered separate in Rust.

Support for FIX protocol … for e.g. an open source equivalent of quickfixj … if there isnt one then can we interoperate with quickfixj from the java land ? or quickfix from the C++ land ?

I’ve found only this: https://github.com/jbendig/fix-rs, which was abandoned as it considers Rust not ready.

Support for mature, efficient and reliable data structures similar to java collections ?

There is Vec, HashMap and HashSet in stdlib, lot more outside of it.

Support for an ORM library such as hibernate ?

There is Diesel, its not asyng though.

If there isnt one then is there a lower level alternative such as jdbc in Rust Core?

There are drivers for many databases, but there is no standard like jdbc.

Benchmarking support similar to JMH ?

https://doc.rust-lang.org/1.16.0/book/benchmark-tests.html

logging support for e.g. log4j … high performance logging ?

Floating point precision library such as Java BigDecimal etc ? As we are dealing with money we cannot afford to have rounding errors etc.

There is BigDecimal


#6

Of course, you can easily (for some definition of easily) wrap ODBC in a safe Rust wrapper interface (if that hasn’t already been done).

EDIT: Already exists: https://github.com/Koka/odbc-rs


#7

I’ve been in finance for a while and have seen how people rebuild Java from the ground up to avoid ever doing a garbage collection in the 8 hour trading window. It can be done, but the result is non-idiomatic Java and realistically you can’t use any of the third party libraries without rewriting them to avoid creating new objects.

In Rust you can write normally and use third party libraries as though it was ‘normal java’ and you will avoid the GC collects. I would highly encourage you to take the plunge as there’s a clear financial advantage (especially with the compile time thread safety) to doing this.

The earlier you do this, the more of a lead you will have over your peers. The penny hasn’t dropped for most of the finance world as to just how perfect Rust is for that domain.

(If you’re near St. Paul’s happy to have a coffee to discuss)


#8

I suspect it’s dropped but there’s a sea of existing code in place. If you have a predominantly Java (or JVM) based system, you’re looking at essentially a rewrite of those parts. If you’re mostly C (or C++ with C ABI exposed) then the path should be easier although not simple. You also have to weigh all the risk of rewriting (or significantly intruding on) existing working systems - no matter how amazing Rust is, there’s a category of bugs that you’ll revisit there again.

For greenfield, however, it’s definitely a good language to consider. But, as mentioned, one has to be prepared to write low level parts of the stack themselves.


#9

I think I’d be tempted to go straight to mio and implement my own stack on that, given that tokio and async/await are still evolving. Watch out that the Java style of cross-references everywhere doesn’t translate naturally to Rust. Also maybe consider actors as an alternative to non-blocking multithreading, e.g. actix, which is getting good benchmarks for web (actix-web).


#10

Wow the response to my post has been great. Thanks all for taking the time.

@gilescope ‘compile time thread safety’ alone is a good enough reason to take the plunge IMO. However I need to ensure what exactly this term means. Surely the shared data access would have to be synchronized by the programmer. Sure the default immutability of data and loaning data concepts help but either I am not understanding the threading model of Rust(I havent studied it much yet) or surely there can be deadlocks, starvation and data corruption etc like in any other low level language.

@jimuazu Thanks for pointing out actix. I suppose its similar to AKKA in java/scala world. We are normally trying to shave off millis or even nanos from our latency so adding this abstraction will probably not help. It will most likely be low level constructs that we would need.

@vitalyd you are right. We are doing object pooling etc but even then in busy periods the gc can kick off randomly and cause chaos. The object pooling + complex concurrency give us a non stop supply of bugs that tend to pop up at the worst of times. This is the main reason I have taken this initiative.

Here is an overview of what I will be trying to do:

Connect to a few providers using a FIX engine as fix protocol is pretty much the industry standard. Get streaming prices(multiple updates within a sec) for just two instruments(in beginning) lets say GBP/USD and EUR/USD. Build an aggregated price book using the streaming prices for each of the instruments. Keep the books sorted by best price. The system will need to be scalable to hundreds of instruments but the principle should be the same…

There is 3 reasons why I am doing this experiment:

  1. Potential execution speed of rust code due to pre compilation rather than JIT etc.
  2. Avoid gc pauses.
  3. Avoid multi threading bugs because of Rust compiler guarantees.(I have no practical experience with this yet)

#11

Deadlocks, yes, but the language/libs make this somewhat more difficult to occur in Rust (and easier to spot IMHO).

Starvation - not sure what you mean exactly, but, if you mean using all of some resource (like sockets), the RAII nature of Rust makes this very difficult to mess up.

Corruption - absolutely 100% prevented in “Safe” code (sans a bug in the compiler etc). You can still corrupt things by using pointers directly, but, that would involve “unsafe” code which you shouldn’t be doing in anything other than safe abstraction wrappers, and, ideally, you should have 0 unsafe code in your actual application directly.


#12

You should find that Rust satisfies all 3 of these requirements quite well.


#13

AFAIK In Rust you can get deadlock and starvation, but race conditions are a thing of the past - I think you might want to read https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html .

It would be really cool to have a fix crate: https://crates.io/crates/fix-rs has been one attempt with an interesting blog on the subject here: http://www.codeofview.com/fix-rs/2016/11/10/implementing-fix-messages-with-rust/
but it seems they’ve given up so feel free to pick up where they left off. If you want to start from scratch the nom parser is recommended by quite a few.


#14

Deadlocks, starvation and corruption can and will still happen as the system matures. For a low latency system one will inevitably use some unsafe code to shave off processing time and corruption likes those places. But, this code will likely be a small fraction of the overall codebase and thus easier audit more closely.

Deadlocks and starvation will need to be addressed in a similar manner to other languages - it’s more of a design issue.


#15

Rust eliminates data races, not race conditions. See: https://doc.rust-lang.org/beta/nomicon/races.html


#16

The closest (OSS, at least) approximation to what a (part of) low latency high throughput trading system would look like is http://netbricks.io/. This is a stand-in for what multicast marketdata packet processing might look like with kernel bypass networking (dpdk in this case), and that’s by far the hottest path in most of these systems.


#17

Regarding GUI, one possible solution is to use a client-server design where the server is written in Rust and the client is written in a language with a more mature UI ecosystem (Python, Java, web stuff…).


#18

@alinaqvi90, just wanted to say that if you do end up doing some experimentation/prototyping, please report back here :slight_smile:


#19

actix appears to perform a lot better than AKKA. actix-web is within 5-20% of the best in web benchmarks (https://github.com/actix/actix-web), better than tokio in some tests. So still worth considering.


#20

Should also mention that you want as little concurrency as possible in trading systems (or any system really) - you want parallelism instead. If I was building a trading system from scratch, I’d follow the seastar design: shard your trading universe across cores (and machines) and keep it single threaded on each core. Any necessary communication between cores (ideally very minimum) is done over message queues.