Docker Swarm下Memcached水平扩展:PHP服务自动适配方案咨询
我之前在基于Swarm部署PHP应用时也遇到过完全一样的问题——要让应用自动利用扩容后的缓存节点,核心就是利用Docker Swarm内置的服务发现能力,再配合PHP端的动态服务器列表管理。下面是几个可行的方案,按推荐优先级排序:
方案1:利用Swarm DNS动态解析所有Memcached实例
Docker Swarm的overlay网络自带DNS服务发现,当你扩容Memcached服务时,服务名(比如memcached)会自动解析为所有运行中实例的IP地址。PHP只需要定期解析这个服务名,就能拿到最新的服务器列表。
具体实现步骤:
确保服务在同一个Overlay网络:在
docker-compose.yml中定义共享的overlay网络,让PHP和Memcached服务都加入这个网络:version: '3.8' services: php-app: image: your-custom-php-image deploy: replicas: 3 networks: - app-overlay memcached: image: memcached:alpine deploy: replicas: 1 # 后续通过`docker service scale memcached=5`扩容 networks: - app-overlay networks: app-overlay: driver: overlayPHP端动态获取并更新服务器列表:不要硬编码单个Memcached地址,而是通过DNS解析服务名拿到所有实例IP,再将它们添加到Memcached客户端。为了应对扩容/缩容的变化,建议定期刷新这个列表:
function getMemcachedClient(): Memcached { $memcached = new Memcached(); // 清空旧的服务器列表 $memcached->resetServerList(); // 解析Swarm服务名,获取所有实例IP // 方法1:用gethostbynamel $servers = gethostbynamel('memcached'); // 方法2:如果gethostbynamel被禁用,用dns_get_record // $records = dns_get_record('memcached', DNS_A); // $servers = array_column($records, 'ip'); // 将所有IP添加到客户端 foreach ($servers as $server) { $memcached->addServer($server, 11211); } return $memcached; } // 使用示例 $client = getMemcachedClient(); $client->set('user_123', ['name' => 'John'], 3600);你可以根据业务场景调整刷新频率:比如每次请求初始化客户端(适合低流量场景),或者用定时任务每N分钟刷新一次全局的服务器列表(适合高流量场景)。
方案2:借助客户端库的服务发现能力
如果你的PHP应用使用了第三方Memcached客户端(比如一些封装完善的社区库),部分库已经内置了基于DNS的服务发现逻辑,会自动定期刷新服务器列表。你只需要配置服务名作为地址,不用手动处理解析逻辑。
方案3:用Swarm VIP做负载均衡(简化版)
如果不想修改PHP代码,可以利用Swarm的VIP(虚拟IP)特性:Memcached服务的VIP会自动在所有实例间做负载均衡。此时PHP只需要连接memcached:11211这个固定地址,Swarm会自动把请求转发到不同的实例。
不过这个方案的缺点是:PHP客户端无法直接利用Memcached的分布式缓存特性(比如按key哈希分配到不同节点),所有请求都通过VIP转发,性能略逊于直接连接多个实例。
内容的提问来源于stack exchange,提问作者ajnozari

