0 x00 the

SOFARegistry is ant Financial’s open source, production-grade, time-sensitive, and highly available service registry.

This series of articles focuses on analyzing design and architecture, that is, using multiple articles to summarize the implementation mechanism and architecture ideas of DataServer or SOFARegistry from multiple perspectives, so that you can learn how Ali designs.

This fourth article introduces SOFARegistry’s message bus.

0x01 Related Concepts

1.1 Event-driven model

The event-driven model is what we call the observer. Programming model based on publish-subscribe model.

1.1.1 concept

Defines a one-to-many dependency between objects in which all dependent objects are notified and updated automatically when an object’s state changes.

From a programming point of view, the core components of an event-driven model usually include the following:

  • Event source: The object responsible for generating the event. A button, for example, is an event source that produces the “click” event
  • Event listener (event handler) : The object responsible for handling events
  • Events: Also called event objects, are information Bridges between event sources and event listeners. Is at the heart of the event model drive

1.1.2 Application Environment

Event-driven models are usually a good choice when we are faced with the following environments:

  • There are many tasks in the program;
  • Tasks are highly independent of each other (so they don’t need to communicate with each other, or wait for each other);
  • Some tasks block while waiting for events to arrive;

1.2 Message Bus

Bus refers to the common communication trunk that transmits information between various computer functions, while EventBus is a Bus that sends subscription events from an event source to a subscriber, decoupling the strong dependency between the subscriber and the event source in the observer mode.

Message bus plays the role of message routing and has a complete routing mechanism to determine the direction of message transmission. The sender only needs to send messages to the message bus, regardless of how the message is forwarded. In order to avoid message loss, part of the message bus provides a certain mechanism of persistent storage and disaster recovery.

A message bus is simply a message center to which many microservice instances can be connected and to which instances can send or receive messages (via listening).

Common application scenarios where observer mode is used can be replaced by EventBus.

0x02 Business Domain

2.1 Business Scope

DataServer is essentially a web application, so it has the following features:

  • Need to process messages from various parties;
  • There are many tasks in the program, and the tasks are independent. Most of the tasks do not have mutually exclusive communication operations. Some tasks block while waiting for events to arrive;
  • A message often has multiple delivery sources;

Therefore, event-driven mechanisms are a natural fit.

2.2 points

The problems that can be thought of are as follows:

  • Because an event often has multiple sources of delivery, how do you decouple the logic between event delivery and event processing?
  • How do you register a Listener once to know which events the Listener is interested in, and then notify the Listener when a certain type of event occurs?
  • How can a Listener handle multiple events?
  • How can an event be processed by multiple Listeners?
  • Can the registration process be simplified?
  • Do you need to maintain message order?
  • Are messages processed asynchronously or synchronously?
  • Should multiple same messages be merged?

More on Ali’s thinking later in this article.

2.3 Solutions

The internal logic of DataServer is mainly implemented by event-driven mechanism. The following figure shows the interaction flow of some events in the EventCenter. As shown in the figure, an event often has multiple delivery sources, which is suitable for decoupling the logic between event delivery and event processing.

0x03 EventCenter

There are many message buses in the industry. For example, Android EventBus is a publish/subscribe EventBus framework based on the observer pattern, which separates the receiver and sender of events, simplifying communication between components.

SOFARegistry EventCenter serves a similar purpose: it logically decouples event recipients from senders, simplifying communication between components. Ali implementation has its own characteristics, developers can learn from the use of skills and ideas here.

3.1 Directory Structure

├ ─ ─ event │ ├ ─ ─ AfterWorkingProcess. Java │ ├ ─ ─ DataServerChangeEvent. Java │ ├ ─ ─ event. Java │ ├ ─ ─ EventCenter. Java │ ├ ─ ─ LocalDataServerChangeEvent. Java │ ├ ─ ─ MetaServerChangeEvent. Java │ ├ ─ ─ RemoteDataServerChangeEvent. Java │ ├ ─ ─ StartTaskEvent. Java │ ├ ─ ─ StartTaskTypeEnum. Java │ └ ─ ─ handler │ ├ ─ ─ AbstractEventHandler. Java │ ├ ─ ─ AfterWorkingProcessHandler. Java │ ├ ─ ─ DataServerChangeEventHandler. Java │ ├ ─ ─ LocalDataServerChangeEventHandler. Java │ ├ ─ ─ MetaServerChangeEventHandler. Java │ └ ─ ─ StartTaskEventHandler. JavaCopy the code

3.2 the class definition

Class definitions are as follows:

public class EventCenter {

