高可用性高性能 Web 缓存

来自 Alpine Linux

简介

本文档解释了如何使用 HAProxyucarp 来提供高性能和高可用性服务。本文档已使用 Alpine Linux 2.2.3 进行测试。

在本文档中,我们将使用 Squid web 缓存 作为示例服务。Squid 通常只使用单个处理器,即使在多处理器机器上也是如此。为了获得更高的 web 缓存性能,最好将 web 缓存扩展到多个(廉价)物理机上。虽然 web 缓存被用作示例服务,但本文档适用于其他服务,例如邮件、web 加速等。

网络拓扑图

最后,我们将拥有一个如下所示的架构

工作站都连接到 192.168.1.10 上的 HAProxy 实例。192.168.1.10 是一个由 ucarp 控制的虚拟 IP;也就是说,HAProxy 在任何给定时间都在一个 web 缓存服务器上运行,但任何 web 缓存都可以是 HAProxy 实例。

HAProxy 将 web 流量分配到所有活动的 web 缓存服务器,这些服务器缓存来自 Internet 的资源。

优势

  • 图表中的 HAProxy 服务器是“虚拟的” - 它代表在任何 web 缓存服务器上运行的服务
  • 每个 web 缓存服务器都配置为其他服务器的镜像 - 这简化了添加额外容量。
  • HAProxy 将忽略已失败或已离线的服务器,并在它们返回服务时发出通知
  • 此配置允许在“滚动停机”中升级或修改单个服务器,而不会给用户带来停机时间。
  • 如果运行 HAProxy 的服务器崩溃,Ucarp 会自动在另一个缓存上重启 HAProxy 服务。这是自动恢复,从客户端的角度来看,通常停机时间少于 3 秒。

初始服务

获得高可用性的第一步是拥有多个服务器;在每个 cache1-4 上执行以下操作

  • 安装 squid
apk add squid
  • 创建一个最小的 /etc/squid/squid.conf
acl all src all
acl localhost src 127.0.0.1/32
acl localnet src 10.0.0.0/8     # RFC1918 possible internal network
acl localnet src 172.16.0.0/12  # RFC1918 possible internal network
acl localnet src 192.168.0.0/16 # RFC1918 possible internal network 

icp_port 3130
icp_access allow all

cache_peer 192.168.1.11 sibling 3128 3130
cache_peer 192.168.1.12 sibling 3128 3130
cache_peer 192.168.1.13 sibling 3128 3130
cache_peer 192.168.1.14 sibling 3128 3130

http_access allow localnet
http_access allow localhost
http_access deny all

http_port 3128

forwarded_for off
警告: 这只是用于演示目的的最小配置。您可能需要配置更严格的 ACL


icpcache_peer 条目允许所有四个 squid 服务器共享缓存信息。一旦一个服务器检索到一个项目,其他服务器就可以从本地服务器获取信息,而无需重新检索。

  • 确保 squid 在启动时启动
rc_update add squid
rc-service squid start


此时,您应该能够将浏览器设置为使用任何 192.168.1.1[1-4]:3129 作为代理地址,并连接到 Internet。由于此配置文件未使用任何优化,因此浏览速度将比正常。这是可以预期的。您对一个服务器的 squid 配置所做的任何优化都可以应用于数组中的所有服务器。此示例的目的是表明服务在整个数组中是一致的。

Ucarp 虚拟 IP 管理器

Ucarp 在所有服务器上运行,并确保虚拟 IP 地址可用。在示例图中,我们使用虚拟 IP 192.168.1.10。

  • AlpineLinux ucarp init 脚本期望它在多宿主机上运行;能够在每个接口上运行 ucarp 进程。复制接口的脚本
apk add ucarp
ln -s ucarp /etc/init.d/ucarp.eth0
cp /etc/conf.d/ucarp /etc/conf.d/ucarp.eth0
  • 编辑 /etc/conf/ucarp.eth0 文件
REALIP=
VHID=1
VIP=192.168.1.10
PASSWORD=SecretPassword
  • 创建 etc/ucarp/vip-up-eth0.sh
#!/bin/sh
 
 # Add the VIP address
 ip addr add $2/24 dev $1
 
 for a in 330 440 550; do beep -f $a -l 100; done
  • 创建 /etc/ucarp/vip-down-eth0.sh
#!/bin/sh

 # Remove the VIP address
 ip addr del $2/24 dev $1

 for a in 550 440 330; do beep -f $a -l 100; done
  • 使脚本可执行
