0%
#Setting

Engineering@Bitpanda: Why we at Bitpanda Pro love Vert.x

2021년 1월 27일 6 분 읽기
뉴스 기사 배너 이미지

Back in 2018, when we set out to build the next-generation JVM stack to power our growing business, we set out some goals:

  1. Start small and scale to ride the next Bitcoin bull run

  2. Service customers faster than in the blink of an eye under varying loads

  3. Service customers 24 hours a week, 365 days a year

  4. Stay transparent: when a service is under-performing, clients learn about this, and can immediately react

Then, we quickly learned the fastest human eye-blinkers's performance is roughly 200 milliseconds. Also, apparently there are many fast eye-blinkers who want to jump on the Bitcoin band wagon. As the business goals and the first set of requirements became known, a more refined set of software-engineering goals was identified:

Stick to domain-driven design, identify natural context boundaries

We were not sold on orchestrating tens, possibly hundreds of microservices. Instead, we wanted to start with just one service and add more if the need arose.

Design software with resilience in mind

Each service implementation should have well-understood and testable unhappy path handling. Whenever this path is encountered and the system cannot self-heal, all errors are transparently propagated to a supervisory entity and the faulty instance is removed from the operation. Finally, if there are faults in the system, they don't propagate to other context boundaries and bring our whole operation to a halt.

Avoid heavy frameworks which come with tons of dependencies

Each dependency comes with some hidden cost. One is its potential exposure to security vulnerability. The other is losing control altogether, which means performance-tuning and just keeping our application maintainable, scalable and predictable is a much more difficult job.

H1: Multi-Reactor For The Masses

Enter the Vert.X and its 650 kB of asynchronous, reactive Java framework goodness.

At the core of Vert.x is the principle event-handling. Traditionally, Java applications scaled by encapsulating work-loads on Threads. While in modern multi-core systems, threads are cheap and operating systems are built to support enormous amounts of concurrent workloads, in Java, it is still quite complex to reign in orchestration of threads.

This has partly to do with Javal's memory model (chapter 17.4) when threads have to access shared memory - heap space. Get this wrong and you are in for some pretty frustrating hours of debugging out-of-memory, dead-locks, live-locks and the likes of Java concurrency.

Now imagine we set a number of available threads in the system to a fixed number up-front. We don't create any new threads while running the application and design workload execution to take place on any of these threads. Furthermore, the application instructs the execution layer on what to do by emitting events and by registering handlers ( who does it) which execute in a so-called event loop. When the processing of one event is finished, the next event-handler is called to occupy the underlying thread.

In summary, the life cycle of threads and the entire cost of concurrency management is completely solved by the framework.

Multi-Reactor Pattern

At this point you might think, this is all well and good, but how does it relate to your goals that you set out to achieve? Well, imagine the service you've been commissioned to build is a HTTP server. In case of Vert.X you can seamlessly hook your event handlers to Netty's ChannelHandler (another multi-reactor) and your final setup could look like this:

Multi-Reactor HTTP Server

Notice the time axis at the bottom where every slice represents concurrent processing of user requests using registered event handlers. Some requests may be very cheap to complete - fetching current account balance, while others - processing a new client order - may take longer. This means that while one thread is occupied by creating a new order to buy Bitcoin, the other registered event handlers may complete processing requests to deposit or withdraw funds on the other available thread.

Verticles As Context Holders

Verticles are the entry point to Ver.X multi-reactor. Each Verticle is spawned with its own Context which is not visible to other verticles. This forces developers to organise code in a perfect share-nothing encapsulation. Moreover, each context allows for perfect testability of the business logic. Integration to database or message-oriented-middleware which resides in other contexts can be mocked and eventually tested separately.

A good practice for writing verticles is to register an exception handler which nicely aides our goal of resilience by design.

