zoukankan      html  css  js  c++  java
  • RPC框架基本原理(一):服务注册

    什么是RPC框架

    RPC整个过程涉及四类对象:客户端、客户端代理、服务端和服务端代理。RPC要求客户端和服务端之间约定好调用接口和传输格式(如JSON,Xml等),客户端在调用该接口时,由客户端的代理对象负责对调用的参数(包括调用的函数名和参数等信息)进行格式转换,使之符合约定的传输格式,并通过网络传送至服务端。数据传输至服务端后,交由服务端代理对象进行格式解码,获取调用的接口和参数,最后调用服务端对象相应的方法获取结果并返回客户端。服务端的服务地址发布到ConfigServer,并推送给客户端,各种配置和规则信息通过Diamond发布订阅,服务的基本信息采集到Redis中。

    基本的调用关系图如下

    这张图是解释RPC注册中心经典的图,图中的ConfigServer可以看做是一个内存数据库,它主要有两个功能:

    1. 服务提供者的地址和服务信息
    2. 向服务订阅者推送所订阅的服务提供者的地址信息

    这里需要注意的是:真正发起远程调用是在消费者端和服务端生产者端和ConfigServer没有直接关系,实际的RPC是一个点对点的过程,通过TCP进行通信。

    架构图如下:

    服务注册的流程

    • 服务与spring容器绑定,监听容器的fresh,close等事件,进行服务的注册与关闭,
    • 第一个服务注册时,首先校验该服务是否已经注册,如果hsf依赖的netty服务未启动,启动netty服务,这里涉及nio的轮询线程池(hsfwork),以及后端具体hsf处理线程池(bizProcess),这些线程池是同步的,可以采用listenerFuture进行异步解构。
    • 启动好服务后,注册服务的基本信息到configserver中(注册流程分为注册前,注册,注册后)。

    关键的技术

    Netty服务

    常见I/O模型

    • 阻塞I/O(blocking I/O)
    • 非阻塞I/O (nonblocking I/O)
    • I/O复用(select,poll,epoll) (I/O multiplexing)
    • 信号驱动I/O (signal driven I/O (SIGIO))
    • 异步I/O (asynchronous I/O (the POSIX aio_functions))

    阻塞I/O(blocking I/O)

    非阻塞I/O (nonblocking I/O)


    用户进程其实是需要不断的主动询问kernel数据好了没有。因为需要不断地轮询,这消耗了大量的CPU的资源。

    I/O复用(select,poll,epoll)

    select:

    select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。这样所带来的缺点是:

    • 单个进程可监视的fd数量被限制,即能监听端口的大小有限。
    • 一般来说这个数目和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max察看。32位机默认是1024个。64位机默认是2048.

    对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低:
    当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll与kqueue做的。

    需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大

    poll:

    poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。

    它没有最大连接数的限制,原因是它是基于链表来存储的,但是同样有一个缺点:

    大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。 2. poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。

    epoll:

    epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就需态,并且只会通知一次。还有一个特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。

    Java从1.4开始提供了NIO工具包,支持用 I/O复用模型来进行网络编程。其模式图:

    信号驱动I/O (signal driven I/O (SIGIO))

    异步I/O (asynchronous I/O (the POSIX aio_functions))


    这种模型与信号驱动模型的主要区别是:信号驱动I/O由内核通知我们何时可以开始一个I/O操作,而异步I/O模型由内核通知我们I/O操作何时已经完成.

    JDK1.7 升级了NIO 类库,升级后的NIO类库被称为NIO2.0。java也正是提供了异步文件I/O操作,同时提供了与UNIX网络编程事件驱动I/O对应的AIO。

    Netty4的beta3加了AIO了,但是到beta9又被去了,作者的意思是测试下来AIO性能不如NIO,所以没必要用,在Linux上NIO的实现本身就是epoll,使用jdk的AIO没有意义,在windows上jdk的AIO实现是IOCP,这种情况下使用AIO是比poll的性能高的,但是netty的服务器一般是在linux上,所以抛弃windows没啥大不了,windows最多做个客户端,用nio也就够了。

  • 相关阅读:
    四级英语day9
    123
    像程序员一样思考
    Kali
    OS X
    Effective Java
    DHU ACM OJ
    Ambari
    Hadoop
    Hadoop2
  • 原文地址:https://www.cnblogs.com/zhulongchao/p/5597734.html
Copyright © 2011-2022 走看看