preface

Structural changes are often due to business scale.

With the expansion of business scale, in order to meet the technical requirements of business, the technical architecture needs to be upgraded from single application architecture to distributed service architecture to reduce the technical cost of the company and better adapt to the development of business.

Many advantages of distributed service architecture are not listed here. Today’s topic is service framework. In order to implement sertization, it is necessary to have a set of easy-to-use service framework to support the upgrade of business technology architecture.

Service framework

The core of service architecture is service invocation. In distributed service architecture, services are distributed in different processes of different hosts. The essential difference between service invocation and in-process method invocation of single application is that it needs to communicate with network.

RPC Demo implementation ideas

Liang Fei, the original author, recorded his very concise RPC implementation ideas here.

Core framework class

/* * Copyright 2011 Alibaba.com All right reserved. This software is the * confidential and proprietary information of Alibaba.com ("Confidential * Information"). You shall not disclose such Confidential Information and shall * use it only  in accordance with the terms of the license agreement you entered * into with Alibaba.com. */
package com.alibaba.study.rpc.framework;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * RpcFramework
 * 
 * @author william.liangf
 */
public class RpcFramework {

    /** ** Exposure services **@paramService Service implementation *@paramPort Service port *@throws Exception
     */
    public static void export(final Object service, int port) throws Exception {
        if (service == null)
            throw new IllegalArgumentException("service instance == null");
        if (port <= 0 || port > 65535)
            throw new IllegalArgumentException("Invalid port " + port);
        System.out.println("Export service " + service.getClass().getName() + " on port " + port);
        ServerSocket server = new ServerSocket(port);
        for(;;) {
            try {
                final Socket socket = server.accept();
                new Thread(new Runnable() {
                    @Override
                    public void run(a) {
                        try {
                            try {
                                ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
                                try{ String methodName = input.readUTF(); Class<? >[] parameterTypes = (Class<? >[])input.readObject(); Object[] arguments = (Object[])input.readObject(); ObjectOutputStream output =new ObjectOutputStream(socket.getOutputStream());
                                    try {
                                        Method method = service.getClass().getMethod(methodName, parameterTypes);
                                        Object result = method.invoke(service, arguments);
                                        output.writeObject(result);
                                    } catch (Throwable t) {
                                        output.writeObject(t);
                                    } finally{ output.close(); }}finally{ input.close(); }}finally{ socket.close(); }}catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            } catch(Exception e) { e.printStackTrace(); }}}/** ** references service **@param<T> Interface generic *@paramInterfaceClass Interface type *@paramHost Indicates the host name of the server@paramPort Indicates the server port *@returnRemote Service@throws Exception
     */
    @SuppressWarnings("unchecked")
    public static <T> T refer(final Class<T> interfaceClass, final String host, final int port) throws Exception {
        if (interfaceClass == null)
            throw new IllegalArgumentException("Interface class == null");
        if (! interfaceClass.isInterface())
            throw new IllegalArgumentException("The " + interfaceClass.getName() + " must be interface class!");
        if (host == null || host.length() == 0)
            throw new IllegalArgumentException("Host == null!");
        if (port <= 0 || port > 65535)
            throw new IllegalArgumentException("Invalid port " + port);
        System.out.println("Get remote service " + interfaceClass.getName() + " from server " + host + ":" + port);
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), newClass<? >[] {interfaceClass},new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
                Socket socket = new Socket(host, port);
                try {
                    ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
                    try {
                        output.writeUTF(method.getName());
                        output.writeObject(method.getParameterTypes());
                        output.writeObject(arguments);
                        ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
                        try {
                            Object result = input.readObject();
                            if (result instanceof Throwable) {
                                throw (Throwable) result;
                            }
                            return result;
                        } finally{ input.close(); }}finally{ output.close(); }}finally{ socket.close(); }}}); }}Copy the code

Defining service Interfaces

/* * Copyright 2011 Alibaba.com All right reserved. This software is the * confidential and proprietary information of Alibaba.com ("Confidential * Information"). You shall not disclose such Confidential Information and shall * use it only  in accordance with the terms of the license agreement you entered * into with Alibaba.com. */
package com.alibaba.study.rpc.test;

/**
 * HelloService
 * 
 * @author william.liangf
 */
public interface HelloService {

    String hello(String name);

}
Copy the code

