java网关服务性能提升利器:CPU绑定对象池

SONA 是一个由比心语音技术团队开发,用于快速搭建语音房产品的全端解决方案,包含了房间管理、实时音视频、房间IM、长连接网关等能力,支撑了比心聊天室、直播、游戏房等业务。


前言

Sona 平台是一个搭建语音房产品的全端解决方案,包含了房间管理、实时音视频、房间IM、长连接网关等能力。其中最基础核心的就是长连接网关。

池化技术是把一些能够复用的东西放到池中,提前保存大量的资源,避免重复创建、销毁的开销,从而极大提高性能。在请求量比较大的时候能明显优化应用性能,降低系统频繁建连的资源开销。池化技术的应用非常广泛,我们工作中常见的比如数据库连接池、线程池、http连接池等。


一、对象池

还有一种可能在工作中不是经常使用的池化技术 - 对象池 ,它的核心思想就是空间换时间。

我们知道 Java 中频繁地创建和销毁对象的开销是很大的,通常情况下对象是分配在堆上的,因为堆是线程共享的,所以同一时间可能会有很多线程申请空间分配,在这种情况下要加锁处理,这样一来就会造成分配效率下降。虽然可以使用 TLAB 来分配(TLAB是每个线程独有的,它可以避免这种开销,直接分配内存),但还是存在着一些效率问题。

我们可以使用预先创建好的对象来减少频繁创建对象的性能开销,同时还可以对对象进行统一的管理,降低了对象的使用成本。这样不仅避免频繁地创建和销毁所带来的性能损耗,提高并发处理能力,而且能够降低 JVM GC 的压力。

像 Disruptor,它之所以高性能其实有一部分原因就是,RingBuffer 数组元素在初始化时一次性全部创建,提升缓存命中率,对象循环利用,避免频繁GC。

二、Netty Recycler

Recycler 是 Netty 提供的自定义实现的轻量级对象回收站,借助 Recycler 可以完成对象的获取和回收。

在 SONA网关中,每次业务请求最终都会被封装成 ChannelEventTask 丢到线程池里执行。为了尽可能地提升网关的性能,我就使用了 Recycler 来做池化。在压测过程中,内存占用以及CPU 消耗都有比较明显的改善。

使用方式其实非常简单,下面这个是 Netty 官方给出的样例:

通过 RECYCLER.get() 来获取对象,handle.recycle(this) 来回收对象 。

public class MyObject {

  private static final Recycler<MyObject> RECYCLER = new Recycler<MyObject>() {
    protected MyObject newObject(Recycler.Handle<MyObject> handle) {
      return new MyObject(handle);
    }
  }

  public static MyObject newInstance(int a, String b) {
    MyObject obj = RECYCLER.get();
    obj.myFieldA = a;
    obj.myFieldB = b;
    return obj;
  }
    
  private final Recycler.Handle<MyObject> handle;
  private int myFieldA;
  private String myFieldB;

  private MyObject(Handle<MyObject> handle) {
    this.handle = handle;
  }
  
  public boolean recycle() {
    myFieldA = 0;
    myFieldB = null;
    return handle.recycle(this);
  }
}

MyObject obj = MyObject.newInstance(42, "foo");
...
obj.recycle();

Recycler 原理

Recycler 里面一共包含四个核心组件:Stack、WeakOrderQueue、Link、DefaultHandle。

整个 Recycler 的内部结构中各个组件的关系,可以通过下面这幅图进行描述

Stack

private static final class Stack<T> {

    final Recycler<T> parent; // 所属的 Recycler

    final WeakReference<Thread> threadRef; // 所属线程的弱引用

    final AtomicInteger availableSharedCapacity; // 线程回收对象时,其他线程能保存的被回收对象的最大个数

    final int maxDelayedQueues; // WeakOrderQueue最大个数

    private final int maxCapacity; // 对象池的最大大小,默认最大为 4095

    private final int ratioMask; // 控制对象的回收比率,默认只回收 1/8 的对象

    private DefaultHandle<?>[] elements; // 存储缓存数据的数组

    private int size; // 缓存的 DefaultHandle 对象个数

    private int handleRecycleCount; 

    // WeakOrderQueue 链表的三个重要节点
    private WeakOrderQueue cursor, prev;

    private volatile WeakOrderQueue head;

    // 省略其他代码
}

Stack 对象是从 Recycle 内部的 FastThreadLocal 对象中获得,因此每个线程拥有属于自己的 Stack 对象,创造了无锁的环境,并通过 weakOrderQueue 与

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值