This article was first published on the public account: Songhua preserved egg bulletin board

The author works for JINGdong, and has an in-depth understanding of stability assurance, agile development, advanced JAVA, and microservices architecture

I. Module subcontracting

On the whole, subcontracting is carried out in layers, and then each package is divided into API package and specific scheme package, from which three points need to pay attention to are extracted

  • 1.1 Degree of reuse 1) Classes in the package should have the same possibility of reuse 2) classes that work closely together should be placed in the same package 3) For change factor, classes in the package should be changed completely or not changed at all 4) Changes should be terminated within the package and should not be propagated to other packages
  • 1.2 Stability 1) Dependent packages are always more stable than dependents 2) Do not make a stable package dependent on unstable packages 3) one-way dependence, acyclic dependence
  • 1.3 Degree of abstraction 1) The more stable a package is, the more abstract it should be. 2) The instability of an abstract package causes all its dependent packages to be in constant change

Microkernels and plug-ins for framework extensions

Most of the better developed frameworks adhere to the concept of microkernel, Eclipse microkernel is OSGi(relying on meta-INF/manifest.MF configuration), Spring microcore is BeanFactory, Maven microcore is Plexus, Dubbo’s microcore is an SPI(dependent on meta-INF /services/com.xxx.xxx configuration). In general, the core should not have functionality, but rather a lifecycle and integration container that loads, unloads, and runs plug-in modules so that functionality can interact and extend in the same way, and any functionality can be replaced. If not, at least the third party should be treated equally, that is, the functions that the original author can achieve. The extender should be able to achieve all the functions through extension, and the original author should regard himself as the extender, so as to ensure the sustainability of the framework and the stability from inside to outside.

3. Equal treatment of third parties for framework extension

  • 3.1 Dogfoodin- Eat your own dog food 1) The framework’s own functions have extension points to achieve 2) the loading mode of microkernel can also be extended
  • 3.2 Autowire- Dependency injection 1) Assembly logic is accomplished by mutual assistance between extension points 2) eliminating hard-coded Bridges and intermediate code
  • 3.3 Cascading- Cascading 1) Cascading expansion granularity, hierarchical breakdown 2) loading small extension points from large extension points
  • 1) Only interact with extension points within reach and forward indirectly 2) keep behavior single and input and output clear 3) One object should know the least about other objects

4. Filter-chain model of framework extension

An event processing process is dispatched to a set of execution objects that form a chain structure over which event processing is passed

Fifth, outside of the framework extension lifecycle

The framework should not control the life cycle of implementation classes. At most, the framework provides utility classes for auxiliary management, not absolute control, and should satisfy the following specifications

  • 1. Try to refer to instances of external objects, not class elements. Correct examples: usrinstance.xxx (),Spring IoC, incorrect examples: class.forname (userClass).newinstance ().xxx
  • 2. Use IoC injection to reduce the static factory approach. Example: correct setXxx (XXX), error example: XxxFactory. GetXxx (), applicationContext) getBean (” XXX “)

Consistent data model for framework extension

URL as a public contract of Dubbo, all extension points contain URL parameters, and URL as context information runs through the whole extension point design system. All configuration information is converted to URL parameters, all meta information is transmitted using URLS, and all interfaces can obtain urls

7. Domain model division

  • 1. Service domain: also known as behavior domain, as the functional set of components, responsible for the lifecycle management of both the entity domain and the session domain, such as Velocity’s Engine\Spring’s BeanFactory
  • 2. Entity domain: The object model that represents operations, around which any product has a core concept, such as Velocity’s Templcat\Spring beans
  • 3. Session domain: Represents the transient state of each operation or run. It is created before operation and destroyed after operation, such as the Invocation in Spring

Advantages of domain model division: clear structure, can be directly applied; Hyperemia model, solid domain zone behavior; Variable and immutable state separation, variable state concentration; All domains are thread-safe and do not require locking

Dubbo core domain model

  • 1. Service domain Protocol: The main function entry of Invoker exposure and reference, responsible for the life cycle management of Invoker
  • 2. Instance domain Invoker: It is the core model of Dubbo, to which any model can be drawn or transformed. It represents an executable that invokes, either a local implementation, a remote invocation, or a cluster implementation
  • 3. Session domain Invocation: Invocation variables, such as method names and parameters, are held

