Application of Microkernel Architecture in Large Front-end System (Microfront-end)

Talk about architecture, not framework. In addition to the “micro front end”, another idea of building high elastic architecture is proposed.

1

A group of software programs that minimize the number of programs that provide and implement the mechanisms and functions required by an operating system. These basic mechanisms include low-level address space management, thread management, and interprocess communication.

2. Design concept

Distinguish the implementation of the system from the basic operating rules of the system. It is implemented by modularizing core functions into several independent processes, each running separately, called services. All server processes run in different address Spaces.

Keeping services separate reduces coupling between systems, makes it easier to implement and debug, and improves portability. It can avoid the failure of a single component and cause the whole system crash. The kernel only needs to restart this component, so that the functions of other servers will not be affected, and the system stability will be increased. At the same time, some service processes can be replaced or added as required to make the function more flexible.

In terms of code volume, core systems generally use less code than integrated systems because of their simplified functionality. Less code means fewer bugs lurking.

3. Specific application

The microkernel architecture is used with two main considerations: “core system” and “plug-in module”. The application logic is divided into separate “core systems” and “plug-in modules” to provide good scalability and flexibility, and the application’s new features are isolated from the underlying business logic.

First, the core system

The core system is usually a minimal module that can run on its own, as operating systems (Windows NT, Mac OS X) do. From a business application perspective, core systems provide general business logic for specific scenarios, rules, and complex conditional judgments, while plug-in modules provide more specific business logic. The core system can be added or extended to achieve the ability to generate additional business logic.

Second, plug-in module

A plug-in module is typically a standalone component that specializes in handling additional features. In general, plug-in modules have no dependencies on each other. Of course, you can create plug-ins that depend on other plug-in modules, but it is important that plug-in modules communicate with each other without dependencies.

3. Obtain the plug-in module and judge its availability

The core system needs to know the availability of each plug-in and how to get them, and a common way to do this is to use a set of registries. The registry contains basic information about each plug-in, including its name, data specification, remote access protocol (depending on how the plug-in module connects to the core system), and other custom data. For example, the upload plug-in for uploading files in Baidu web disk provides the plug-in name, data specification (input and output data), data format (JSON and XML), and if the plug-in is loaded asynchronously, there is also a specific remote HTTP access protocol address.

Connect to the core system

Plug-in modules can connect to the core system in a variety of ways, including OSGI (Open Service Gateway Initiative), messaging mechanisms, Web services, and point-to-point binding (object instantiation, both dependency injection). The implementation mode depends on specific application scenarios and special requirements (single-machine deployment and distributed deployment). The microkernel architecture does not require specific implementation modes by default, but it must ensure that plug-in modules do not rely on each other.

5. Communication standards

The communication specification between plug-in module and core system is divided into standard specification and custom specification. The custom specification usually means that a plug-in module is developed by a third party service. In this case, an Adapter needs to be provided between the custom specification and the standard specification so that the core system does not need to care about the specific implementation of each plug-in module. It is important to have a versioning strategy before designing a standard specification.

6. Event mode

The core system provides a variety of event modes, mainly including the commonly used point-to-point mode, publish and subscribe mode. Meanwhile, events are classified into global (system-level) events, system internal events and plug-in module internal events. Because there is no dependency between sender and receiver in point-to-point mode and a message corresponds to only one receiver, it can be used to broadcast global (system-level) events, such as calling up a plug-in module. In the publish-subscribe model, there is a time dependence between the subscriber and the publisher, which can be used for internal events of the system and plug-in modules. In addition, the core module can publish certain events that are part of the basic operation rules of the business through the publish-subscribe model.

7. Interface design

When a plug-in module is registered with the core system, a specific plug-in module can be invoked through system-level events. Core modules is required at this time to provide an interface belongs to the basic operation rules for the use of plug-in modules, in the same way, the plug-in modules must also be run according to the communication specification provides entry (similar to a Java Main method), and data specification (parameter format, the returned data format), in order to guarantee plug-in modules can work correctly on the core system. The plug-in module is independent of the core system. However, according to specific requirements (providing pure data services and processing system data and information), the system services of the core module may be required to perform some customized functions. At this time, the core system needs to provide a Context object. And plug-in modules can only interact with the outside world through this context object. Context objects provide apis and events for basic operations (calling up other plug-in modules, calling up system services, and getting system information).

4. Use in the front-end system

