What kind of “EventBus” to use in Spring? Built-in, Reactor, Akka?

后端 未结 3 1972
花落未央
花落未央 2021-01-30 01:58

We\'re going to start a new Spring 4 application in a few weeks. And we\'d like to use some event-driven architecture. This year I read here and there about \"Reactor\" and whil

3条回答
  •  有刺的猬
    2021-01-30 02:14

    Carefully define what you want from the framework. If a framework has more features than you need, it is not always good. More features means more bugs, more code to learn, and less performance.

    Some features to concern are:

    • the nature of actors (threads or lightweight objects)
    • ability to work on a machine cluster (Akka)
    • persistent message queues (JMS)
    • specific features like signals (events without information), transitions (objects to combine messages from different ports into complex event, see Petri Nets) etc.

    Be careful with synchronous features like await - it blocks the whole thread and is dangerous when actors are executed on a thread pool (thread starvation).

    More frameworks to look at:

    Fork-Join Pool - in some cases, allows await without thread starvation

    Scientific workflow systems

    Dataflow framework for Java - signals, transitions

    ADD-ON: Two kinds of actors.

    Generally, parallel working system can be represented as a graph, where active nodes send messages to each other. In Java, as in most other mainstream languages, active nodes (actors) can be implemented either as threads or tasks (Runnable or Callable) executed by a thread pool. Normally, part of actors are threads and part are tasks. Both approaches has their advantages and disadvantages, so it's vital to chose most appropriate implementation for each actor in the system. Briefly, threads can block (and wait for events) but consume much memory for their stacks. Tasks may not block but use shared stacks (of threads in a pool).

    If a task calls a blocking operation, it excludes a pooled thread from service. If many tasks block, they can exclude all threads, causing a deadlock - those tasks which can unblock blocked tasks cannot run. This kind of deadlock is called thread starvation. If, in attempt to prevent thread starvation, configure thread pool as unlimited, we simply convert tasks into threads, loosing advantages of tasks.

    To eliminate calls to blocking operations in tasks, the task should be split in two (or more) - first task calls blocking operation and exits, and the rest is formatted as an asynchronous task started when the blocking operation finishes. Of course, the blocking operation has to have an alternative asynchronous interface. So, for example, instead of reading socket synchronously, NIO or NIO2 libraries should be used.

    Unfortunately, standard java library lacks asynchronous counterparts for popular synchronization facilities like queues and semaphores. Fortunately, the are easy to implement from scratch (see Dataflow framework for Java for examples).

    So, making computations purely with non-blocking tasks is possible but increases the size of code. Evident advise is to use threads where possible and tasks only for simple massive computations.

提交回复
热议问题