AWS:使用云计算运行 Stockfish 高速分析棋局

基于浏览器/JavaScript 的国际象棋引擎(Engine)已在主流的国际象棋对弈网站(如 chess.comLichess)中流行已久。虽然这些引擎被移植至 JavaScript 后的确使得引擎的使用率被推广到了前所未有的高度,性能却大打折扣。

以我的 MacBook Pro(14英寸,2021年,搭载 Apple M1 Pro)为例,使用 Lichess 分析工具(运行以 WebAssembly 编译而成的 JavaScript 版 Stockfish NNUE)的分析速度约为每秒四百万节点(~4MN/s),如下图所示。



使用 Homebrew 在本地安装 Stockfish:

1
brew install stockfish

运行 Stockfish Bench 工具进行性能测试:

1
stockfish bench 16 16 18

结果为近每秒一千六百万节点(~16MN/s)。根据以上数据可得,Javascript 版 Stockfish 在我的 MacBook 上仅有原本的 1/4 性能。

1
2
3
4
===========================
Total time (ms) : 11156
Nodes searched : 174631062
Nodes/second : 15653555

使用

显然,从性能和效率上考虑,浏览器端引擎并不是一个优秀的解决方案。因此,在可行的条件下,我们应当尽量避免使用基于浏览器/JavaScript 的分析引擎。有关如何在国际象棋软件(Chess GUI)中使用 Stockfish,请参考此部分 Stockfish 官方 Wiki 中的内容(英文)

另外,Lichess 提供了在其网页版分析工具中通过设置 WebSocket 服务器引入外置引擎的功能(GitHub - lichess-org/external-engine),利用这一功能,我们可以很方便地利用 Lichess 网页客户端使用原生引擎。另外,在 Lichess 上完成的对局也都显然能够直接用于分析。有关此功能的部署和使用,请见下节:云计算。

云计算

要取得更快的分析速度,在某些情况下,使用云计算服务可能是个不错的选择。然而,需要注意的是,与许多云服务的用法不同,运行国际象棋引擎是一个极度依赖于计算资源的项目,在大部分环境下,Stockfish 的性能则几乎完全由 CPU 数量决定。因此,事实上,要取得可观的、比多数个人计算机更快的分析速度,我们需要选用计算能力较强(CPU 数量较多)的资源,而这也意味着较高额的账单。

好消息是,AWS EC2 的计费方式较为灵活,我们仅需为实际使用量付费。当 AWS EC2 实例停机后,则不再产生费用。若配置合理,仅有与其关联的附加服务会继续产生一部分小额费用。因此,只要仅在实际需要使用引擎进行分析时启动计算实例,并在结束时及时停机,账单额度便完全可控。另外,我认为我们的使用情景完全可以接受使用 Spot(抢占)实例,通过相关设定能够进一步优化成本。

以我所选用的 c6a.8xlarge(AMD EPYC 7R13, 32 vCPU, 64 GB RAM)为例,On-Demand(按量付费)的使用费用约为 USD 1.22/小时,若每天开机一小时,则每个月产生的账单额度约为 USD 37.23(数据来自 AWS 价格计算器)。



若我们选择请求 Spot 实例,根据该型号的历史竞价情况预估,应当能节省约 42% 左右成本,即 ~USD 0.71/小时。



根据我们的需求,有关 Spot 实例请求的最佳设定(位于 Advanced details)如下图所示。



安装

我建议从 Stockfish 最新代码进行编译安装,以下步骤以此为例,使用的操作系统为 Amazon Linux 2(RHEL/CentOS)。你也可以下载 Stockfish 官方发布版本的预构建二进制文件

1
2
3
4
5
6
7
8
sudo yum install -y git gcc gcc-c++ make

git clone https://github.com/official-stockfish/Stockfish.git
cd Stockfish/src

make -j build ARCH=x86-64-modern

sudo ln -s ~/Stockfish/src/stockfish /usr/bin/stockfish

在 EC2(c6a.8xlarge)上使用 Stockfish Bench 工具,得到了速度显著高于我的 MacBook 的结果(~51MN/s)。

1
2
3
4
===========================
Total time (ms) : 52024
Nodes searched : 2668352894
Nodes/second : 51290806

Lichess 外置引擎

为避免不必要的未使用开机时长所产生的费用,我对 lichess-org/external-engine 的代码做了简单修改

1
2
3
4
5
6
7
8
 if engine.alive and engine.idle_time() > args.keep_alive:
+ if args.idle_shutdown:
+ subprocess.run("sudo shutdown -h now", shell=True)
+ sys.exit()
logging.info("Terminating idle engine")
engine.terminate()

+ parser.add_argument("--idle-shutdown", action="store_true", help="Shut down the system when idle for longer than keep-alive if set")

若指定 --idle-shutdown 参数,则脚本将在空闲指定时间(--keep-alive)后自动停机以停止计费。

要使用我修改后的 Lichess 外置引擎脚本,请从以下库克隆代码并安装依赖:

1
2
3
4
git clone https://github.com/binaryshell/external-engine

cd external-engine
pip3 install -r requirements.txt

接下来,请在 Lichess 网站创建具备外置引擎读写权限的 API 访问 Token



你可以直接通过以下指令直接运行 Lichess 外置引擎服务:

1
python3 example-provider.py --name "AWS EC2" --token=lip_YOURTOKEN --engine /usr/bin/stockfish

不过,我建议将其设定为系统服务以便使用,以及在开机后自动启动。

编辑 /etc/systemd/system/external-engine.service 文件并置入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=External Engine Provider for Lichess.org

[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/ec2-user/external-engine/example-provider.py --name "AWS EC2 c6a.8xlarge" --token=lip_YOURTOKEN --engine /usr/bin/stockfish --max-hash 32768 --max-threads 128 --default-depth 32 --idle-shutdown
User=ec2-user
Group=ec2-user
Restart=always

[Install]
WantedBy=multi-user.target

其中,参数中的 --max-hash--max-threads 值应当按照实例的属性调整以获得最佳性能。

载入并启用服务:

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable external-engine.service
sudo systemctl start external-engine.service

此时,登入 Lichess 分析面板即可选择使用外置引擎。



And enjoy! :)




参考

我在搭建此服务的过程中参考了这篇文章:Running Stockfish in the Cloud | MattPlaysChess(英文)
其中,作者列出了部分 AWS EC2 实例型号运行 Stockfish Bench 工具的结果(性能),并介绍了在支持 UCI 协议的棋局分析工具(如 ChessBase 等国际象棋数据库软件)中通过 SSH 连接远程服务器上的 Stockfish 的相关思路。

netsage by qian