    private Multimap<Class<? extends Event>, AbstractEventHandler> MAP = ArrayListMultimap.create();

    /**
     * eventHandler register
     * @param handler
     */
    public void register(AbstractEventHandler handler) {
        List<Class<? extends Event>> interests = handler.interest();
        for(Class<? extends Event> interest : interests) { MAP.put(interest, handler); }}/**
     * event handler handle process
     * @param event
     */
    public void post(Event event) {
        Class clazz = event.getClass();
        if (MAP.containsKey(clazz)) {
            Collection<AbstractEventHandler> handlers = MAP.get(clazz);
            if(handlers ! =null) {
                for(AbstractEventHandler handler : handlers) { handler.handle(event); }}}else {
            throw new RuntimeException("no suitable handler was found:"+ clazz); }}}Copy the code

3.2.1 operation

Normal EventBus typically has three operations:

  • Register Listener–register (Object Listener);
  • Unregister Listener–unregister (Object Listener);
  • Publish Event– POST (Object Event);

However, There is no logout operation in Ali’s EventCenter. As it is not needed in business, there are only the following interfaces.

  • Register (AbstractEventHandler Handler) is an AbstractEventHandler Handler that works to find out which events this Listener is interested in and register that event type and the corresponding Listener with the EventCenter.
  • When an event is posted, the list of handlers for the message is iterated, and the handlers are called one by one. Because the execution is synchronous, there is no need to maintain the order of the messages, otherwise you would need to use a queue to ensure that the events for each thread post are ordered;

The concrete use, for example, is as follows: in the MetaServerChangeEventHandler has the following code on the news.

eventCenter.post(new StartTaskEvent(set));

eventCenter.post(new DataServerChangeEvent(result.getNodes(), versionMap,
        DataServerChangeEvent.FromType.REGISTER_META));
Copy the code

3.2.2 Execution & decoupling

The handler declares what kind of events it supports. When registering, it will register itself in the eventCenter map with the event as the key. In the POST function, according to the class of the event, the handler is extracted and executed. Also decoupled.

3.2.3 the Listener list

In observer mode, a list of listeners is maintained in an event source, and listeners registered with this event source are generally notified of only one class of events. If a Listener is interested in multiple events of different classes, it needs to register with multiple event sources.

How does EventCenter register a Listener once, knowing which events the Listener is interested in, and notifying the Listener when a certain type of event occurs?

The answer is in ArrayListMultimap, whose key is Event and whose Value is AbstractEventHandler. The map is a list of Event Event types and interested handlers. An Event can have multiple handlers.

3.2.4 ArrayListMultimap

As the name implies, com.google.com mon. Collect. ArrayListMultimap can set up a corresponding value in the key ArrayList. This ensures that an event can have more than one handler.

See the following examples.

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

import java.util.Collection;

