# 7.3-Splash负载均衡配置

用 Splash 做页面抓取时，如果爬取的量非常大，任务非常多，用一个 Splash 服务来处理的话，未免压力太大了，此时可以考虑搭建一个负载均衡器来把压力分散到各个服务器上。这相当于多台机器多个服务共同参与任务的处理，可以减小单个 Splash 服务的压力。

## 1. 配置 Splash 服务

要搭建 Splash 负载均衡，首先要有多个 Splash 服务。假如这里在 4 台远程主机的 8050 端口上都开启了 Splash 服务，它们的服务地址分别为 41.159.27.223:8050、41.159.27.221:8050、41.159.27.9:8050 和 41.159.117.119:8050，这 4 个服务完全一致，都是通过 Docker 的 Splash 镜像开启的。访问其中任何一个服务时，都可以使用 Splash 服务。

## 2. 配置负载均衡

接下来，可以选用任意一台带有公网 IP 的主机来配置负载均衡。首先，在这台主机上装好 Nginx，然后修改 Nginx 的配置文件 nginx.conf，添加如下内容：

```python
http {
    upstream splash {
        least_conn;
        server 41.159.27.223:8050;
        server 41.159.27.221:8050;
        server 41.159.27.9:8050;
        server 41.159.117.119:8050;
    }
    server {
        listen 8050;
        location / {proxy_pass http://splash;}
    }
}
```

这样我们通过 upstream 字段定义了一个名字叫作 splash 的服务集群配置。其中 least\_conn 代表最少链接负载均衡，它适合处理请求处理时间长短不一造成服务器过载的情况。

当然，我们也可以不指定配置，具体如下：

```python
upstream splash {
    server 41.159.27.223:8050;
    server 41.159.27.221:8050;
    server 41.159.27.9:8050;
    server 41.159.117.119:8050;
}
```

这样默认以轮询策略实现负载均衡，每个服务器的压力相同。此策略适合服务器配置相当、无状态且短平快的服务使用。

另外，我们还可以指定权重，配置如下：

```python
upstream splash {
    server 41.159.27.223:8050 weight=4;
    server 41.159.27.221:8050 weight=2;
    server 41.159.27.9:8050 weight=2;
    server 41.159.117.119:8050 weight=1;
}
```

这里 weight 参数指定各个服务的权重，权重越高，分配到处理的请求越多。假如不同的服务器配置差别比较大的话，可以使用此种配置。

最后，还有一种 IP 散列负载均衡，配置如下：

```python
upstream splash {
    ip_hash;
    server 41.159.27.223:8050;
    server 41.159.27.221:8050;
    server 41.159.27.9:8050;
    server 41.159.117.119:8050;
}
```

服务器根据请求客户端的 IP 地址进行散列计算，确保使用同一个服务器响应请求，这种策略适合有状态的服务，比如用户登录后访问某个页面的情形。对于 Splash 来说，不需要应用此设置。

我们可以根据不同的情形选用不同的配置，配置完成后重启一下 Nginx 服务：

```
sudo nginx -s reload
```

这样直接访问 Nginx 所在服务器的 8050 端口，即可实现负载均衡了。

## 3. 配置认证

现在 Splash 是可以公开访问的，如果不想让其公开访问，还可以配置认证，这仍然借助于 Nginx。可以在 server 的 location 字段中添加 auth\_basic 和 auth\_basic\_user\_file 字段，具体配置如下：

```python
http {
    upstream splash {
        least_conn;
        server 41.159.27.223:8050;
        server 41.159.27.221:8050;
        server 41.159.27.9:8050;
        server 41.159.117.119:8050;
    }
    server {
        listen 8050;
        location / {
            proxy_pass http://splash;
            auth_basic "Restricted";
            auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
        }
    }
}
```

这里使用的用户名和密码配置放置在 /etc/nginx/conf.d 目录下，我们需要使用 htpasswd 命令创建。例如，创建一个用户名为 admin 的文件，相关命令如下：

```
htpasswd -c .htpasswd admin
```

接下来就会提示我们输入密码，输入两次之后，就会生成密码文件，其内容如下：

```
cat .htpasswd 
admin:5ZBxQr0rCqwbc
```

配置完成之后我们重启一下 Nginx 服务，运行如下命令：

```
sudo nginx -s reload
```

这样访问认证就成功配置好了。

## 4. 测试

最后，我们可以用代码来测试一下负载均衡的配置，看看到底是不是每次请求会切换 IP。利用 <http://httpbin.org/get> 测试即可，代码实现如下：

```python
import requests
from urllib.parse import quote
import re

lua = '''
function main(splash, args)
  local treat = require("treat")
  local response = splash:http_get("http://httpbin.org/get")
  return treat.as_string(response.body)
end
'''

url = 'http://splash:8050/execute?lua_source=' + quote(lua)
response = requests.get(url, auth=('admin', 'admin'))
ip = re.search('(\d+\.\d+\.\d+\.\d+)', response.text).group(1)
print(ip)
```

这里 URL 中的 splash 字符串请自行替换成自己的 Nginx 服务器 IP。这里我修改了 Hosts，设置了 splash 为 Nginx 服务器 IP。

多次运行代码之后，可以发现每次请求的 IP 都会变化，比如第一次的结果：

```
41.159.27.223
```

第二次的结果：

```
41.159.27.9
```

这就说明负载均衡已经成功实现了。

本节中，我们成功实现了负载均衡的配置。配置负载均衡后，可以多个 Splash 服务共同合作，减轻单个服务的负载，这还是比较有用的。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://python3webspider.cuiqingcai.com/7.3splash-fu-zai-jun-heng-pei-zhi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