Domain model thread safety

  • 1. Service domains: Usually stateless and thread-safe
  • 2. Entity domains: Are thread-safe by designing them as immutable classes, with all attributes read-only, or by replacing entire class references
  • 3. Session domain: keep all variable states, and the session domain is only used in the thread stack, each call is created in the thread stack instance, call on the destruction, is thread safety

10. API and SPI separation

Apis in Dubbo, such as ServiceConfig\ReferenceConfig\RpcContext, are for users, spIs in Dubbo, such as Protocol\Transporter\LoadBalance, are for extenders, The API should be declarative, describing what is required, and the SPI should be procedural, describing how to implement it. They should not be mixed together, and the user should not see the implementation written by the extender

11. API can be configured and must be programmable

  • 1. Configuration to simplify common use
  • 2. Programming interface for framework integration

Xii. Piping and distribution

Pipes are generally suitable for composite behavior, and the main functionality is implemented with cross-sectional AOP, such as servlets. Dispatch generally applies to policy behavior, and the main function is realized by events, such as Flux

Main process interception

No common framework can Cover all the requirements, whether it is the request response flow of the Web framework, the SQL-mapping process of the ORM framework, or the call process of the Service framework, allowing external behavior is the basic extension of the framework. Otherwise you have to hack the source code if you need to add security, journaling, or modify paging SQL

Dubbo call procedure interception

Dubbo uses the full pipe design, the framework itself logic, are implemented using cross section interception, such as the common consumer end context\collect\generic\ Activelimit \monitor\future and other chain filters, Chain filters such as Token/Exception/echo/Accesslog/Trace/executelimit are common in the production end

Xv. Event distribution

Interceptors take effect before and after pointcuts. They interfere with the process and trigger non-critical behavior, whereas events are based on state data and trigger state observer behavior

Reactor and Proactor event driven models

The Reactor model focuses on the ready state, such as notifying us to actively read when it is readable, similar to Linux epoll, while ProActor cares about the completed state, such as the memory address (Buffer) and read event that we specify to store data. It will notify us when it’s finished, similar to the Windows IO Completion Port

Dubbo exposes/references/calls events

Dubbo uses a chain of interceptors along the critical path to separate responsibilities and keep the interface functional and trouble-free. If a non-critical path is deployed, the main process is not affected even if the distribution fails

Coordinated defense

  • 1. Reliability separation. Unreliable operations should be minimized
  • 2. State separation. Stateful fields should be minimized, and immutable classes should be declared final
  • 3. Verify status. Fail early, and assert all at the entrance when there are incoming parameters or state changes
  • 4. Exception defense. Do not eat exceptions raw. Try to ensure that the exception information provides a solution and that the journal information contains context
  • 5. Reduce the unbounded nature of modification and do not bury mines. Avoid branching processes based on exception types, while keeping the NULL and Empty semantics consistent

Open and close principle

The open closed principle, open to extension, closed to change, because risk often comes from change. Embrace changes by inheriting the original class and overriding the method extension logic, not by modifying the original class

20. Incremental and expansive

If there is an existing scenario of stateless message sending and a new session message sending requirement is added later, if incremental expansion is adopted, the stateless message sending remains unchanged, the synchronous message sending is implemented, and a Request/Response processing is added on the basis of the stateless message, and the session message is sent. Add a SessionRequest/SessionResponse processing

Dubbo incremental expansion

The traditional C\S model is a q&A model, while Dubbo’s RPC model includes Proxy\Custer\Protocol. Protocol is only responsible for Protocol implementation, which is opaque and point-to-point. Cluster is only responsible for pretending multiple providers in the Cluster as one. Proxy is only responsible for transparent interface, bridge dynamic Proxy, the overall architecture is very easy to expand

22. Additional functions at higher levels

Rely on low-level contracts as little as possible and implement functionality with as little abstraction as possible. While low-level switching is implemented, higher-level functionality can continue to be reused

Dubbo high order Generalization call

Taking the method name and method parameters in the REQUEST body from PHP to Router as the input parameters of the Router remote call to the backend Java service, and finally returning the result of the remote call to PHP is a high-level generalization call compatible with Restful services

24. Conclusion

Article source: www.liangsonghua.me Author introduction: Liang Songhua, senior engineer of JINGdong, focuses on stability assurance, agile development, JAVA advanced and micro-service architecture for a long time