@Override public void start(Promise start) { //do this before anything else context.exceptionHandler(error -> { if(error instanceof FatalError) { escalateAndShutdown(error); } else { log.error("this error is ignored", error); } });

registerServiceHealthCheck();

//complete start-up only when successfully connected to database registerHandlerWhenConnectedToDatabase().setHandler(start.future()); }

and clean up when you're done.

@Override public void stop(Promise stop) { databaseConnectionPool.close().setHandler(stop.future()); }

Since verticles operate with their own share-nothing contexts, it is not possible to facilitate direct method-calls of this sort:

@RequiredConstructor public final class OrderProcessingVerticle extends AbstractVerticle

// never reference another Verticle private final OrderMatchingVerticle matching; // or other context than own private final Context parentContext;

private MatchResult match(Order order) { return matching.handle(order); }

Instead, if one verticle wishes to communicate to another it does so by passing a message over EventBus to a specific address.

Using ask:

EventBus Askprivate Future askToMatch(Order order) { // an empty envelope, in which the system relays the final outcome Promise whenReplied = Promise.promise(); //emit event by passing a message and register response handler vertx.eventBus().request("handle-this-order-for-me", order, reply -> { if(reply.succeeded()) { whenReplied.complete(); } else { whenReplied.fail(reply.cause()); } }); //return async result of the whole event-handling return whenReplied.future(); }

Using broadcast:

EventBus Broadcast

By chaining event handlers which may operate in many fully independent contexts, Vert.X framework provides building blocks for creating a complex and performant system which at the same time allows for clean architecture. We argue such a reactive system is easier to reason about than its many alternatives and leaves room to grow your business in times of emergent requirements.

In future posts, we will look at how we solved service encapsulation and why we at Bitpanda Pro love Apache Kafka.

트레이딩을
자동화
하세요!

세계적 수준의 자동화된 암호화폐 거래 봇

시작하기
트레이딩 자동화

인기 뉴스

How to Set Up and Use Trust Wallet for Binance Smart Chain
#Bitcoin#Bitcoins#Config+2 더 많은 태그

How to Set Up and Use Trust Wallet for Binance Smart Chain

Your Essential Guide To Binance Leveraged Tokens

Your Essential Guide To Binance Leveraged Tokens

How to Sell Your Bitcoin Into Cash on Binance (2021 Update)
#Subscriptions

How to Sell Your Bitcoin Into Cash on Binance (2021 Update)

What is Grid Trading? (A Crypto-Futures Guide)

What is Grid Trading? (A Crypto-Futures Guide)

Cryptohopper에서 무료로 거래를 시작하세요!

무료 사용 - 신용카드 필요 없음

시작하기
Cryptohopper appCryptohopper app

면책 조항: Cryptohopper는 규제 기관이 아닙니다. 암호화폐 봇 거래에는 상당한 위험이 수반되며 과거 실적이 미래 결과를 보장하지 않습니다. 제품 스크린샷에 표시된 수익은 설명용이며 과장된 것일 수 있습니다. 봇 거래는 충분한 지식이 있거나 자격을 갖춘 재무 고문의 조언을 구한 경우에만 참여하세요. Cryptohopper는 어떠한 경우에도 (a) 당사 소프트웨어와 관련된 거래로 인해, 그로 인해 또는 이와 관련하여 발생하는 손실 또는 손해의 전부 또는 일부 또는 (b) 직접, 간접, 특별, 결과적 또는 부수적 손해에 대해 개인 또는 단체에 대한 어떠한 책임도 지지 않습니다. Cryptohopper 소셜 트레이딩 플랫폼에서 제공되는 콘텐츠는 Cryptohopper 커뮤니티 회원이 생성한 것이며 Cryptohopper 또는 그것을 대신한 조언이나 추천으로 구성되지 않는다는 점에 유의하시기 바랍니다. 마켓플레이스에 표시된 수익은 향후 결과를 나타내지 않습니다. Cryptohopper의 서비스를 사용함으로써 귀하는 암호화폐 거래와 관련된 내재적 위험을 인정하고 수락하며 발생하는 모든 책임이나 손실로부터 Cryptohopper를 면책하는 데 동의합니다. 당사의 소프트웨어를 사용하거나 거래 활동에 참여하기 전에 당사의 서비스 약관 및 위험 공개 정책을 검토하고 이해하는 것이 필수적입니다. 특정 상황에 따른 맞춤형 조언은 법률 및 재무 전문가와 상담하시기 바랍니다.

©2017 - 2024 저작권: Cryptohopper™ - 판권 소유.