public class testArrayListMultimap {
     static void main(a) {
        Multimap<String, String> multimap = ArrayListMultimap.create();
        multimap.put("fruit"."banana");
        multimap.put("fruit"."apple");
        multimap.put("fruit"."apple");
        multimap.put("fruit"."peach");
        multimap.put("fish"."crucian");
        multimap.put("fish"."carp");

        System.err.println(multimap.size());/ / 6
        Collection<String> fruits = multimap.get("fruit");
        System.err.println(fruits);//[bannana, apple, apple, peach]}}Copy the code

3.3 the Listener

Listener is implemented by an AbstractEventHandler derived class.

3.3.1 base class

AbstractEventHandler Base class AbstractEventHandler

public abstract class AbstractEventHandler<Event> implements InitializingBean {

    @Autowired
    private EventCenter         eventCenter;

    @Override
    public void afterPropertiesSet(a) throws Exception {
        eventCenter.register(this);
    }

    /**
     * event handle func
     * @param event
     */
    public void handle(Event event) {
            doHandle(event);
    }

    public abstract List<Class<? extends Event>> interest();

    public abstract void doHandle(Event event);
}
Copy the code

Its main functions are as follows:

  • Derived classes must implement interest to declare what events they want to handle, and events are configured in an array so that a function can handle multiple events.
@Override
public List<Class<? extends LocalDataServerChangeEvent>> interest() {
    return Lists.newArrayList(LocalDataServerChangeEvent.class);
}
Copy the code
  • Derived classes implement doHandle to handle messages;

  • Because of the Settings in afterPropertiesSet, every Handler that inherits this class is automatically registered with EventCenter.

3.3.2 rainfall distribution on 10-12 derived class

MetaServerChangeEventHandler, for example, as long as the interest function declared in his interest in which messages, realize the business in the doHandle function.

public class MetaServerChangeEventHandler extends AbstractEventHandler<MetaServerChangeEvent> {
  
    @Override
    public List<Class<? extends MetaServerChangeEvent>> interest() {
        return Lists.newArrayList(MetaServerChangeEvent.class);
    }
  
		@Override
    public void doHandle(MetaServerChangeEvent event) {... }}Copy the code

3.3.2 Automatic registration

I need to talk specifically about automatic registration, because it is easy for new contacts to be surprised by omissions.

Automatic registration is done using Spring’s afterPropertiesSet method.

The afterPropertiesSet method can be configured for a specific bean and will be called after all the bean properties have been initialized, but before init. AfterPropertiesSet must implement the InitializingBean interface.

package org.springframework.beans.factory;

public interface InitializingBean {
    void afterPropertiesSet(a) throws Exception;
}
Copy the code

The base class AbstractEventHandler implements the InitializingBean interface.

public abstract class AbstractEventHandler<Event> implements InitializingBean
Copy the code

Each derived class registers the derived class itself with eventCenter.

@Override
public void afterPropertiesSet(a) throws Exception {
    eventCenter.register(this);
}
Copy the code

3.4 Core Message

When it comes to business, EventCenter handles three types of messages:

  • DataServerChangeEvent is a node change message of other Data servers.
  • MetaServerChangeEvent, Meta Sever change message;
  • StartTaskEvent:;

There are three message processing handlers:

  • public class DataServerChangeEventHandler extends AbstractEventHandler

  • public class MetaServerChangeEventHandler extends AbstractEventHandler

  • public class StartTaskEventHandler extends AbstractEventHandler

We use StartTaskEvent as an example, where the message content is set according to the business.

public class StartTaskEvent implements Event {
    private final Set<StartTaskTypeEnum> suitableTypes;

    public StartTaskEvent(Set<StartTaskTypeEnum> suitableTypes) {
        this.suitableTypes = suitableTypes;
    }

    public Set<StartTaskTypeEnum> getSuitableTypes(a) {
        returnsuitableTypes; }}Copy the code

3.5 Main Logic

The main logic of EventCenter is shown in the following figure:

          +------------------------------+
          | MetaServerChangeEventHandler |
          +-----------+------------------+
                      |
                      |  post(newStartTaskEvent) | | | +------------------------+ v | StartTaskEventHandler | +---------------------+-----------------------+ | | | EventCenter | | +--------------------+ | | | | | | | | +-----------------------------------------+ +---------------------> doHandle | | | |Multimap< <Event>, AbstractEventHandler> | | | | | | | +-----------------------------------------+ | <--------------+ afterPropertiesSet | | | | register | | | | +---------------------------------------------+ | | interest | | | | | | | +--------------------+  | +------------------------+Copy the code

The phone is shown below:

0 x04 summary

SOFARegistry EventCenter functions like most industry buses: it logically decouples event receivers and sages, simplifying communication between components. But Ali’s implementation has its own characteristics, and developers can learn from the tips and ideas here.

The answers to our previous questions are as follows:

  • Because an event often has multiple sources of delivery, how do you decouple the logic between event delivery and event processing?
    • The handler declares what kind of events it supports. When registering, the handler uses the event as the key and registers itself in the eventCenter map. In the POST function, depending on the class of the event, the handler is removed and executed, which is also decoupled.
  • How do you register a Listener once to know which events the Listener is interested in, and then notify the Listener when a certain type of event occurs?
    • Answer: Derived classes must implement interest to declare what events they want to handle;
  • How can a Listener handle multiple events?
    • Answer: Following the question, events are configured in an array, which allows a function to handle multiple events.
  • How can an event be processed by multiple Listeners?
    • Answer: use ArrayListMultimap to implement the listener list;
  • Can the registration process be simplified?
    • Answer: Automatic registration, derived classes do not need to worry about. AfterPropertiesSet is set so that every Handler that inherits this class is automatically registered with the EventCenter.
  • Do you need to maintain message order?
    • Answer: No, because it is synchronous;
  • Are messages processed asynchronously or synchronously?
    • Answer: Here is synchronization;
  • Should multiple same messages be merged?
    • Answer: There is no merging, no business requirement;

0 XFF reference

EventBus analysis in Guava

How does ant Financial Service registry realize the smooth scaling of DataServer

Ant gold uniform service registry SOFARegistry parsing | service discovery path optimization

The service registry Session storage policy | SOFARegistry parsing

Introduction to the Registry – SOFARegistry architecture for Massive Data