Higress 基于自定义插件访问 Redis

news2024/11/24 1:02:59

作者:钰诚

简介

基于 wasm 机制,Higress 提供了优秀的可扩展性,用户可以基于 Go/C++/Rust 编写 wasm 插件,自定义请求处理逻辑,满足用户的个性化需求,目前插件已经支持 redis 调用,使得用户能够编写有状态的插件,进一步提高了 Higress 的扩展能力。

图片

文档在插件中调用 Redis [ 1] 中提供了完整的网关通过插件调用 Redis 的例子,包括阿里云 Redis 实例创建与配置、插件代码编写、插件上传与配置、测试样例等流程。接下来本文重点介绍几个基于 Redis 的插件。

多网关全局限流

网关已经提供了 sentinal 限流 [2 ] ,能够有效保护后端业务应用。通过 redis 插件限流,用户可以实现多网关的全局限额管理。

以下为插件代码示例,在请求头阶段检查当前时间内请求次数,如果超出配额,则直接返回 429 响应。

func onHttpRequestHeaders(ctx wrapper.HttpContext, config RedisCallConfig, log wrapper.Log) types.Action {
    now := time.Now()
    minuteAligned := now.Truncate(time.Minute)
    timeStamp := strconv.FormatInt(minuteAligned.Unix(), 10)
    // 如果 redis api 返回的 err != nil,一般是由于网关找不到 redis 后端服务,请检查是否误删除了 redis 后端服务
    err := config.client.Incr(timeStamp, func(response resp.Value) {
        if response.Error() != nil {
            log.Errorf("call redis error: %v", response.Error())
            proxywasm.ResumeHttpRequest()
        } else {
            ctx.SetContext("timeStamp", timeStamp)
            ctx.SetContext("callTimeLeft", strconv.Itoa(config.qpm-response.Integer()))
            if response.Integer() == 1 {
                err := config.client.Expire(timeStamp, 60, func(response resp.Value) {
                    if response.Error() != nil {
                        log.Errorf("call redis error: %v", response.Error())
                    }
                    proxywasm.ResumeHttpRequest()
                })
                if err != nil {
                    log.Errorf("Error occured while calling redis, it seems cannot find the redis cluster.")
                    proxywasm.ResumeHttpRequest()
                }
            } else {
                if response.Integer() > config.qpm {
                    proxywasm.SendHttpResponse(429, [][2]string{{"timeStamp", timeStamp}, {"callTimeLeft", "0"}}, []byte("Too many requests\n"), -1)
                } else {
                    proxywasm.ResumeHttpRequest()
                }
            }
        }
    })
    if err != nil {
        // 由于调用redis失败,放行请求,记录日志
        log.Errorf("Error occured while calling redis, it seems cannot find the redis cluster.")
        return types.ActionContinue
    } else {
        // 请求hold住,等待redis调用完成
        return types.ActionPause
    }
}

插件配置如下:

图片

测试结果如下:

图片

结合通义千问实现 token 限流

对于提供 AI 应用服务的开发者来说,用户的 token 配额管理是一个非常关键的功能,以下例子展示了如何通过网关插件实现对通义千问后端服务的 token 限流功能。

首先需要申请通义千问的 API 访问,可参考此链接 [3 ] 。之后在 MSE 网关配置相应服务以及路由,如下所示:

图片

图片

编写插件代码,插件中,在响应 body 阶段去写入该请求使用的 token 额度,在处理请求头阶段去读 redis 检查当前剩余 token 额度,如果已经没有 token 额度,则直接返回响应,中止请求。

func onHttpRequestBody(ctx wrapper.HttpContext, config TokenLimiterConfig, body []byte, log wrapper.Log) types.Action {
  now := time.Now()
  minuteAligned := now.Truncate(time.Minute)
  timeStamp := strconv.FormatInt(minuteAligned.Unix(), 10)
  config.client.Get(timeStamp, func(response resp.Value) {
    if response.Error() != nil {
      defer proxywasm.ResumeHttpRequest()
      log.Errorf("Error occured while calling redis")
    } else {
      tokenUsed := response.Integer()
      if config.tpm < tokenUsed {
        proxywasm.SendHttpResponse(429, [][2]string{{"timeStamp", timeStamp}, {"TokenLeft", fmt.Sprint(config.tpm - tokenUsed)}}, []byte("No token left\n"), -1)
      } else {
        proxywasm.ResumeHttpRequest()
      }
    }
  })

  return types.ActionPause
}

func onHttpResponseBody(ctx wrapper.HttpContext, config TokenLimiterConfig, body []byte, log wrapper.Log) types.Action {
  now := time.Now()
  minuteAligned := now.Truncate(time.Minute)
  timeStamp := strconv.FormatInt(minuteAligned.Unix(), 10)
  tokens := int(gjson.ParseBytes(body).Get("usage").Get("total_tokens").Int())
  config.client.IncrBy(timeStamp, tokens, func(response resp.Value) {
    if response.Error() != nil {
      defer proxywasm.ResumeHttpResponse()
      log.Errorf("Error occured while calling redis")
    } else {
      if response.Integer() == tokens {
        config.client.Expire(timeStamp, 60, func(response resp.Value) {
          defer proxywasm.ResumeHttpResponse()
          if response.Error() != nil {
            log.Errorf("Error occured while calling redis")
          }
        })
      }
    }
  })
  return types.ActionPause
}