Implementation services

/* * Copyright 2011 Alibaba.com All right reserved. This software is the * confidential and proprietary information of Alibaba.com ("Confidential * Information"). You shall not disclose such Confidential Information and shall * use it only  in accordance with the terms of the license agreement you entered * into with Alibaba.com. */
package com.alibaba.study.rpc.test;

/**
 * HelloServiceImpl
 * 
 * @author william.liangf
 */
public class HelloServiceImpl implements HelloService {

    public String hello(String name) {
        return "Hello "+ name; }}Copy the code

Exposed services

/* * Copyright 2011 Alibaba.com All right reserved. This software is the * confidential and proprietary information of Alibaba.com ("Confidential * Information"). You shall not disclose such Confidential Information and shall * use it only  in accordance with the terms of the license agreement you entered * into with Alibaba.com. */
package com.alibaba.study.rpc.test;

import com.alibaba.study.rpc.framework.RpcFramework;

/**
 * RpcProvider
 * 
 * @author william.liangf
 */
public class RpcProvider {

    public static void main(String[] args) throws Exception {
        HelloService service = new HelloServiceImpl();
        RpcFramework.export(service, 1234); }}Copy the code

Reference service

/* * Copyright 2011 Alibaba.com All right reserved. This software is the * confidential and proprietary information of Alibaba.com ("Confidential * Information"). You shall not disclose such Confidential Information and shall * use it only  in accordance with the terms of the license agreement you entered * into with Alibaba.com. */
package com.alibaba.study.rpc.test;

import com.alibaba.study.rpc.framework.RpcFramework;

/**
 * RpcConsumer
 * 
 * @author william.liangf
 */
public class RpcConsumer {
    
    public static void main(String[] args) throws Exception {
        HelloService service = RpcFramework.refer(HelloService.class, "127.0.0.1".1234);
        for (int i = 0; i < Integer.MAX_VALUE; i ++) {
            String hello = service.hello("World" + i);
            System.out.println(hello);
            Thread.sleep(1000); }}}Copy the code

summary

Liang Fei big blog using native JDK API to show you a vivid RPC demo, is really strong.

The idea behind this simple example is:

  • A blocked socket IO stream is used to communicate between the server and client, that is, the service provider and the service consumer in RPC applications. And it is end-to-end, using port numbers to communicate directly
  • Method is called remotely using the JDK’s dynamic proxy
  • The serialization of arguments is also the simplest objectStream to use

Service framework

The core of service framework is service invocation. In distributed service architecture, services are distributed in different processes of different hosts. The essential difference between service invocation and in-process method invocation of single application is that it needs to communicate with network.

The following figure shows the architecture of the service framework, which is the main implementation of the service framework, such as Dubbo, SpringCloud, etc.

  • Invoker is the caller of the service

  • Provider is a service Provider

  • Registry is the Registry of services

  • Monitor is the monitoring module of the service

It is clear that the Invoker and Provider are the invokers and callees of the service, respectively.

But these two are not enough, because the caller needs to know where the service is deployed and where to call the service, so there is a Registry module, whose function is to register the service for the service provider and discover the service for the service caller.

As a service monitoring module, Monitor is responsible for service invocation statistics and link analysis, and is also an important part of service governance.

The core module

The following figure is the flow chart of the service framework. We decompose the process from three aspects: service registration, discovery and invocation.

Service registration is the service provider to register service information to the registry. Responsible for deleting the service registration information from the registry when the provider application goes offline.

Service discovery is that the service caller subscribes to the service from the registry to obtain information about the service provider. The registry is responsible for notifying the service caller when the service registry information changes.

Service invocation means that the service caller initiates a service invocation to the service provider by getting the information of the service provider from the registry to obtain the invocation result.

According to the above flow chart, we analyze the specific process of the request.

The process of Invoker as a service Invoker is as follows:

  1. From bottom to top, the service caller can only get the API interface or JAR package of the API interface provided by the service provider, so the service caller needs to go through a layer of Proxy to disguise the implementation of the service.
  2. After passing through the Proxy, it passes through the routing Router, load balancing module, and the purpose is to select the most suitable service provider machine from the heap of service provider information obtained from the registry. In addition, it will also pass through the Monitor monitoring module;
  3. Then it goes through the service code Codec module, which is designed to encode and decode the transmitted request according to the communication protocol and object serialization before transmission over the network.
  4. It eventually passes through the network communications Transporter module, which transmits the Codec encoded requests.

