使用Funkload运行和自动化分布式负载测试的工具
项目描述
Bench Master 3000
本包的目的是帮助您使用FunkLoad在多台服务器和/或处理器上运行大型、并行化的负载测试。如果您只需要进行适度的负载测试,可能直接使用FunkLoad会更好。
即使您最终使用的是“普通”的FunkLoad,此文档也可能提供一些有用的提示和见解。但请务必阅读FunkLoad的文档。它是一个非常强大且灵活的工具。要充分发挥Bench Master的优势,您必须熟悉其各种脚本和服务。
工作原理理论
Bench Master允许将负载测试部署到多个服务器(或单个服务器的多个别名,从而更好地利用多核或多处理器系统),每个服务器都有自己的负载测试运行器。当所有负载测试运行器完成基准测试后,结果将汇总到主服务器,生成综合报告。
恰好有一个“主节点”,以及一个或多个“节点”。主节点通过SSH与节点通信,使用pssh库并行化操作。节点可以是不同的物理机器,尽管也可以使用同一台机器多次(在这种情况下,将建立多个并发SSH连接)。同一台机器——甚至是同一版本的Bench Master——也可以同时作为主节点和一个或多个节点。(在这种情况下,主节点实际上将建立一个或多个SSH连接到localhost。)
负载测试使用FunkLoad正常创建/记录。这将生成两个文件,必须将它们保存在同一目录下
<Testname>.conf,用于配置负载测试运行器、FunkLoad监控服务器等。
test_<Testname>.py,其中包含实际的测试,作为FunkLoadTestCase的子类,具有单个测试方法test_<testName>。
在使用Bench Master时,有一个可用的扩展:您可以执行以下操作来获取节点编号(一个大于或等于0的整数,在配置中以字符串形式表示)
node_num = self.conf_get('bench', 'node_num', '0')
这有助于区分节点:由于所有节点都并行执行测试运行,因此需要小心不要有两个测试同时要求同一资源(例如,登录名)。
请注意,虽然可以将FunkLoad测试放入包中,但FunkLoad实际上只考虑模块。将测试和.conf文件对放入任何目录,即使没有__init__.py,也是完全可行的。
先决条件
首先,一些需求
Bench Master只能在类Unix操作系统中运行。
您至少需要安装FunkLoad 0.12和PSSH 2.1.1。这些将被安装为benchmaster包的依赖项。
您必须在Bench Master上安装ssh和scp。
您还必须在Bench Master上安装gnuplot,以便它可以生成其报告。通常最好使用操作系统的包管理器来安装。
所有Bench节点都必须运行SSH守护程序,并接受来自Bench Master的连接。
提示:您的Bench节点上的SSH守护程序可能只接受有限数量的入站连接。如果您使用了许多“虚拟”节点,则需要小心不要拒绝后者连接。如果您使用OpenSSH,应在sshd_config文件中将MaxStartups和MaxSessions选项设置为足够高的数值。
Bench Master必须能够在不输入密码或被提示接受远程主机的签名的情况下SSH到节点。实际上,这意味着Bench Master运行的用户的公钥必须列在远程Bench节点上用户的authorized_keys文件中,并且每个远程节点的签名必须在Bench Master上的known_hosts文件中记录。
所有Bench节点应设置相同。特别是,Bench节点运行程序的安装和工作目录应在所有主机上的同一路径。
可选地,您还可以配置Bench节点上的SSH守护程序以接受由Bench Master发送的各种环境变量。这些对于正常操作不是必需的,但在编写和调试负载测试时可能很有用。这些变量是
- PSSH_NODENUM
节点的编号。第一个节点将有编号0。
- PSSH_BENCH_RUN
当前测试运行的名称。在调用bench master时可以设置。默认值基于当前日期和时间以及测试名称生成一个唯一的名称。
- PSSH_BENCH_WORKING_DIR
顶级bench节点工作目录。
要使用这些,需要在每个节点的 sshd_config 文件中添加以下内容
AcceptEnv PSSH_*
安装
Bench Master可以使用 zc.buildout、easy_install 或 pip 安装。它将安装两个控制其执行的控制台脚本,分别是 bench-master 和 bench-node。
以下是一个 buildout.cfg 文件,它可以创建一个可以用于bench master和/或节点的隔离环境
[buildout] parts = bench-tools versions = versions # Note: Change versions as required or remove versions block to get # latest versions always [versions] benchmaster = 1.0b1 funkload = 1.12.0 pssh = 2.1.1 [bench-tools] recipe = zc.recipe.egg eggs = funkload benchmaster
注意:如上所示,将版本“固定”是一个好的做法。然而,您应该检查在您阅读本说明时哪些版本是合适的。或者,您可以完全跳过 [versions] 块以获取所有内容的最新版本,但请注意,如果某些依赖项在PyPI上发布了不兼容的版本,这可能会在未来造成问题。
为了简单起见,建议您在所有参与bench运行的服务器上创建相同的安装。例如,您可以将上面的 buildout.cfg 文件放在 /opt/bench 中,然后运行
$ buildout bootstrap --distribute # or download a bootstrap.py and run that $ bin/buildout
提示:您应确保所有bench节点安装都属于适当的用户 - 通常是与bench master一起通过SSH远程登录的用户。
现在您应该已经在 bin 目录中有了 bench-master、bench-node 以及FunkLoad的各种 fl-* 脚本。
如果您更喜欢使用 pip 或 easy_install,您可以只需安装 benchmaster egg。然而,建议您在 virtualenv 中这样做。
$ virtualenv --no-site-package bench $ cd bench $ bin/easy_install benchmaster
录制测试
要记录测试,您可以使用与FunkLoad一起安装的 fl-record 脚本。要使用它,您还需要安装 TCPWatch。tcpwatch 二进制文件需要位于系统路径中,以便 fl-record 可以找到它。或者,您可以将 TCPWATCH 环境变量设置为指向二进制文件本身。
例如,您可以使用以下这样的buildout
[buildout] parts = bench-tools versions = versions # Note: Change versions as required or remove versions block to get # latest versions always [versions] benchmaster = 1.0b1 funkload = 1.12.0 pssh = 2.1.1 tcpwatch = 1.3.1 [bench-tools] recipe = zc.recipe.egg:scripts eggs = docutils funkload tcpwatch benchmaster initialization = import os os.environ['TCPWATCH'] = "${buildout:bin-directory}/tcpwatch"
安装TCPWatch后,您可以使用以下命令启动记录器
$ bin/fl-record TestName
注意:您应该使用“驼峰命名法”来命名测试。这确保生成的代码遵循bench-master程序期望的约定。如果您使用其他命名约定,您可能需要将测试名称指定为bench-master命令的可选命令行参数 - 请参阅下面。
现在打开一个网页浏览器,并配置它使用 127.0.0.1 端口 8090 的HTTP代理(有关详细信息,请参阅 fl-record 输出和文档)。
在此阶段,您可以访问要测试的网站并执行您想要进行负载测试的操作。提前规划您的步骤会有所帮助,因为“随意”的点击或重新加载会使测试更难以重复或有用。
完成操作后,返回运行 fl-record 的终端并按 Ctrl+C。它应该会生成两个文件:test_TestName.py 和 TestName.conf。
您可能希望将这些文件移出当前目录,例如
$ mkdir bench-tests $ mv test_* bench-tests/ $ mv *.conf bench-tests/
在此阶段,您应该编辑这两个生成的文件,以确保它们作为负载测试是有效和有用的。.conf 文件包含注释,您可能想填写详细信息,例如更具体的名称。
您还需要考虑如果您的测试用例在多个基准节点上反复、并行运行会发生什么。如果您只是抓取几个页面,使用记录的测试可能就足够了。但是,如果您正在进行任何特定的用户操作(例如登录或提交详细信息),您需要确保并行测试不会相互干扰。
为了区分测试,您可以使用 node_num 配置变量。您可以在 FunkLoadTestCase 中获取此变量
node_num = self.conf_get('bench', 'node_num', '0')
注意,Funkload 还附带了一个凭证服务器(请参阅 fl-credential-ctl 脚本),您可以使用它来维护多个线程和多轮测试运行的单个凭证数据库。
执行测试
您可以使用 fl-run-test 脚本来执行指定模块中的所有测试。这对于负载测试来说不是很有用,但在编写和调试测试时非常有用。它也可以作为简单的功能测试工具。
$ bin/fl-run-test test_Testname.py
这将运行指定模块中的测试。请注意,测试和相应的 .conf 文件需要位于当前目录中。如果您已将测试移动到专用目录,例如如上所述的 bench-tests/,则可以执行以下操作
$ cd bench-tests $ ../bin/fl-run-test test_Testname.py
有关更多详细信息,请参阅 FunkLoad 文档。
要在单个节点上运行简单的基准测试,您可以使用 fl-run-bench。这是基准主控在每个节点上执行的操作
$ bin/fl-bench-test test_Testname.py Testname.test_TestName
请注意,我们必须指定测试用例类(Testname)和方法(test_TestName),因为基准运行程序只会运行一个测试,即使您在模块中放入了多个测试。
在此阶段,了解控制基准运行程序的参数很有用。
- 周期
基准运行程序将运行给定测试的多个周期。每个周期在特定的并发级别上运行,这相当于在该周期中使用一定数量的线程。这实际上是对具有多个并发用户执行负载测试场景的模拟。
您可以使用 -c 命令行参数指定周期。例如,-c 10:20:30 将分别执行三个周期,线程数分别为 10、20 和 30。默认周期在负载测试的 .conf 文件中配置。
为了获得有用的负载测试,您通常会运行多个周期,步长固定,这使得测试的输出更容易比较。
- 持续时间
基准运行程序将为固定持续时间的每个周期运行。默认值在 .conf 文件中找到,但可以用 -D 命令行参数覆盖,例如 -D 300 以运行每个周期 5 分钟。
给定周期内的每个线程都会尽可能多地执行测试,直到测试结束(即经过 duration 秒)。不完整的测试将被终止,不会计入负载测试结果。
此外,您还可以设置请求之间的最小和最大睡眠时间(实际的睡眠时间是在这两个值之间的随机值),测试执行之间的睡眠时间以及线程启动延迟。这些有助于模拟一定程度上的随机性和延迟,有时也可以作为一种有用的方法,在真实测试开始之前让服务器达到“稳定状态”。请查看 -h 选项的 fl-run-bench 命令输出,以及 .conf 文件中的注释,以及 FunkLoad 文档的详细信息。
提示:尝试不同的持续时间并发设置。由于每个线程都会在测试持续时间内重复执行测试,因此可以通过增加任一参数来增加正在执行的测试数量。高并发与低持续时间模拟了高负载的短暂爆发。较长的持续时间模拟了持续负载。后者通常更有启示性,因为短持续时间可能会导致 FunkLoad 丢失在持续时间结束前未完成的测试,而实际上这些测试可能永远不会完成,因为服务器上的网关超时。
一旦您已经测试了您的基准测试在“普通”FunkLoad 中正常工作,您就可以使用 Bench Master 部署它。
为了说明这种部署,我们假设
上述先决条件已安装。
您已在两台机器上安装了 Bench Master,分别为 192.168.0.10 和 192.168.0.11,使用上述建议的 buildout,在 /opt/bench 中。因此,二进制文件位于 /opt/bench/bin/。
Bench Master 以用户 bench 运行。此用户存在于两个主机上,并拥有 /opt/bench 及其子目录的所有权。
已设置 SSH 密钥,以便 bench 可以从主服务器到节点以及从主服务器到自身(我们将使用 bm.example.com 作为基准节点以及主服务器)进行 SSH 连接,而无需输入密码。
提示:首先手动测试此操作,并确保远程主机已知,即被记录在 known_hosts 文件中。
测试位于 /opt/bench/bench-tests/test_Testname.py,相应的 Testname.conf 在同一目录。
首先,我们需要创建一个节点配置文件。这告诉基准主服务器要将测试部署到哪些节点。我们将称此为 nodes.pssh,并将其保存在顶级目录 /opt/bench 中。它应包含如下条目
load-test-00 bench load-test-01 bench load-test-02 bench load-test-03 bench
第一个标记是主机名。第二个是使用的用户名。请注意,我们在这里使用“伪”主机名。这是因为我们希望使用相同的物理服务器多次。这些可以在 /etc/hosts 文件中解析为实际 IP 地址,例如使用
load-test-00 192.168.245.10 load-test-01 192.168.245.11 load-test-02 192.168.245.10 load-test-03 192.168.245.11
在这里,我们选择在每台物理机器上运行两个基准节点。这种配置适用于双核/处理器的机器,其中一个 Python 进程可以充分利用每个核心。
我们现在可以执行测试
$ mkdir bench-output $ bin/bench-master -s /opt/bench/bin/bench-node -w bench-output -c 10:20:30 -D 300 nodes.pssh bench-tests/test_Testname.py
在此命令中
-s 选项指定远程基准节点上 bench-node 脚本的路径 (仅限于远程基准节点)。(它不需要在主节点上存在,除非主服务器也用作节点。)如果 bench-node 已在远程服务器上给定用户的 PATH 中,则可以省略此选项。此选项用于 ssh 调用,以在每个主机上执行 bench-node 脚本。
-w 选项是基准主节点的当前工作目录。它最终将包含最终的基准报告以及基准运行期间记录的信息。每个基准运行的具体信息都汇总在一个中间目录下,该目录的名称与基准运行的名称相同。默认情况下,使用当前日期/时间和测试名称。
-c 选项覆盖了每个节点上基准测试的并发设置 (仅限于每个节点)。在这里,我们将运行三个循环,每个节点分别使用 10、20 和 30 个并发线程。这意味着,如果使用四个节点,则实际的并发线程数分别为 40、80 和 120。
-D 选项以类似的方式覆盖持续时间。因此,在每个循环中,每个节点上的每个线程将尝试在 5 分钟(300 秒)内尽可能多次执行测试。由于节点并行运行,这意味着每个循环的总持续时间是 5 分钟。
两个位置参数给出了节点文件和测试模块的路径。在这种情况下,可以提供相对或绝对路径——它不需要在当前目录中。
除了这些选项外,还可以指定
-n,为基准运行指定名称,该名称用作基准主工作目录下的目录名称。默认情况下,使用由当前日期和时间以及测试名称构建的名称。请注意,如果您在多次调用中使用相同的名称,则临时文件可能会被覆盖,但所有最终报告都将保留。
--num-nodes,限制正在使用的节点数量。默认情况下,使用节点文件中的所有节点。如果您只想使用前两个节点,例如,可以指定 --num-nodes=2。
-x,指示每个节点上的工作目录路径。默认情况下,使用 /tmp/bench-node,如果不存在则将其创建。
-u,覆盖测试的基础 URL,该 URL 存在于测试 .conf 文件中。
-v,查看更多输出。
最后,可能需要给出测试名称(即记录测试时给予 fl-record 的名称)作为第三个位置参数,在测试模块 .py 文件之后。如果您在记录测试时没有使用“驼峰式”(或全部小写),则这是必要的。例如,如果模块 test_FooBar.py 中的测试方法为 test_foo_bar(),则可以使用
$ bin/bench-master -s /opt/bench/bin/bench-node -w bench-output -c 10:20:30 -D 300 nodes.pssh bench-tests/test_FooBar.py foo_bar
有关更多详细信息,请参阅 bin/bench-master -h 的输出。
观察执行
在基准主节点运行期间,它将
在每个节点上创建一个工作空间,并将测试文件以及针对每个节点定制的 .conf 文件远程复制到该工作空间中。可以使用 -x 命令行选项设置每个节点上工作空间的父目录。在此目录内部,为每个标记的测试运行创建一个子目录。
注意:您可以使用 -n 选项设置标签。这对于将测试分组在一起很有用。默认情况下,会根据当前日期/时间和测试名称创建一个唯一的标签。
在每个测试运行子目录内部,为每个节点创建一个特定的子目录。这允许在同一个物理机器上的同一个安装中有多个“虚拟”节点(即多个节点进程)。
在每个节点上执行 bench-node 脚本。这会进一步运行 FunkLoad 基准测试运行器。
在每个节点上监控标准输出和标准错误。这些可以在 bench 主工作空间的 out/ 和 err/ 目录中找到,以文本文件的形式对应于每个节点。您可以 tail 这些文件以获得每个节点的实时输出。
err/ 目录将帮助您了解远程节点是否出现了问题。 out/ 目录有助于检查每个节点的进度。
当测试正在运行时,您将在三个标题下看到各种进度指示器:“启动线程”、“记录 <duration> 秒”和“停止线程”。对于每一项,您可能会看到许多“。”、“E”或“F”字符。一个“。”表示成功,一个“E”表示错误,一个“F”表示失败。
启动和停止线程的失败可能表明 FunkLoad 无法启动足够的线程以获取周期中指示的并发性。这是否是一个问题取决于您实际需要生成有效负载测试的并发性。FunkLoad 无论如何都会继续进行测试。
“记录 <duration> 秒”这一行是最重要的。这是 FunkLoad 实际执行测试的时间。这里的错误表明测试代码本身存在问题,并且应该很少见。一个“F”表示无法获取页面,或者测试断言失败。在负载测试场景中,这可能意味着您的服务器已停止响应或超时。报告(见下文)将提供有关报告了哪些类型失败和错误的更多详细信息。
查看报告
一旦所有远程节点都完成,bench 主将
将每个节点上的 FunkLoad 输出 XML 文件收集到 bench 主工作空间的 results/ 子目录中。
将这些文件合并成一个结果文件。
从这个结果生成一个 HTML 报告。
最终的 HTML 报告将出现在 bench 主工作空间的 report/ 目录中。如果它在远程服务器上,您可能希望使用能够提供静态 HTML 文件的 Web 服务器来提供它,以便于查看报告。
例如,您可以使用以下命令在端口 8000 上启动一个简单的 HTTP 服务器:
$ cd bench-output $ python -m SimpleHTTPServer 8000
当然,您也可以使用 Apache、nginx 或任何其他 Web 服务器,并且可以使用 -w 选项到 bench-master 脚本来将所有结果放入一个已经配置为提供 Web 内容的目录中。
提示:如果您正在运行多个相关的负载测试,例如测试一系列对您基础设施的计划更改的效果,将这些报告分组在一起可能会有所帮助。如果您使用相同的名称运行多个基准测试,如由-n选项给出,Bench Master会将所有报告分组在单个顶级目录下(<bench name>/reports/*)。请注意,如果您这样做,out/和err/目录中的文件将在每次运行时被覆盖。
您第一次看到FunkLoad报告时,可能会被详尽的细节所淹没。一些更重要的事项包括:
查找任何错误或失败。这些报告针对每个循环,以及针对单个页面,并在报告末尾总结。请注意,在高并发时,错误 - 特别是像503或504这样的HTTP错误 - 可能只是表明您已经“用尽”了您的服务器。如果这种情况发生在远高于实际预期的并发性下,这可能不是问题。
查看整个基准测试的整体吞吐量,并观察它如何随着循环并发性的变化而变化。FunkLoad通过三个指标来展示这一点:
- 每秒成功测试次数
这是可以执行的完整测试次数除以持续时间,汇总到所有循环中。
如果您的测试模拟用户在多个步骤中完成特定过程(例如购买产品或创建某些内容),这可以是一个有用的“业务”指标(例如,“我们可以在10分钟内卖出X产品”)。
- 每秒成功页面次数
这是每秒可以下载的完整Web页面的数量,包括样式表和图像等资源。
请注意,FunkLoad将以与网络浏览器相同的方式缓存资源,因此给定的线程可能在给定循环中只获取某些资源一次。
这是一个有用的指标,了解当您的网站在负载下运行时,访问者可能会接收到多少“页面印象”。如果您的测试只获取一个页面,或者获取的页面在服务器处理时间方面大致相同,则此指标最有意义。
- 每秒成功请求数
这是原始吞吐量的衡量标准,即每秒完成的请求数。
这个指标不一定与访问者体验您的网站有关,因为它将网页及其依赖资源视为单独的请求。
查找整体趋势。随着并发性的增加,性能如何下降?是否存在任何“硬”限制,性能明显下降,或者网站完全停止响应?如果是这样,请尝试考虑这可能是怎么回事,例如操作系统对线程数或处理器或打开文件描述符的数量限制。
查看正在获取的各个页面。是否有任何页面特别慢?随着并发的增加,不同的页面性能如何下降?
有关更多详细信息,请参阅FunkLoad文档。
服务器监控
理解负载测试运行期间发生的事情非常重要。如果结果不是您所期望或希望的,您需要知道从哪里开始调整。
一些重要的考虑因素包括:
托管应用程序的服务器上的CPU、内存和磁盘I/O负载是多少?瓶颈在哪里?
基准节点和被测试服务器之间的网络基础设施容量是多少?您是否受到带宽的限制?是否有任何防火墙或其他设备正在执行密集请求扫描,甚至主动限制吞吐量?
实验台节点上发生了什么?它们是否未能生成足够的负载,或者未能处理从服务器返回的数据量?
在任何情况下,您都需要进行监控。这可以包括:
在服务器上运行 top、free 以及其他“点时间”监控工具。
使用 monit 等工具实时观察多个进程。
查看与您的应用程序相关的各种服务的日志文件,包括在测试运行时的实时日志以及测试完成后。
使用 FunkLoad 内置的监控工具。
注意: FunkLoad 监控服务器仅适用于 Linux 主机。
FunkLoad 监控器非常有用,至少因为它包含在最终报告中。您可以看到在负载测试过程中,任意数量的服务器上的负载过载、内存和网络吞吐量发生了什么。
FunkLoad 监控需要在每个被监控的主机上运行监控服务器。监控控制程序 fl-monitor-ctl 与 FunkLoad 一起安装。您可以使用上面显示的 Bench Master 构建配置来安装它,或者在每个主机上简单地安装 virtualenv 或 buildout。
一旦您安装了 fl-monitor-ctl,每个主机都需要一个配置文件。例如
[server] # configuration used by monitord host = localhost port = 8008 # sleeptime between monitoring in second # note that load average is updated by the system only every 5s interval = .5 # network interface to monitor lo, eth0 interface = eth0 [client] # configuration used by monitorctl host = localhost port = 8008
您应根据需要调整主机名、网络接口和端口号。
然后您可以使用以下命令在每个主机上启动监控器
$ bin/fl-monitor-ctl monitor.conf startd
安装监控器后,您需要告诉 FunkLoad 要监控哪些主机。这通过测试的 .conf 文件中的 [monitor] 部分完成。例如
[monitor] hosts = bench-master.example.com bench-node.example.com www.example.com [bench-master.example.com] description = Bench master port = 8008 [bench-node.example.com] description = Bench node port = 8008 [www.example.com] description = Web server port = 8008
在这个例子中,我们选择监控实验台主节点和节点,以及正在测试的 web 服务器。监控实验台节点很重要,因为它有助于确定它们是否按正常情况生成负载。
有了这个配置,您应该在 FunkLoad 报告中获得监控信息。
注意: 如果您使用 bench-master 运行测试,它将确保只有第一个节点收集监控统计数据。从所有节点同时监控多个主机是没有意义的。
手动生成报告
当 FunkLoad 执行基准运行时,它将写入一个包含所有相关测试结果和统计数据的 XML 文件。基准主节点从每个节点收集这些 XML 文件,并将它们汇总到一个文件中。(这些单独的文件都保存在 bench-master 工作目录内部基准运行目录下的 results/ 目录中。)然后它使用 FunkLoad 报告生成器创建一个 HTML 报告。
如果您想手动创建报告,可以使用 fl-build-report 脚本。
例如,要获取报告的纯文本版本,可以使用
$ bin/fl-build-report bench-output/<run name>/results/*.xml
要获取相同报告的 HTML 版本,可以使用 -html 选项
$ bin/fl-build-report --html bench-output/<run name>/results/*.xml
报告将被放置在当前目录下。使用 -o 标志指示不同的输出目录。
差异报告
您可以使用负载测试来了解您的更改对性能的影响。为了更容易比较负载测试运行,FunkLoad 提供了差异报告。
例如,假设您已经在 bench-output/baseline/reports/test_foo-20100101 中创建了一个“基线”报告。然后,您可以添加一个新的服务器,并在 bench-master 中重新运行相同的测试,这次使用“new-server”名称。生成的报告可能是 bench-output/new-server/reports/test_foo-20100201。您可以使用以下方式创建两个报告之间的差异:
$ bin/fl-build-report --diff bench-output/baseline/reports/test_foo-20100101 bench-output/new-server/reports/test_foo-20100201
当然,这同样适用于使用“plain” FunkLoad 生成的报告。
提示:为了使差异报告有意义,您需要在两个报告中执行相同的测试,具有相同的周期数、相同的周期并发性和相同的持续时间。
致谢
最初由 Julian Coyne 创建 <julian.coyne@unified.com.au>。由 Martin Aspeli <optilude@gmail.com>重构为单独的包。
变更日志
1.0b1 - 2010-07-26
初始发布
benchmaster-1.0b1.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 1614164bccd0ca6c6e4f6357640fa205cf052ab5f2b15252d5f1f593eeb58333 |
|
MD5 | 8f0248c5b15cbe3e0defd1e0e39cd270 |
|
BLAKE2b-256 | 9c313a569157db980c378b8c6d3ce648ef79e89da94f6ec6afed395da6edf1de |