什么是微服務
- 微服務架構是一個分布式系統,按照業務進行划分成為不同的服務單元,解決單體系統性能等不足。
- 微服務是一種架構風格,一個大型軟件應用由多個服務單元組成。系統中的服務單元可以單獨部署,各個服務單元之間是松耦合的。
微服務概念起源:Microservices
微服務之間是如何獨立通訊的
同步
REST HTTP 協議
REST 請求在微服務中是最為常用的一種通訊方式,它依賴於 HTTP\HTTPS 協議。RESTFUL 的特點是:
- 每一個 URI 代表 1 種資源
- 客戶端使用 GET、POST、PUT、DELETE 4 個表示操作方式的動詞對服務端資源進行操作:GET 用來獲取資源,POST 用來新建資源(也可以用於更新資源),PUT 用來更新資源,DELETE 用來刪除資源
- 通過操作資源的表現形式來操作資源
- 資源的表現形式是 XML 或者 HTML
- 客戶端與服務端之間的交互在請求之間是無狀態的,從客戶端到服務端的每個請求都必須包含理解請求所必需的信息
舉個例子,有一個服務方提供了如下接口:
@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)遠程過程調用,簡單的理解是一個節點請求另一個節點提供的服務。它的工作流程是這樣的:
- 執行客戶端調用語句,傳送參數
- 調用本地系統發送網絡消息
- 消息傳送到遠程主機
- 服務器得到消息並取得參數
- 根據調用請求以及參數執行遠程過程(服務)
- 執行過程完畢,將結果返回服務器句柄
- 服務器句柄返回結果,調用遠程主機的系統網絡服務發送結果
- 消息傳回本地主機
- 客戶端句柄由本地主機的網絡服務接收消息
- 客戶端接收到調用語句返回的結果數據
舉個例子。
首先需要一個服務端:
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