之所以写出来,一方面是整理思路,另一个方面也给自己立个任务,防止自己后面不将这些想法实现。

0 背景

开放平台的网关处于ISV(外部第三方服务商)和内部业务之间,在网关层面会调用不同的内部业务方,而内部业务方由不同的业务技术团队提供,不同的业务接口性能有不同,稳定性也不同。因此要屏蔽掉不同业务接口相互影响,以及对开放平台网关的影响。

为了提升网关的稳定性需要从以下两点着手:

  • http请求异步化。这种方式可以将容器的accept线程池与业务处理线程池隔离,避免业务处理时间过长导致拒绝网络请求。主流的实现主要有:
    • servlet 3 中的异步servlet,和jetty中 Continuation
    • NIO,最新的zuul 2 是这种方式。
    • 在这里不多做讨论,后面会有新的文章专门讨论这一点。
  • 线程池隔离。网关在调用业务服务时采用线程池隔离,能够避免不同业务之间的相互影响。

1 线程池隔离思路

网关的业务处理能力基本固定,因此总体的线程数量较为稳定,而不同的业务可以根据其权重分配到不同的线程数。业务线程分配模式可以支持一下策略:

  • 预留线程数(retain)
    • 比如一个业务的预留线程数是100,也就是说在调用业务时,至少线程数<100,保证能够申请到新的线程;当线程数>100时,就需要根据实际线程数据。
  • 最大线程数(max)
    • 最大线程数是对业务线程的一种限制,比如其最大线程数是100,在业务调用中,如果线程数>100后,这个业务申请新线程会失败。
  • 预留+最大线程数限制(mix)

综合上面两种方式。

  • 普通模式(regular),即没有特别说明,在申请线程时,根据线程池中剩余线程池数量定。

1.1 实现实例

假设线程池共有200个线程。A任务为预留模式,预留线程数为100,B任务为max模式,最大50个线程,C为mix模式,预留20个线程,最大50个线程,D任务为普通模式。

在线程池逻辑上就会这样划分:

----------|--|--------|
A保留线程数 C保留 剩余80个,用于A、B、C、D按照优先级获取

但当B获取到50个之后,将不能继续获取,指导其释放之前的线程,C获取到50个线程之后将于B相同处理。而D则可能一直获取不到,或者按照优先级获取了剩余的80个线程。

2 实现方式

2.1 概念抽象

首先抽象几个概念:

  • 资源池(Resource Pool)

本质和线程池意义一样,在这里之所以不叫线程池,是为了与线程池本身概念做区分。

  • 调度策略(Policy)

上文中说提到的四种方式。

  • 调度器(Scheduler)

任务向调度器申请线程资源,调度器根据其所属策略不同计算后调度,如果可以获取线程,则直接提交到资源池执行,如果无法获取,则放到等待队列中执行。

  • 等待队列(Queue)

每个任务最开始放置到队列,由调度器从队列中获取。

整体实现思路如图所示:

2.2 资源池实现方式

资源池是一个逻辑概念,本质上和线程池是一样的,但可以有多线程池和单线程池实现方式。

2.2.1 多线程池实现

多线程池就是使用多个线程池组合成一个资源池,这种方式可以对retain类型任务使用独立的线程池,其他类型的任务可以独立线程池,也可以共享一个线程池。

  • 优点
    • 任务之间可以线程池级别隔离,避免相互影响
  • 缺点
    • 资源消耗较大,任务增减时,多线程的变化不够灵活
  • 已有实现
2.2.2 单线程池实现

单线程池实现时,一个线程池就是资源池,在线程池内部划分出了逻辑结构。

3 结语

分析了很多,我自己还没开始实现,所以还没办法给出验证。正如一开始所说,这是给自己立个flag,紧接着会在项目中实现并线上使用。

我在开放平台的建设过程中,大量学习了淘宝开放平台 的技术思路,特别是放翁博客。之后还会有开放平台建设中的技术沉淀和思考,在之后的技术文章中会有更多介绍,里面也借鉴了许多淘宝开放平台的内容。