chmod +x /etc/ucarp/*.sh
  • 启动 ucarp 并保存更改
 rc-update add ucarp.eth0
 rc-service ucarp.eth0 start
 lbu commit
  • 对每个缓存服务器执行上述步骤。

一旦它在每个服务器上运行,依次拔下每个服务器上的网线。几秒钟后,其他服务器应该会发出提示音,因为它们举行选举以选择新的主服务器。(注意,所有服务器都会短暂地成为主服务器,然后其他服务器会迅速降级自身。)无论哪个服务器被选为主服务器,您都应该能够 ping 通 192.168.1.10。

HA Proxy 负载均衡器

HA 负载均衡器

  • 自动跨 web 缓存分配请求
  • 自动检测缓存何时更改状态,并禁用或重新启用向其发送请求。


  • 在每个 web 缓存上安装 haproxy。
apk add haproxy
  • 我们将 haproxy 用作简单的 tcp 负载均衡器,因此我们不需要高级 http 选项。以下是一个简单的 `/etc/haproxy.cfg` 文件
global
  uid haproxy
  gid haproxy
  chroot /var/empty

defaults
  # 30 minutes of waiting for a web request is crazy, 
  # but some users do it, and then complain the proxy
  # broke the interwebs.
  timeout client 30m
  timeout server 30m 
  # If the server doesnt respond in 4 seconds its dead
  timeout connect 4s

listen http_proxy 192.168.1.10:8080
  mode tcp
  balance roundrobin
  server cache1 192.168.1.11:3128 check
  server cache2 192.168.1.12:3128 check
  server cache3 192.168.1.13:3128 check
  server cache4 192.168.1.14:3128 check
  

如果您的 squid 缓存具有公共、可路由的 IP 地址,您可能希望将平衡算法更改为 source。当客户端的 IP 地址在请求之间发生变化时,某些 web 应用程序会感到困惑。使用 balance source 将客户端负载均衡到所有 web 代理,但一旦客户端被分配给特定的代理,它将继续使用该代理。

  • 确保您拥有 haproxy 用户和组
adduser -s /bin/false -D -h /dev/null -H haproxy
  • 不要启动 haproxy 或将其添加到 rc 脚本;我们稍后会这样做。
  • 对 cache2-4 执行上述步骤;请注意,所有实例的 `/etc/haproxy.cfg` 完全相同。
  • 在当前拥有 192.168.1.10 ucarp 地址的缓存上
rc-service haproxy start
  • 将您的浏览器更改为使用 192.168.1.10:8080 作为代理地址。
    • 您应该能够浏览 Internet
    • 您的浏览应该分布在所有 4 个 squid 服务器上

启用 HA 服务

按照上述说明操作后,您应该具备以下条件

  • Squid 正在每个 web 缓存上运行
    • 您可以通过 ip 地址连接到每个 web 缓存并浏览互联网
  • ucarp 正在所有实例上运行
    • 您可以 ping 通 192.168.1.10
    • 如果您拔下连接到提供 192.168.1.10 的盒子的以太网电缆,另一个盒子会取代它
  • haproxy 已在每个缓存服务器上配置,但未运行


  • 更新每个服务器上的 `etc/ucarp/vip-up-eth0.sh` 以包含启动 haproxy 的语句
#!/bin/sh
 
 # Add the VIP address
 ip addr add $2/24 dev $1

 rc-service haproxy start
 
 for a in 330 440 550; do beep -f $a -l 100; done
  • 更新每个服务器上的 `etc/ucarp/vip-down-eth0.sh` 以包含停止 haproxy 的语句
#!/bin/sh

 rc-service haproxy stop

 # Remove the VIP address
 ip addr del $2/24 dev $1

 for a in 550 440 330; do beep -f $a -l 100; done
  • 保存更改
 lbu commit


维护

haproxy 进程在所有可用的 web 代理之间负载均衡请求。如果代理崩溃,haproxy 会自动将其从池中删除,并将传入的请求重定向到其余可用的代理。一旦代理恢复服务,haproxy 会自动注意到并再次开始向其发送请求。


ucarp 进程确保“haproxy”始终在虚拟 ip (192.168.1.10) 上运行。即使运行 haproxy 的机器崩溃,客户端也不需要重新配置。另一个盒子接管虚拟地址,一切“正常工作”


要从服务中删除代理,只需将其关闭即可。更优雅的方法是更新 haproxy.conf 并告诉 haproxy 使用新配置。例如,要从池中删除 192.168.1.11

  • 登录到 192.168.1.10
  • 编辑 /etc/haproxy.conf 并注释掉 192.168.1.11 行
# server cache1 192.168.1.11:3128 check # 192.168
  • 请求 haproxy 的软重启
 /usr/bin/haproxy -D -p /var/run/haproxy.pid -f /etc/haproxy.cfg -sf \
  $( cat /var/run/haproxy.pid )

这会导致现有的 haproxy 完成连接,但不接受新的连接。最终,旧的 haproxy 进程将死亡,只留下新的进程。由于 web 请求可能需要很长时间,因此旧的 haproxy 实例可能会持续数分钟。在关闭 web 代理服务器之前,请确保旧进程已终止。


同样,要将 web 缓存添加到 farm 中,请使用上述命令让 haproxy 开始使用新的配置文件。

“-sf”标志允许对 web 缓存进行滚动维护,而对客户端没有可观察到的影响。