测试结果如下:

图片

图片

基于 cookie 的缓存、容灾以及会话管理

除了以上两个限流的例子,基于 Redis 可以实现更多的插件对网关进行扩展。例如基于 cookie 来做缓存、容灾以及会话管理等功能。

  • 缓存&容灾:基于用户 cookie 信息缓存请求应答,一方面能够减轻后端服务压力,另一方面,当后端服务不可用时,能够实现容灾效果。
  • 会话管理:使用 Redis 存储用户的认证鉴权信息,当请求到来时,先访问 redis 查看当前用户是否被授权访问,如果未被授权再去访问认证鉴权服务,可以减轻认证鉴权服务的压力。
func onHttpRequestHeaders(ctx wrapper.HttpContext, config HelloWorldConfig, log wrapper.Log) types.Action {
  cookieHeader, err := proxywasm.GetHttpRequestHeader("cookie")
  if err != nil {
    proxywasm.LogErrorf("error getting cookie header: %v", err)
    // 实现自己的业务逻辑
  }
    // 根据自己需要对cookie进行处理
  cookie := CookieHandler(cookieHeader)
  config.client.Get(cookie, func(response resp.Value) {
    if response.Error() != nil {
      log.Errorf("Error occured while calling redis")
      proxywasm.ResumeHttpRequest()
    } else {
      // 实现自己的业务逻辑
      proxywasm.ResumeHttpRequest()
    }
  })
  return types.ActionPause
}

总结

Higress 通过支持 redis 调用,大大增强了插件的能力,使插件功能具有更广阔的想象空间,更加能够适应开发者多样的个性化需求,如果大家有更多关于 Higress 的想法与建议,欢迎与我们联系!

相关链接:

[1] 在插件中调用 Redis

https://help.aliyun.com/zh/mse/user-guide/develop-gateway-plug-ins-by-using-the-go-language?spm=a2c4g.11186623.0.0.45a53597EVVAC0#5e5a601af18al

[2] sentinal 限流

https://help.aliyun.com/zh/mse/user-guide/configure-a-throttling-policy?spm=a2c4g.11186623.0.i4

[3] 链接

https://help.aliyun.com/zh/dashscope/developer-reference/api-details?spm=a2c4g.11186623.0.i4#602895ef3dtl1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1562100.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ 注册Nacos

下载源码&#xff1a; git clone GitHub - nacos-group/nacos-sdk-cpp: C client for Nacos 编译源码 cd nacos-sdk-cpp cmake . make 生成库文件 在nacos-sdk-cpp 下 注册nacos 将include 和libnacos-cli.so libnacos-cli-static.a 放入你的工程 如果Nacos服务地址:…

3.26号arm

1. SPI相关理论 1.1 概述 spi是一种同步全双工串行总线&#xff0c;全称串行外围设备接口 通常SPI通过4个引脚与外部器件相连&#xff1a; MISO&#xff1a;主设备输入/从设备输出引脚。该引脚在从模式下发送数据&#xff0c;在主模式下接收数据。 MOSI&#xff1a;主设备输…

LangChain入门:9.使用FewShotPromptTemplate实现智能提示工程

在构建智能提示工程时&#xff0c;LangChain 提供了强大的 FewShotPromptTemplate 模型&#xff0c;它可以帮助我们更好地利用示例来指导大模型生成更加优质的提示。 在这篇博文中&#xff0c;我们将使用 LangChain 的 FewShotPromptTemplate 模型来设计一个智能提示工程&#…

StarRocks使用Minio备份和还原

1.安装minio minio api端口&#xff1a;9090 下文用到这个端口 必须提前创建好桶: packfdv5 名称自定义和后面对上就可以 2.创建备份仓库 格式&#xff1a; CREATE REPOSITORY <repository_name> WITH BROKER ON LOCATION "s3a://<bucket_name>/backup…

47.goto语句

目录 一.goto语句 二.语法格式 三.举例 四.视频教程 一.goto语句 goto语句可以使程序在没有任何条件的情况下跳转到指定位置&#xff0c;所以goto语句也就跳转语句。 二.语法格式 格式1&#xff1a;goto label&#xff1a;//其他代码 lable&#xff1a;//其他代码格式2&a…

【Node.js从基础到高级运用】二十、Node.js 强大的REPL

引言 Node.js REPL&#xff08;Read-Eval-Print Loop&#xff09;是一种交互式的命令行工具&#xff0c;它允许开发者快速地执行JavaScript代码&#xff0c;并查看结果。这个功能在进行快速原型设计、调试、学习JavaScript或Node.js时非常有用。 启动REPL 首先&#xff0c;确保…

【总结】在嵌入式设备上可以离线运行的LLM--Llama

