什么是微服務?微服務之間是如何獨立通訊的?


什么是微服務

  • 微服務架構是一個分布式系統,按照業務進行划分成為不同的服務單元,解決單體系統性能等不足。
  • 微服務是一種架構風格,一個大型軟件應用由多個服務單元組成。系統中的服務單元可以單獨部署,各個服務單元之間是松耦合的。

微服務概念起源:Microservices

微服務之間是如何獨立通訊的

同步

REST HTTP 協議

REST 請求在微服務中是最為常用的一種通訊方式,它依賴於 HTTP\HTTPS 協議。RESTFUL 的特點是:

  1. 每一個 URI 代表 1 種資源
  2. 客戶端使用 GET、POST、PUT、DELETE 4 個表示操作方式的動詞對服務端資源進行操作:GET 用來獲取資源,POST 用來新建資源(也可以用於更新資源),PUT 用來更新資源,DELETE 用來刪除資源
  3. 通過操作資源的表現形式來操作資源
  4. 資源的表現形式是 XML 或者 HTML
  5. 客戶端與服務端之間的交互在請求之間是無狀態的,從客戶端到服務端的每個請求都必須包含理解請求所必需的信息

舉個例子,有一個服務方提供了如下接口:

@RestController
@RequestMapping("/communication")
public class RestControllerDemo {
    @GetMapping("/hello")
    public String s() {
        return "hello";
    }
}

另外一個服務需要去調用該接口,調用方只需要根據 API 文檔發送請求即可獲取返回結果。

@RestController
@RequestMapping("/demo")
public class RestDemo{
    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/hello2")
    public String s2() {
        String forObject = restTemplate.getForObject("http://localhost:9013/communication/hello", String.class);
        return forObject;
    }
}

通過這樣的方式可以實現服務之間的通訊。

RPC TCP 協議

RPC(Remote Procedure Call)遠程過程調用,簡單的理解是一個節點請求另一個節點提供的服務。它的工作流程是這樣的:

  1. 執行客戶端調用語句,傳送參數
  2. 調用本地系統發送網絡消息
  3. 消息傳送到遠程主機
  4. 服務器得到消息並取得參數
  5. 根據調用請求以及參數執行遠程過程(服務)
  6. 執行過程完畢,將結果返回服務器句柄
  7. 服務器句柄返回結果,調用遠程主機的系統網絡服務發送結果
  8. 消息傳回本地主機
  9. 客戶端句柄由本地主機的網絡服務接收消息
  10. 客戶端接收到調用語句返回的結果數據

舉個例子。

首先需要一個服務端:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * RPC 服務端用來注冊遠程方法的接口和實現類
 */
public class RPCServer {
    private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    private static final ConcurrentHashMap<String, Class> serviceRegister = new ConcurrentHashMap<>();

    /**
     * 注冊方法
     * @param service
     * @param impl
     */
    public void register(Class service, Class impl) {
        serviceRegister.put(service.getSimpleName(), impl);
    }

    /**
     * 啟動方法
     * @param port
     */
    public void start(int port) {
        ServerSocket socket = null;
        try {
            socket = new ServerSocket();
            socket.bind(new InetSocketAddress(port));
            System.out.println("服務啟動");
            System.out.println(serviceRegister);
            while (true) {
                executor.execute(new Task(socket.accept()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class Task implements Runnable {
        Socket client = null;

        public Task(Socket client) {
            this.client = client;
        }

        @Override
        public void run() {
            ObjectInputStream input = null;
            ObjectOutputStream output = null;
            try {
                input = new ObjectInputStream(client.getInputStream());
                // 按照順序讀取對方寫過來的內容
                String serviceName = input.readUTF();
                String methodName = input.readUTF();
                Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
                Object[] arguments = (Object[]) input.readObject();
                Class serviceClass = serviceRegister.get(serviceName);
                if (serviceClass == null) {
                    throw new ClassNotFoundException(serviceName + " 沒有找到!");
                }
                Method method = serviceClass.getMethod(methodName, parameterTypes);
                Object result = method.invoke(serviceClass.newInstance(), arguments);

                output = new ObjectOutputStream(client.getOutputStream());
                output.writeObject(result);
            } catch (Exception e) {
                e.printStackTrace();

            } finally {
                try {
                    // 這里就不寫 output!=null才關閉這個邏輯了
                    output.close();
                    input.close();
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }

}

其次需要一個客戶端:

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.InetSocketAddress;
import java.net.Socket;

/**
 * RPC 客戶端
 */
public class RPCclient<T> {
    /**
     * 通過動態代理將參數發送過去到 RPCServer ,RPCserver 返回結果這個方法處理成為正確的實體
     */
    public static <T> T getRemoteProxyObj(final Class<T> service, final InetSocketAddress addr) {

        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                Socket socket = null;
                ObjectOutputStream out = null;
                ObjectInputStream input = null;
                try {
                    socket = new Socket();
                    socket.connect(addr);

                    // 將實體類,參數,發送給遠程調用方
                    out = new ObjectOutputStream(socket.getOutputStream());
                    out.writeUTF(service.getSimpleName());
                    out.writeUTF(method.getName());
                    out.writeObject(method.getParameterTypes());
                    out.writeObject(args);

                    input = new ObjectInputStream(socket.getInputStream());
                    return input.readObject();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    out.close();
                    input.close();
                    socket.close();
                }
                return null;
            }
        });

    }

}

再來一個測試的遠程方法。

public interface Tinterface {
    String send(String msg);
}

public class TinterfaceImpl implements Tinterface {
    @Override
    public String send(String msg) {
        return "send message " + msg;
    }
}

測試代碼如下:

import com.huifer.admin.rpc.Tinterface;
import com.huifer.admin.rpc.TinterfaceImpl;

import java.net.InetSocketAddress;

public class RunTest {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                RPCServer rpcServer = new RPCServer();
                rpcServer.register(Tinterface.class, TinterfaceImpl.class);
                rpcServer.start(10000);
            }
        }).start();
        Tinterface tinterface = RPCclient.getRemoteProxyObj(Tinterface.class, new InetSocketAddress("localhost", 10000));
        System.out.println(tinterface.send("rpc 測試用例"));

    }
}

輸出 send message rpc 測試用例

異步

消息中間件

常見的消息中間件有 Kafka、ActiveMQ、RabbitMQ、RocketMQ ,常見的協議有 AMQP、MQTTP、STOMP、XMPP。這里不對消息隊列進行拓展了,具體如何使用還是請移步官網。

作者:HuiFer
鏈接:什么是微服務?微服務之間是如何獨立通訊的?
來源:github


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM