Clarence Java DocClarence Java Doc
开发总结
Java
数据库
缓存
JVM
Spring
微服务
消息队列
高并发
分布式
高可用
设计模式
场景题
Netty
云原生
算法
系统架构
开发协议
IOT
人工智能
开发总结
Java
数据库
缓存
JVM
Spring
微服务
消息队列
高并发
分布式
高可用
设计模式
场景题
Netty
云原生
算法
系统架构
开发协议
IOT
人工智能
  • 基本概述
  • 优势和挑战
  • 单体到微服务
  • 核心组件
  • 运维与监控
  • 解决方案
  • 微服务模式
  • 最佳实践与案例
  • Java总结-微服务

基本概述

一、什么是微服务?

  • 微服务架构是一个分布式系统,按照业务进行划分成为不同的服务单元,解决单体系统性能等不足。
  • 微服务是一种架构风格,一个大型软件应用由多个服务单元组成。系统中的服务单元可以单独部署,各个服务单元之间是松耦合的。

微服务概念起源:Microservices

二、微服务之间的通讯方案

1、同步方案:HTTP/RPC

REST HTTP 协议

REST 请求在微服务中是最为常用的一种通讯方式,它依赖于 HTTP\HTTPS 协议。RESTFUL 的特点是:

  • 每一个 URI 代表 1 种资源
  • 客户端使用 GET、POST、PUT、DELETE 等操作方式对服务端资源进行操作:
    • 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("Service 服务启动");
            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 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 测试用例 。

2、异步方案:消息中间件

常见的消息中间件有 Kafka、ActiveMQ、RabbitMQ、RocketMQ ,常见的协议有 AMQP、MQTTP、STOMP、XMPP。这里不对消息队列进行拓展了,具体如何使用还是请移步官网。

3、HTTP和RPC对比

RPC 和 HTTP 主要区别在于通信方式、使用场景、性能、协议特性等方面,具体对比如下:

1. 概念与本质

对比项RPC(Remote Procedure Call)HTTP(HyperText Transfer Protocol)
定义远程过程调用,像调用本地函数一样调用远程服务超文本传输协议,主要用于 Web 交互
目标让远程调用像本地调用一样透明规定数据如何在客户端和服务器之间传输

2. 主要区别

对比项RPCHTTP
通信方式多种协议(TCP、UDP、HTTP/2 等)仅基于 HTTP/HTTPS
调用风格以函数调用方式调用远程方法以 RESTful 方式访问资源(GET、POST 等)
数据格式Protobuf、Thrift、MessagePack 等二进制格式,性能高JSON、XML,文本格式,可读性高但体积大
性能高效,数据序列化后传输,适合低延迟高并发HTTP 头部大,序列化/反序列化开销较高,性能相对较低
适用场景微服务内部通信(如 gRPC、Thrift)Web 服务、第三方 API 调用
状态管理可以支持长连接、流式通信(如 gRPC 的流模式)REST API 无状态,每次请求需重新建立连接
支持异步支持(如 gRPC 支持 Async Stub)WebSocket、HTTP/2 Push 支持异步
开发方式代码生成器自动生成客户端/服务端 Stub,调用透明需要手写 HTTP 请求和解析响应

3. 适用场景

  • RPC 适用场景

    • 微服务架构内部通信(如 gRPC 在 Kubernetes 中的服务间调用)
    • 低延迟、高吞吐的场景(如高频交易、游戏服务器通信)
    • 需要流式数据处理(如 gRPC 双向流式通信)
  • HTTP 适用场景

    • Web 服务和 API(如 RESTful API)
    • 跨平台通信(如移动端、前端与后端交互)
    • 需要良好可读性和调试性的场景(JSON 易读,方便调试)

4. 总结

  • RPC 更适合高性能、低延迟的微服务通信,通常用于后端服务间调用,比如 gRPC、Thrift。
  • HTTP 更适合 Web API 和外部开放接口,适用范围更广,但性能相对低,如 RESTful API。

如果你的业务是 微服务内部通信,可以考虑 RPC(如 gRPC);如果是 对外提供 API,HTTP(REST API)会更合适。

Last Updated:
Contributors: hanchen, Clarence
Next
优势和挑战