在搭载NGINX的Elastic Beanstalk环境中,动态将EC2实例私有IP添加至Django的CACHE LOCATION配置是否合理?
先直接给你两个核心问题的答案,再解决你遇到的缓存set后get返回None的异常:
核心问题1:是否需要添加所有EC2私有IP到CACHES的LOCATION?
必须添加所有当前EB环境的EC2实例私有IP,不能只写127.0.0.1:11211。
原因很简单:你的NGINX配置只是把请求反向代理到本地的Django服务(proxy_pass http://127.0.0.1:8000),这意味着每个EC2实例上都独立运行着Django进程和Memcached进程。如果只配置127.0.0.1,每个实例的缓存完全独立——当负载均衡把请求打到实例A时,你set的缓存只存在于A的Memcached里;后续请求打到实例B时,自然get不到这个值。
只有把所有实例的私有IP都加入LOCATION,Django的Memcached后端才能利用Memcached的分布式特性,把所有实例的Memcached组成一个统一的缓存池,不管请求落到哪个实例,都能访问到共享的缓存数据。
核心问题2:NGINX是否会集中管理缓存?
不会。你的NGINX在这里只是扮演反向代理的角色,负责把外部请求转发到本地的Django服务,它完全不参与缓存的管理逻辑。缓存的读写、分布式调度都是由Django的Memcached客户端(你用的PyMemcacheCache)和各个实例上的Memcached进程共同完成的。
解决你遇到的缓存set后get返回None的异常
你已经正确获取了实例IP并配置到CACHES里,但缓存无法正常读写,大概率是以下几个原因之一,按顺序排查:
1. 安全组限制了Memcached的跨实例访问
每个EC2实例的安全组需要允许同一EB环境内其他实例的私有IP段访问11211端口。默认情况下,Memcached监听11211端口,但如果安全组只允许127.0.0.1/32访问,其他实例根本连不上这个端口,自然无法写入或读取缓存。
排查方法:在某台实例上执行telnet 另一实例的私有IP 11211,如果连接失败,立刻去调整安全组规则,添加一条入站规则:允许来自当前EB环境实例所在私有子网IP段的流量访问11211端口。
2. Memcached绑定了本地回环地址
检查Memcached的配置文件(通常路径是/etc/memcached.conf),看-l参数的值:
- 如果是
-l 127.0.0.1,Memcached只会监听本地回环接口,其他实例无法连接; - 必须改成
-l 0.0.0.0或者实例的私有IP,这样才能接受来自其他实例的连接。
修改后重启Memcached服务:sudo systemctl restart memcached
3. Boto3代码获取了无关的EC2实例
你的当前代码是获取所有EC2实例,但可能包含了其他环境的实例、已停止的实例,这些无效IP会导致Django客户端尝试连接不可用的Memcached节点,进而影响缓存读写。
优化你的代码,通过EB环境的标签过滤出当前环境的运行中实例:
class MemcachedLocations(object): MEMCACHED_PORT = "11211" # 从EB环境变量获取当前环境名称和AWS区域(EB会自动注入这些变量) EB_ENV_NAME = os.environ.get('EB_ENVIRONMENT') REGION = os.environ.get('AWS_REGION', 'us-west-2') @cached_property def get(self): # EB会自动为实例赋予IAM角色,无需硬编码AK/SK,直接用默认凭证即可 client = boto3.client('ec2', region_name=self.REGION) response = client.describe_instances( Filters=[ { 'Name': 'tag:elasticbeanstalk:environment-name', 'Values': [self.EB_ENV_NAME] }, { 'Name': 'instance-state-name', 'Values': ['running'] } ] ) private_ips_list = [] for reservation in response['Reservations']: for instance in reservation['Instances']: private_ip = instance['PrivateIpAddress'] private_ips_list.append(f"{private_ip}:{self.MEMCACHED_PORT}") return private_ips_list
注意:EB环境会自动为实例分配IAM角色,只要给角色添加ec2:DescribeInstances权限,就不需要硬编码AK/SK,更安全也更易维护。
4. 检查PyMemcache依赖和配置
确保你已经安装了pymemcache包(Django的PyMemcacheCache后端依赖它),可以在EB的requirements.txt里加入pymemcache>=4.0.0。另外,你可以尝试给CACHES添加一些调试参数,快速定位连接问题:
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache', 'LOCATION': MemcachedLocations().get, 'OPTIONS': { 'connect_timeout': 1, 'timeout': 1, 'use_pooling': True, } } }
超时参数能帮你快速发现连接问题,如果有连接超时的错误,就能定位到网络或Memcached配置的问题。
内容的提问来源于stack exchange,提问作者Jarad

