欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

RPC调用与GC垃圾回收

程序员文章站 2023-04-07 09:39:43
RPC调用 多个服务协同完成一次业务时,由于业务约束(如红包不符合使用条件、账户余额不足等)、系统故障(如网络或系统超时或中断、数据库约束不满足等),都可能造成服务处理过程在任何一步无法继续,使数据处于不一致的状态。传统的基于数据库本地事务的解决方案只能保障单个服务的一次处理具备原子性、隔离性、一致 ......

rpc调用

  • 多个服务协同完成一次业务时,由于业务约束(如红包不符合使用条件、账户余额不足等)、系统故障(如网络或系统超时或中断、数据库约束不满足等),都可能造成服务处理过程在任何一步无法继续,使数据处于不一致的状态。传统的基于数据库本地事务的解决方案只能保障单个服务的一次处理具备原子性、隔离性、一致性与持久性,但无法保障多个分布服务间处理的一致性

RPC调用与GC垃圾回收

  • 分析源代码,基本原理如下:
    • client 一个线程调用远程接口,生成一个唯一的 id (比如一段随机字符串,uuid 等) , dubbo 是使用 atomiclong 从 0 开始累计数字的
    • 将打包的方法调用信息(如调用的接口名称,方法名称,参数值列表等),和处理结果的回调对象 call back ,全都封装在一起,组成一个对象 0bject
    • 向专门存放调用信息的全局 concurrenthashmap 里面 put ( id , object )
    • 将 id 和打包的方法调用信息封装成一对象 connrequest ,使用 iosession.write ( connrequest )异步发送出去
    • 当前线程再使用call back 的get()方法试图获取远程返回的结果,在 get()内部,则使用 synchronized 获取回调对象 cailback 的锁,再先检测是否已经获取到结果,如果没有,然后调用 callback 的 wait()方法,释放 callback 上的锁,让当前线程处于等待状态
    • 服务端接收到请求并处理后,将结果(此结果中包含了前面的 id ,即回传)发送给客户端,客户端 socket连接上专门监听消息的线程收到消息,分析结果,取到 id ,再从前面的concurrenthashmap里面 get(id) ,从而找到 callback ,将方法调用结果设置到 callback 对象里
    • 监听线程接着使用 synchronized 获取回调对象 callback 的锁(因为前面调用过 wait ( ) ,那个线程已释放 callback 的锁了),再 notlfyall ( ) ,唤醒前面处于等待状态的线程继续执行( call back 的 get ( )方法继续执行就能拿到调用结果了),至此,整个过程结束

 

  • 当前线程怎么让它暂停,等结果回来后,再向后执行?
    • 先生成一个对象obj ,在一个全局 map 里 put ( 1d obj )存放起来,再用synchronized获取obj锁,再调用obj.wait()让当前线程处于等待状态,然后另一消息监听线程等到服务端结果来了后,再 map.get (id )找到 obj ,再用 synchronized获取obj 锁,再调用obj.notifyall唤配前面处于等待状态的线程
    • socket 通信是一个全双工的方式,如果有多个线程同时进行远程方法调用,这时建立在client server之间的socket连接上会有很多双方发送的消息有传递,前后顺序也可能是乱七八嘈的,server处理完结果后,将结果消息发送给 client, client收到很多消息,怎么知道消息结果是原先哪个线程调用的? 使用一个id ,让其唯一,然后传递给服务端,再服务端又回传回来,这样就知道结果是原先哪个线程的了

gc垃圾回收

大多数刚创建的对象会被分配在eden区,当eden区满的时候,执行minor gc,将消亡的对象清理掉,并将剩余的对象复制到一个存活区survivor0,当survivor0也满的时候,将其中仍然活着的对象直接复制到survivor1,以后eden区执行minor gc后,就将剩余的对象添加survivor1,当两个存活区切换了几次(hotspot虚拟机默认15次,用-xx:maxtenuringthreshold控制,大于该值进入老年代)之后,仍然存活的对象将被复制到老年代

年轻代收集器

  • serial收集器:“停止-复制”算法,单线程,进行垃圾收集时必须暂停其他线程的所有工作
  • parnew收集器:serial收集器的多线程版本,“停止-复制”算法,多线程
  • parallel scavenge收集器:”停止-复制“算法,并行的多线程收集器,可控制的吞吐量

老年代收集器

  • serial old:serial收集器的老年代版本,同样是一个单线程收集器,使用“标记-整理”算法
  • parallel old收集器:parallel scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
  • cms收集器:cms(conrrurent mark sweep)收集器是以获取最短回收停顿时间为目标的收集器,使用"标记-清除"算法

cms收集器

  • 初始标记:标记gcroots能直接关联到的对象,时间很短
  • 并发标记:进行gcroots tracing(可达性分析)过程,时间很长
  • 重新标记:修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,时间较长
  • 并发清除:清除未标记(无关联引用)的对象,伴随着用户线程的执行,清除后会产生浮动垃圾
  • 优缺点:对cpu资源非常敏感,可能会导致应用程序变慢,吞吐率下降,无法处理浮动垃圾,采用的“标记-清除”算法,会产生大量的内存碎片

垃圾回收算法实现

  • 停止-复制算法:将内存分为两块,当其中一块内存用完了,将还存活着的对象复制到另一块中,再将使用过的内存一次性清理掉
  • 标记-清除算法:首先标记出所有需要回收的对象,标记完成后统一回收所有被标记的对象
  • 标记-整理算法:让所有存活对象都向一端移动,然后直接清理掉边界以外的内存