什么是微服务

  • 微服务架构是一个分布式系统,依照业务进行划分成为不同的服务单元,解决单体零碎性能等有余。
  • 微服务是一种架构格调,一个大型软件应用由多个服务单元组成。零碎中的服务单元能够独自部署,各个服务单元之间是松耦合的。
微服务概念起源: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。这里不对音讯队列进行拓展了,具体如何应用还是请移步官网。