The specific process of the service Provider is as follows:

  1. Request From the top down, the Transporter module obtains the Request byte array sent by the caller.

  2. Then through the service code Codec module, according to the communication protocol to solve a complete request package, and then use the specific serialization method deserialized into the request object.

  3. Then it will go through modules such as monitoring, traffic limiting, and authentication.

  4. Finally, the actual business implementation of the service, ServiceImpl, is executed, and the results are returned the way they were.

To break down the work of a service framework as described above, it is easy to understand some open source service frameworks.

The core modules of the general service framework should include registry, network communication, service coding (communication protocol, serialization), service routing, load balancing, service authentication, availability guarantee (service degradation, service traffic limiting, service isolation), service monitoring (Metrics, Trace), configuration center, service governance platform, etc.

The registry

The registry is used to register and discover services. The basic functions of the registry are registration services, offline services, discovery services, and notification of service changes.

Zookeeper, ETCD and Eureka are widely used open source registries.

Zookeeper and ETCD are similar in overall architecture. They are easy to use and widely used.

According to CAP theory, these two systems belong to CP system, and the usability will be poor, but as small and medium-sized service registry, it is still able to do well, not as bad as some people said. Eureka is part of the Spring Cloud Netflix Microservices suite. Unfortunately, Eureka 2.0 open source work has been discontinued.

Network communication

Both the caller and provider of the service come from different processes on different hosts, so network communication is necessary to make the call. It can be said that network communication is the top priority of distributed system and the quality of network communication framework directly affects the performance of service framework. It is very difficult to implement a high performance and strong stability communication framework from scratch. Fortunately, there are many open source high performance network communication framework. There are Mina and Netty for the Java ecosystem, and Netty is the most widely used one at present. Netty uses the Per Thread One Eventloop thread model, similar to other high-performance networking frameworks such as Nginx. In addition, Netty is very easy to use, so the Netty framework is a no-brainer for network communication.

Service code

Two things need to be done before a memory object can be transmitted over the network: first, the communication protocol is determined, and second, serialization.

Communication protocol

The communication protocol states that the data is processed in a certain format before it is sent, and then transmitted to ensure that the receiver gets the data and knows what format to process it in.

Some students may not understand why you need a communication protocol, isn’t there TCP, UDP protocol? This is not a transport layer protocol, but an application layer protocol similar to HTTP.

Because although the TCP protocol is to ensure the reliable and orderly transfer, but if you don’t have a set of application layer protocol, just don’t know if sending a byte data is a complete data request, or multiple requests bytes of data are together, can’t break up, this is the so-called glue bag, need to be carried out in accordance with the agreement unpacking, Break it into complete request packets for processing.

In terms of protocol implementation, large companies or open source service frameworks generally choose self-built protocols, which are more inclined to the service field. Dubbo, of course, there are frameworks that use HTTP directly, HTTP/2, such as GRPC.

serialization

Since the data sent to the network layer must be byte data, it is impossible to directly send an object to the network. Therefore, before sending object data, the object needs to be serialized into byte data and then transmitted.

When the server receives the bytes of data from the network, it needs to deserialize to the relevant objects.

Serialization implementations are readily available, such as Hessian, JSON, Thrift, ProtoBuf, etc. Thrift and ProtoBuf can support cross-language, performance is better, but use to write IDL files, a bit of trouble. Hessian and JSON are friendlier to use, but perform less well.


Service routing

Service routing refers to the process of invoking a service provider by selecting a number of machines from the server address information obtained from the registry according to a certain algorithm.

Routing algorithm is generally undertake choosing according to the scene, such as some companies implement a dual center three such a highly available deployment, but because of the dual network delay is large, the routing policy can implement the same area at this moment, such as Shanghai caller requests will be preferred Shanghai service call, to reduce the network latency caused by end-to-end service call time consuming.

There are also frameworks that support script configuration for directional routing policies.


Load balancing

Load balancer is the module following the service routing. Load balancer is responsible for evenly and reasonably sending the request to the node of the service provider, and the alternative machine is generally selected through the routing module.

There are many load balancing algorithms, such as RoundRobin, Random, LeastActive, and ConsistentHash.