文章目录 Llama 简介运用另一种&#xff1a;MLC-LLM 一个令人沮丧的结论在资源受限的嵌入式设备上无法运行LLM&#xff08;大语言模型&#xff09;。 一丝曙光&#xff1a;tinyLlama-1.1b&#xff08;10亿参数&#xff0c;需要至少2.98GB的RAM&#xff09; Llama 简介 LLaMA…

智慧安防监控EasyCVR视频调阅和设备录像回看无法自动播放的原因排查与解决

智慧安防监控EasyCVR视频管理平台能在复杂的网络环境中&#xff0c;将前端设备统一集中接入与汇聚管理。国标GB28181协议视频监控/视频汇聚EasyCVR平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、…

Spring Boot项目启动速度优化

1、配置自动配置排除列表&#xff0c;减少启动自动配置扫描&#xff0c;配置项spring.autoconfigure.exclude 2、启动类添加索引注解Indexed&#xff0c;去除启动过程中 Components 的扫描步骤&#xff0c;直接从索引文件读取。 import org.springframework.stereotype.lndexe…

ansible-tower安装

特别注意&#xff1a;不需要提前安装ansible&#xff0c;因为ansible tower中的setup.sh脚本会下载对应的ansible版本 ansible tower不支持Ubuntu系统,对cenos系统版本也有一定的限制&#xff0c;建议使用centos7.9。 准备一台全新的机器安装&#xff0c;因为ansible tower需要…

第21章-直连路由和静态路由

1. 直连路由 1&#xff09;定义&#xff1a;指路由器接口直接相连的网段的路由&#xff1b; 2&#xff09;特点&#xff1a; ① 不需要特别的配置&#xff0c;双UP(物理层数据链路层)&#xff1b; ② 在路由器的接口上配置IP地址即可&#xff1b; ③ 开机自动产生&#xff1b; …

Docker容器赋能TitanIDE:引领编程新纪元的集成开发环境

Docker是一种容器化技术&#xff0c;它可以将应用程序和其所有的依赖项打包到一个轻量级、可移植的容器中。以下是Docker的基本概念和优势&#xff1a; 基本概念&#xff1a; 镜像&#xff08;Image&#xff09;&#xff1a;一个镜像是一个只读的模板&#xff0c;可以用于创建…

docker + miniconda + python 环境安装与迁移

本文主要列出从安装到安装python环境到迁移环境的整体步骤。 windows与linux之间进行测试。 一、docker 安装和测试 【linux端】 可以参考其他教程&#xff0c;不在此赘述&#xff0c;以windows端举例。 【windows端】 我的是windows10 家庭中文版&#xff0c;docker 安装和…

如何查询网站是否被搜索引擎收录

怎么看网站有没有被百度收录 对于网站所有者来说&#xff0c;了解自己的网站是否被百度搜索引擎收录是非常重要的。只有被收录&#xff0c;网站才能在百度搜索结果中展现&#xff0c;从而获取流量和曝光。下面介绍几种方法&#xff0c;让您快速了解自己的网站是否被百度收录。…

MySQL之存储引擎,详细总结

在介绍存储引擎之前我们先了解了解MySQL的体系结构&#xff1a; 连接层 最上层是一些客户端和链接服务&#xff0c;主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限 服务层 第二层架构主要完成大多数的核心…

海康Ehome2.0与5.0设备接入EasyCVR视频汇聚平台时的配置区别

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

Vue项目之子组件

子组件 项HelloWorld这样的组件&#xff0c;在其他组件中展示的组件&#xff0c;被称为子组件&#xff0c;展示子组件的组件被称为父组件。 例&#xff1a;Home组件是HelloWorld组件的父组件&#xff0c;App组件爱你是router-link/router-views组件的父组件。 子组件的使用方式…

重构智能防丢产品,苹果Find My技术引领市场发展

目前市场上最主要的防丢技术是蓝牙防丢和GPS防丢&#xff0c;蓝牙防丢是通过感应防丢器与绑定手机的距离来实现防丢的。一般防丢会默认设置一个最远安全距离&#xff0c;超过这个安全距离后&#xff0c;与手机蓝牙信号断开&#xff0c;触发防丢报警&#xff0c;用户根据防丢报警…

vscode通过ssh连接服务器(吐血总结)

一、通过ssh连接服务器 1、打开vscode&#xff0c;进入拓展&#xff08;CtrlShiftX&#xff09;&#xff0c;下载拓展Remote - SSH。 2、点击远程资源管理器选项卡&#xff0c;选择远程&#xff08;隧道/SSH&#xff09;类别。 3、点击SSH配置。 4、在中间上部分弹出的配置文件…

物联网实战--入门篇之(七)嵌入式-MQTT

目录 一、MQTT简介 二、MQTT使用方法 三、MQTT驱动设计 四、代码解析 五、使用过程 六、总结 一、MQTT简介 MQTT因为其轻量、高效和稳定的特点&#xff0c;特别适合作为物联网系统的数据传输协议&#xff0c;已经成为物联网事实上的通信标准了。关于协议的具体内容看看这…