Pingap v0.2.0,基于 Pingora 的反向代理软件

来源: 投稿
作者: 粘土帽子
2024-04-21 14:54:00

Pingap是基于pingora开发的,基于 Apache-2.0 license协议开源,源代码可查阅https://github.com/vicanso/pingap。pingora提供了各类模块便于rust开发者使用,但并不方便非rust开发者使用,因此pingap提供了以toml的形式配置简单易用的反向代理,实现支持多location代理转发,通过插件的形式支持更多的需求场景。特性如下:

  • 支持多location配置,可通过请求的路径与域名筛选
  • 支持HTTP1与HTTP2两种协议
  • 无中断请求的配置更新,方便实时更新应用配置
  • 模板式的请求日志输出,可按模板指定各种输出
  • 提供Web界面式的配置,简化操作
  • 支持各种插件形式,根据需要灵活配置各种特性:如静态文件目录、服务性能指标、WEB后台配置应用等

Location的处理逻辑

该Server下的所有location在初始化时根据权重按高至低排序,接受到请求时按顺序一个个匹配到符合的location为止,若无符合的则返回出错。在选择对应的location之后,判断是否有配置重写pathh(若无则不需要),添加请求头(若无则不需要),成功响应时添加响应头(若无则不需要)。

let header = session.req_header_mut();
let path = header.uri.path();
let host = header.uri.host().unwrap_or_default();

let (location_index, lo) = self
    .locations
    .iter()
    .enumerate()
    .find(|(_, item)| item.matched(host, path))
    .ok_or_else(|| pingora::Error::new_str(LOCATION_NOT_FOUND))?;
if let Some(mut new_path) = lo.rewrite(path) {
    if let Some(query) = header.uri.query() {
        new_path = format!("{new_path}?{query}");
    }
    // TODO parse error
    let _ = new_path.parse::().map(|uri| header.set_uri(uri));
}

Location主要配置请求的匹配、请求头响应头的插入,以及各种插件的关联,是整个流程中的最重要组成部分。下面是相关参数的详细说明:

  • upstream: 配置该location对应的upstream,若该location所有的处理均由插件完成,则可不配置
  • host: 匹配的域名,如果是多个域名则使用,分隔
  • path: 匹配的路径,具体使用后续细说
  • proxy_headers: 转发至upstream时添加的请求头
  • headers: 响应至downstream时添加的响应头
  • rewrite: 请求路径的重写规则
  • proxy_plugins: 添加至该location的插件列表,按顺序执行

Location支持配置对应host(支持多个)与path规则,path支持以下的规则,权重由高至低:

  • 全等模式,配置以=开始,如=/api表示匹配path等于/api的请求
  • 正则模式,配置以~开始,如~^/(api|rest)表示匹配path以/api/rest开始请求
  • 前缀模式,如/api表示匹配path为/api开始的请求
  • 空模式,若未指定path则表示所有的path均匹配,一般建议配置一个/的前缀模式即可,无需使用空模式

插件体系

Pingap中通过Locaton添加各种插件支持更多的应用场景,如鉴权、流控等。现在插件支持在request_filterproxy_upstream_filter阶段执行,均为转发到上游节点前的处理。下面介绍一下proxy plunin的具体逻辑,trait如下:

#[async_trait]
pub trait ProxyPlugin: Sync + Send {
    fn category(&self) -> ProxyPluginCategory;
    fn step(&self) -> ProxyPluginStep;
    async fn handle(&self, _session: &mut Session, _ctx: &mut State) -> pingora::Result {
        Ok(false)
    }
}

主要分三个实现:

  • category: 插件类型,用于区分该插件是哪类形式的插件
  • step: 插件的执行阶段,现只支持在request_filterproxy_upstream_filter阶段执行
  • handle: 插件的执行逻辑,若返回的是Ok(true),则表示请求已处理完成,不再转发到上游节点

Upstream的处理逻辑

Upstream的逻辑比较简单,在匹配location后,根据该location配置的upstream节点列表,按算法选择可用节点,并将请求转发至该节点即可。虽然注意,插件也可配置在proxy_upstream_filter转发至upstream之前执行,可按需配置对应的插件。

Upstream配置为节点地址列表,配置为域名则会根据解析后的IP添加所有节点地址(之后并不会再次刷新域名解析),需要注意节点会使用默认的tcp health check的形式检测节点是否可用,建议配置为http health chech。下面针对相关参数详细说明:

  • addrs: 节点地址列表,地址为ip:port weight的形式,weight权重可不指定,默认为1
  • algo: 节点的选择算法,支持hashround_robin两种形式,如hash:ip表示按ip hash选择节点。默认为round_robin
  • sni: 若配置的是https,需要设置对应的SNI
  • verify_cert: 若配置的是http,是否需要校验证书有效性
  • health_check: 节点健康检测配置,支持http与tcp形式
  • ipv4_only: 若配置为域名时,是否仅添加解析的ipv4节点
  • alpn: 在tls握手时,alpn的配置,默认为H1
  • connection_timeout: tcp连接超时,默认为无
  • total_connection_timeout: 连接超时,对于https包括tls握手部分,默认为无
  • read_timeout: 读取超时,默认为无
  • write_timeout: 写超时,默认为无
  • idle_timeout: 空闲超时,指定连接空闲多久后会自动回收,如果设置为0,则连接不复用,需要注意有些网络设备对于无数据的tcp连接会过期自动关闭,因此可根据需要设置对应的值。默认为无

WEB管理后台

展开阅读全文
点击引领话题📣 发布并加入讨论🔥
0 评论
9 收藏
分享
返回顶部
顶部