Azure函数连接Redis所在Azure VM时出现间歇性超时问题
我需要让Azure Function App连接部署有Redis的Azure VM,以下是简化后的代码:
main.py
import logging import azure.functions as func from . import redis_db def main(req: func.HttpRequest) -> func.HttpResponse: # 加载密钥等操作在此处 # 准备数据库连接 redis_instance = redis_db.Db() # 其他检查(客户端认证等) # 使用redis_instance执行操作 found = redis_instance.check_exists(mykey)
redis_db.py
import logging import redis import os # 注:原代码未导入os,此处补充 from . import constants class Db: rd = None def __init__(self): global rd if rd is None: self.connect() else: logging.info("[RD] Reusing connection...") self.rd = rd def connect(self): hostname = os.environ.get("REDIS_HOST") port = os.environ.get("REDIS_PORT") password = os.environ.get("REDIS_ACCESS_KEY") logging.info("[Redis] Connecting...") self.rd = redis.Redis( host=hostname, port=port, password=password, socket_connect_timeout=constants.timeout_seconds, socket_timeout=constants.timeout_seconds, ) rd = self.rd return self.rd def check_exists(self, key): logging.info(f"[Redis] Checking if code exists for {key} ({type(key)})") try: result = self.rd.get(name=key) logging.info(f"[Redis] Check result: {result}") except Exception as e: logging.exception(f"[Redis] Exception: {type(e)} {e}") return result # 其他Redis方法
环境与异常现象
- 本地运行正常:开启办公室VPN后,Redis VM已将本地IP加入白名单,无连接问题。
- 部署到Azure Premium App Service Plan后,函数已加入VNet,与Redis VM同属一个VNet;应用设置中的
REDIS_HOST、REDIS_PORT、REDIS_ACCESS_KEY均为Key Vault引用,状态显示正常(绿色对勾)。 - 核心问题:触发函数时90%概率抛出
redis.exceptions.TimeoutException,仅偶尔能正常返回200状态;添加重试逻辑、清空全局连接变量、调整超时时间(5秒→30秒)均无法解决。 - 辅助验证:通过门户Web SSH登录函数应用,无ping/telnet命令无法直接检测网络;在
__init__末尾添加self.rd.ping()并捕获异常,确认存在连接超时问题。
VNet网络安全组(NSG)配置异常:
虽然函数与VM同属一个VNet,但NSG规则可能存在间歇性限流或拦截:比如函数子网的出站规则未完全放开Redis端口(默认6379),或Redis VM的入站规则未覆盖函数实例的动态IP段(Premium计划函数实例IP会随缩放变化);部分规则优先级设置错误,导致流量偶尔被拦截。全局连接复用的风险:
当前代码用全局变量rd复用Redis连接,但Azure Function是无状态服务,实例会被Azure动态回收、缩放,全局连接可能在实例回收后变成无效连接;多实例共享全局连接也可能引发冲突,导致连接超时。另外需检查Redis服务器的最大连接数是否被打满,导致新连接无法建立。Azure网络路由问题:
VNet内的用户定义路由(UDR)配置错误,导致部分流量无法正确路由到Redis VM;或是Azure网络基础设施临时波动,引发数据包丢失,进而触发超时。Redis客户端配置缺失:
当前客户端未配置连接池,也未启用retry_on_timeout参数(默认不重试超时请求);同时未设置health_check_interval,无法自动检测无效连接并重建,导致复用的旧连接触发超时。Key Vault引用加载延迟:
虽然应用设置显示正常,但函数启动时可能存在Key Vault密钥加载延迟,导致首次连接时使用空值或旧配置,引发超时;后续请求加载完成后偶尔能正常连接。
内容的提问来源于stack exchange,提问作者Cezille07