The front-end system is regarded as an operating system, and the business logic of basic business operations is abstracted into a system kernel that can operate independently, while the business logic that does not belong to basic business operations is regarded as an application program to complete the installation, uninstallation, disabling, calling and startup functions.

In the large-scale front-end system with more and more functions and more and more responsibilities, if the flexibility, expansibility and flexibility of compatibility in the later stage are not well considered in the initial stage of the project, it is easy to appear awkward situation that the project is difficult to maintain or no one wants to touch, so the initial design is very important.

At present, large front-end single-page systems are divided into independent components according to business, decoupled and reused, and finally stacked, compiled and on-line by components. In this way, although the completion depends on good componentized design, considering the system’s expansibility, flexibility and elasticity, the whole system is tightly tied together and not well split according to the basic business and additional business. Of course, many good front-end engineers also consider this aspect, put forward the concept of micro front-end. However, the micro front end is still a relatively new concept and has not gone through many large front end system practices. The microkernel architecture has been practiced in the back-end services and front-end apps of operating systems and many products.

Define core modules and system services

The core module mentioned above is a minimum module that can run independently and contains the basic operating rules of the system. No plug-in module can still run normally and handle basic business logic, so the basic page and basic functions are individually packaged in a large front-end system to form a minimal module called Core System. The core system can be multiplexed across multiple systems (NPM, Bower, Bundle, JS Chunk) by package. At the same time, the business-related operations are encapsulated into multiple system services according to types and scenarios, and mounted (dependency injection) to the core system, which is called System Service. Note that core System can operate System Service, but System Service cannot operate Core System.

In addition, Core System exposes externally interactive apis and events, called standard interfaces, according to specific module specifications (AMD, CMD, CommonJS, ESM, SystemJS, UMD). In the future, the plug-in module should be developed in strict accordance with the standard interface.

Define plug-in modules

Plug-in module is a module (component) independent of the core system that deals with services that do not belong to the basic operation of the system, such as uploading, downloading, and sharing in web disks. Each plug-in module must be developed in accordance with the defined standard interface and communication specifications, and each plug-in module is independent of each other, so there are not too many requirements on the implementation details of each plug-in. For example, A plug-in module is developed using React, B plug-in module is developed using Vue, and C module is developed using jQuery.

Each plug-in module should provide a JSON file containing the plug-in module’s signature information (Mainfest), which includes the name of the plug-in, data specifications, dependencies, remote access addresses (asynchronously loaded JS download addresses), and other custom fields. Register the Mainfest file when the core system is loaded in the front end to complete the connection between the core system and the plug-in module.

Each plug-in module should provide a run entry with a uniform name, such as the start method. Plug-in lifecycle events can also be provided as standard interfaces for more fine-grained control.

Registration and tuning

Each plug-in provides its own Mainfest signature file and executable (JS file, CSS file). So when the server receives a browser request, it can merge the required plug-in Manifest, merge it into a large JSON structure, and return it to the browser. The browser receives it, executes the core system, registers the Manfiest information, and then launches. During the registration process, you can perform different operations such as startup (by default), preloading, and background running as required.

There may be a need to call up other plug-in modules in the business logic and plug-in internal logic, which cannot be called up directly because plug-in modules are independent of each other and the core system. However, because of the registry and the point-to-point event pattern, information such as the plug-in name and group, and the plug-in module ID can be passed through the API exposed by the core system to be invoked. Check whether the plug-in is registered, loaded (synchronous loading, asynchronous loading), singleton and mutex, parameter information and data format to ensure that it can be correctly invoked.

When an exception occurs during plug-in operation, the core module is notified through system-level events. The core module restarts or shuts down the plug-in module according to the identifier in the signature information.

Iv. Multi-entrance management

In a complex front-end system, the same function may have a single entry, such as upload, download, share and other functions are activated by clicking buttons in different locations. Typically, specific functionality (plug-in modules) is separated from the UI presentation of plug-in module entry. First, divide the basic page structure into different functional blocks as required, such as menu bar, right-click menu, list item, right side area, left side area, and define unique names and ids for these areas. In the Manifest of the plug-in module for which entry presentation is required, identify the entry area and presentation (buttons, images, bootstrap blocks, menu items, drop-down menus).

Core system after registration done in the registry, parsing the needs to show the entrance to the field and to the special rendering plug-in modules entry system services, this will be finished by configuring multiple entry management, in the subsequent changes in demand and change, you just need to change the Manifest file, more perfect system of expansibility, flexibility and elasticity.

5. Technology selection

An architecture exists independently of the framework and class libraries.

