RPC远程过程调用,实现不同服务之间的方法调用,使得程序能够像访问本地系统资源一样,通过网络传输访问远端服务。
java socket 实现 rpc
private static final ExecutorService executorService= Executors.newCachedThreadPool(); //服务的注册 /** * 接收 客户端的调用信息,method.invoke 调用目标方法。 * @param service 接口实现类 * @param port */ public static void provider(final Object service, int port) throws Exception { ServerSocket serverSocket=new ServerSocket(port); while (true){ final Socket socket = serverSocket.accept(); executorService.execute(new Runnable() { public void run() { try { ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream()); String method = inputStream.readUTF(); Object[] args = (Object[]) inputStream.readObject(); ObjectOutputStream stream = new ObjectOutputStream(socket.getOutputStream()); Object result = MethodUtils.invokeExactMethod(service,method, args); stream.writeObject(result); }catch (Exception e){ e.printStackTrace(); } } }); } }
/** * 通过代理拦截 服务接口 再通过socket将方法和参数传递到服务端 * @param interfaceClass 接口服务 * @param host * @param port */ public static <T> T consumer(final Class<T> interfaceClass, final String host,final int port){ //通过代理拦截 服务接口 return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),new Class[]{interfaceClass}, new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket=new Socket(host,port); try { ObjectOutputStream stream= new ObjectOutputStream(socket.getOutputStream()); stream.writeUTF(method.getName()); stream.writeObject(args); ObjectInputStream in= new ObjectInputStream(socket.getInputStream()); Object result = in.readObject(); return result; }catch (Exception e){ e.printStackTrace(); } return null; } }); }
Grpc:
1.
Maven.Projects\protobuf\protobuf:compile
,生成用于序列化的java文件。2.
Maven.Projects\protobuf\protobuf:compile-custom
,生成用于rpc的java代码。
RPC实现了服务消费者和服务提供者之间点对点调用流程,通信、数据序列化和反序列化,而分布式RPC,则在基础上增加了服务的负载均衡策略和实现、服务的注册、服务的高可用、服务治理等等。
soa设计原则
单一应用的问题:
- 业务模块边界不清,代码严重耦合。
- 所有业务都在同一服务,及其不利于开发和迭代,频繁发布等等。
- 某个模块出现问题,影响整体的应用。
服务治理:服务的依赖、负载均衡、链路监控、服务质量统计、服务自动发现、自动下线、服务注册中心等等。
RPC框架与服务治理结合构成一套基本的分布式服务框架。
RPC实现SOA服务化之后服务之间的通信,而服务治理实现服务的运维。
分布式服务框架主要包括服务消费端、服务提供端、服务数据网络传输的序列化和反序列化、服务数据的通信机制、服务注册中心、服务治理组成。
---通信机制使用NIO的网络通信框架。
---服务注册中心使用zookeeper,实现服务发现、自动上下线等。
服务提供端:将服务提供者的信息注册到服务注册中心,信息一般包括服务主机地址、服务类信息、服务接口等。
服务消费端:读取服务注册中心的服务,缓存到本地,同时将消费者信息上报到服务注册中心。
序列化:
将对象的状态信息转化为可存储或可传输的形式的过程。两个指标:1.序列化后码流的大小。2.序列化本身的速度以及系统资源开销大小。
- JSON序列化
- Hessian序列化
- Protobuf序列化
- Thrift序列化
- Avro序列化
- Marshalling序列化
阻塞、非阻塞、同步、异步
- 阻塞:调用方发起调用请求,没有返回结果前,该线程被挂起,处于一直等待状态。
- 非阻塞:调用方发起请求后,当前线程不会等待挂起,而会立刻返回,后续通过轮询等手段获取调用结果。
- 同步:发出一个功能调用时,没有得到结果之前,该调用就不返回。
- 异步:当一个异步过程调用发出后,调用者不会立刻得到结果,通过回调等措施来处理这个调用。
同步异步更多的关注消息通信机制:就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回。但是一旦调用返回,就得到返回值了。而异步则直接返回,没没有返回结果
阻塞非阻塞描述程序在等待调用结果(消息,返回值)时的状态。调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回,而非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
粘包和拆包的问题
拆包:tcp协议中的每个包的头的长度都是固定的,总长度和数据包长度都不能超过限定的值,如果超过就会出现拆包现象。
粘包:发送数据时会先将数据包放入发送缓存,由于Nagle算法判断其发送的可用的数据过小,需要等待一段时间,如果期间又发送的数据,则会和已放入缓存的数据组合成一个数据包,形成粘包。
软负载原理
目的在于将请求按照某种策略分布到多台机器上,使得系统能够实现横向扩展,是应用可伸缩性的关键技术。消费端会先将服务注册中心的数据缓存到本地,在通过某种策略在缓存中选择本次调用的目标机器,再发起服务调用,从而完成负载均衡的功能。
常用算法:随机、加权随机、加权轮询、源地址hash等。