And these algorithms are generally enhanced versions based on weights, because the traffic of each service node needs to be adjusted according to the weight.


Service authentication

Service authentication is the basis of service security invocation. Although most services are internal services, authentication is required for sensitive data.

An authenticated service requires authorization for the caller of the service. Unauthorized callers cannot invoke the service.

Most implementations of service authentication are token-based authentication schemes, such as JWT (JSON Web Token) authentication.


Availability assurance

Availability guarantee module is an important guarantee of service high availability.

Service interaction is mainly divided into two roles: caller and provider. As a service caller, availability can be improved through service degradation. As a service provider, service traffic limiting and service isolation can ensure availability.

Service degradation

Service degradation refers to the substitution of a default value for a service invocation when a dependent service is unavailable.

Imagine that if there is a problem with calling a service on a non-critical path (that is, whether the result of the call is real-time or correct is not particularly important), the call times out, fails, and so on, without degradation, the service caller business is directly applied.

Therefore, some non-critical path on the service invocation, service degradation can achieve lossy service, flexible availability. Open source downgrading components include Netflix’s Hystrix, which is widely used.

Service current limiting

Service degradation protects the caller of the service, that is, the dependent party of the service. What about the provider of the service, how do you guarantee the availability of the service? Service traffic limiting refers to the restriction of service invocation traffic and the frequency of invocation to protect services.

In a high-concurrency scenario, it is easy to have too much traffic, causing the service to crash. Here, traffic limiting is needed to ensure the stable operation of the service itself. Hystrix can also be used for flow limiting, but guava’s RateLimiter is more commonly used. It uses the token bucket algorithm to ensure smooth flow limiting.

Service isolation

Is it enough to protect the service provider in addition to service limiting? If this is not enough, consider a scenario where a problem occurs in one of the faulty methods and processing is time-consuming, blocking the entire service processing thread and preventing normal service methods from being invoked. Hence the need for service isolation. Service isolation refers to the thread pool isolation of the methods executed by the service to ensure that abnormal time-consuming methods do not interfere with normal method calls, thus protecting the stable operation of the service and improving availability.


Service monitoring

Service monitoring is an indispensable support for high availability systems.

Service monitoring includes not only business statistics Metrics such as service invocation, but also distributed link tracing.

Distributed system monitoring is more complex than single application, needs to be a large number of monitoring information aggregated show, especially in the area of distributed link tracking, because the service invocation process involves multiple distribution services on different machines, need a call link display system is convenient to check the call link time-consuming and the problems in the link.

Metrics

Metrics monitors statistics about service invocation, including the number of service invocation times, number of successes, number of failures, and invocation time of service methods, such as average time, time of 99 lines, and time of 999 lines. Full display of service availability and performance information.

Open source Metrics currently monitor Cat from Meituan Dianping, Prometheus from SoundCloud, and SkyWalking based on OpenTracking.

Trace

Trace monitoring is a presentation and analysis of the overall link in the process of a distributed service invocation. You can view the performance of each environment on the link.

The principle of Distributed link Tracing is mostly based on Google’s paper Dapper, a large-scale Distributed Systems Tracing Infrastructure. Open source distributed link tracking systems include Cat from Meituan Dianping, SkyWalking based on OpenTracking, and ZipKin from Twitter.


Configuration center

The configuration center is not only a common system requirement, but also a service framework. It can manage the configuration used in the system and dynamically notify the application system of configuration changes. A complete service framework must be configured, such as dynamic switch, degrade configuration, traffic limiting configuration, authentication configuration, etc.

Open source configuration centers include Alibaba’s Diamond and CTC’s Apollo.


Management platform

A governance platform is a platform that manages services.

If there is no perfect governance platform, it will be difficult to maintain the service scale after it expands, which will inevitably lead to frequent failures and greatly affect the development efficiency.

A governance platform is a platform for service functions, including service weight modification, service offline, and authentication degradation. There is a strong coupling between the governance platform and the service framework, so there is less open source.

other

This is the end of the RPC implementation.

Original is not easy, if you feel good, I hope to give a recommendation! Your support is the biggest motivation for my writing!

Copyright Notice:

Author: Mu Shuwei

Blog garden source: www.cnblogs.com/sanshengshu…

github.com/sanshengshu…

Sanshengshui.github. IO /