The core of the microkernel architecture is to isolate the basic operation of the business from the operation of professional processing extra features, and improve the scalability, flexibility and resilience of the system. Therefore, we need to consider three aspects when selecting the technology: core system, system service and plug-in module.

The core system usually contains the basic functions required by a project, including the basic display page, interactive operation, business processing, and the amount of code is usually very small; System services provide the common functions of business processing, such as list operation, pop-up box, prompt, asynchronous interface processing, etc., usually abstracting the common requirements in the system to this layer. Therefore, these two aspects can be standardized by using the current common React or Vue tools through webpack development, but how to expose the core system API and events to the external plug-in module call is a very important problem.

Plugin modules tend to be specialized lib libraries that handle additional features, so it is recommended to develop and package them using rollup or WebPack lib mode to produce a “clean” bundle (which can also be published to NPM for independent distribution and maintenance). It is important to note that if the bundle is developed according to defined standard specifications, it can run under any microkernel architecture to achieve cross-system capability. Just as programs written to X86 specifications can run on any X86 architecture system.

How do I load the plug-in module bundle asynchronously when I call the plug-in module?

I. Plug-in module development stage

The code for the source Code plug-in module is placed in a root folder and developed and compiled from source code. After each change, a bundle and Manifest file can be generated by rollup or Webpack, and then updated online.

In this mode, after the code of the plug-in module is updated, the corresponding Manifest file is also updated, so the core system loaded into the plug-in module is also updated, without any operation of the basic business logic. Advantages: No need to update and live the underlying business code. Disadvantages: no version number management function and not easy to test.

Solution 2: Release the NPM install plug-in module to github, GitLab and other hosting platforms, and install it into the basic business logic through NPM. The plug-in module needs to be re-published to the hosting platform after each change, and NPM install XXX needs to be re-executed when the version number needs to be updated in the business logic, and then the business code is recompiled to go live.

After the plug-in module is updated, there is no need to live the plug-in module as in scenario 1. Instead, update the dependencies of the business logic and install the latest version of the plug-in module. Advantages: Different stages of plug-in modules can be loaded by version number and easy to test. Disadvantages: You need to reinstall the plug-in module and recompile and online the business logic that depends on the plug-in module. Regression costs are high, and the underlying business logic must be regressive in addition to the plug-in module (you could do that as option 1, of course, but that would eliminate the greatest benefit of NPM -> version number management).


Obtain the Manifest signature information of the plug-in module

Solution 1: Render directly into HTML When the server receives a page request from the browser, the server merges the Manifest signature file of the plug-in module required for the page, outputs the file into HTML, and returns the file to the browser.

Scenario 2: Asynchronously fetch the Manifest signature information set after the Merge from the server via the Async and defer functions of script tags or AJAX.


Remote access protocol

When the core system calls the plug-in module, it can load it asynchronously through the HTTP address of the remote access protocol declared by the plug-in.

Solution 1: Manifest signature file Stores the remote access protocol of the plug-in module in the Manifest signature information, for example, uploading the signature of the plug-in module.

{// Plugin name" name": "upload", // group" group": "com.xxx.xxx", // preload plugin module resource "preload": true, // data specification, require input parameter "arguments": {// Context Object" CTX ": {"type": "Object", "required": true}, // File information to be uploaded "file": {"type": "Object", "required": False}}, / / remote access protocol "entrance" : "http://www.a.com/static/plugin-bundles/upload-0.0.1.min.js"}Copy the code

Option 2: Async interface + import()

The scheme is that the remote access protocol of the system plug-in module is not placed in the Manifest of the plug-in module, but the remote access protocol is obtained through the asynchronous interface request. The plug-in resources are then loaded via webpack’s require.Ensure () or ESM’s import().

// CTX is the core system context object
ctx.loadPlugInAdapter = (pluginName, groud) = > {
	// Upload the remote access protocol of the plug-in module through the interface request
    fetchEntrance(pluginName, group).then(url= > {
	    // The core system executes the plug-in module
	    ctx.invoke(pluginName, url);
    });
}

// Call up the plug-in module
ctx.loadPlugInAdapter('upload'.'com.xxx.xxx');
Copy the code

The last

Architecture and framework are independent. This paper only puts forward an architectural idea, and this architecture is also applied in a complex front-end product of Baidu with a large number of users. Based on this elastic architecture and the modern development concept of Vue/React, the front-end system with high complexity can be well completed. Hopefully, this article has provided you with an alternative approach to building highly resilient front-end systems in addition to microfronts.