更新

更新

用例:

针对 JSON 数据提交进行优化的 API 服务器集群

我有一个分布式应用程序,用于向 MySQL 8 主服务器的从属 API 服务器发送信息。应用程序会进行完全初始同步(约 100,000 条记录,每批 500 条),然后每 5 分钟进行一次增量同步。

我有 3 台 Dell R620 服务器,配备 512GB RAM、5 个 SSD(RAID 6),用作 Web 服务器。我专门将其中一台用作主 MySQL,配置如下:

[mysqld]
server-id=1
# GENERAL #
pid-file                   = /var/run/mysqld/mysqld.pid
socket                     = /var/run/mysqld/mysqld.sock
datadir                        = /var/lib/mysql/
bind-address=*

# GENERAL #
user                           = mysql
default-storage-engine         = InnoDB

# MyISAM #
key-buffer-size                = 32M
myisam-recover-options         = FORCE,BACKUP

# SAFETY #
max-allowed-packet             = 16M
max-connect-errors             = 1000000
skip-name-resolve
#skip-grant-tables

# BINARY LOGGING #
log-bin                        = /var/lib/mysql/mysql-bin
binlog_expire_logs_seconds     = 2000
sync-binlog                    = 1

# CACHES AND LIMITS #
tmp-table-size                 = 32M
max-heap-table-size            = 32M
max-connections                = 500
thread-cache-size              = 50
open-files-limit               = 10000
table-definition-cache         = 4096
table-open-cache               = 4096
#
## INNODB #
innodb-flush-method            = O_DIRECT
innodb-log-files-in-group      = 2
innodb-log-file-size           = 512M
innodb-flush-log-at-trx-commit = 1
innodb-file-per-table          = 1
innodb-buffer-pool-size        = 360G
#
## LOGGING #
log-error                      = /var/lib/mysql/mysql-error.log
log-queries-not-using-indexes  = 1
slow-query-log                 = 1
slow-query-log-file            = /var/lib/mysql/mysql-slow.log
#

## REPLICATION ##
slave-parallel-workers=10
slave-parallel-type = LOGICAL_CLOCK
innodb-flush-log-at-timeout=1800

[mysql]

# CLIENT #
port                           = 3306

在托管 API 的其他服务器上,目标是让它们在本地从属服务器上执行选择查询,并将更改写回主服务器,这将使我们能够拥有专用于接收传入 API 调用的额外资源。因为它们主要用于 Apache/PHP,所以我减少了innodb-buffer-pool-size = 64G

对于高 RAM 服务器,我应该对 Apache 和 PHP 使用哪些优化?

我已经进行了设置,但不确定是否没有充分利用可用资源:

<IfModule mpm_prefork_module>
    StartServers             200
    MinSpareServers          20
    MaxSpareServers          50
    MaxRequestWorkers        100
    MaxConnectionsPerChild   0    
        ServerLimit           512
        MaxClients            512
        MaxRequestsPerChild   10000
</IfModule>

可以在此处找到我的设置的更完整概述,包括变量、状态、mysqltuner.pl 报告:http://plnkr.co/edit/eeGHzFX95j5auJ5lTYum?p=catalogue

更新

目前我们每小时收到大约 5600 个请求,其中大约 70% 的请求可能每个请求最多包含 500 条记录,需要更新或插入查询。总计每秒约 550 个查询。服务器负载通常在 2.5-4 之间。

该网站是用 Laravel 5.4 编写的,我们使用 Laravel、Eloquent 等测试了正常 API 路由的吞吐量,并使用 Apache Benchmark 测试了吞吐量: ab -c 100 -n 2000 -p sample.json -T application/json -H "Content-Type: application/json" -H "Authorization: Bearer eyJ0eXAiO" https://www.myserver.com/api/accounting

结果如下:

Benchmarking www.myserver.com (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests


Server Software:        Apache/2.4.29
Server Hostname:        www.myserver.com
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-CHACHA20-POLY1305,2048,256
TLS Server Name:        www.myserver.com

Document Path:          /api/accounting
Document Length:        65 bytes

Concurrency Level:      100
Time taken for tests:   375.487 seconds
Complete requests:      2000
Failed requests:        1134
   (Connect: 0, Receive: 0, Length: 1134, Exceptions: 0)
Total transferred:      735018 bytes
Total body sent:        162864000
HTML transferred:       131018 bytes
Requests per second:    5.33 [#/sec] (mean)
Time per request:       18774.370 [ms] (mean)
Time per request:       187.744 [ms] (mean, across all concurrent requests)
Transfer rate:          1.91 [Kbytes/sec] received
                        423.57 kb/s sent
                        425.49 kb/s total

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        3  315 1554.1      5   11497
Processing:  8420 18299 2501.9  18658   24051
Waiting:     8419 18298 2501.9  18658   24050
Total:       8424 18614 2791.2  18792   30388

Percentage of the requests served within a certain time (ms)
  50%  18792
  66%  19699
  75%  20247
  80%  20619
  90%  21560
  95%  22343
  98%  23933
  99%  27099
 100%  30388 (longest request)

sample.json 包含 500 条记录,服务器负载达到了 103。您还会注意到,超过一半的帖子都失败了。

在此处输入图片描述

看来 apache 是我们的瓶颈,当我深入研究它时,get_included_files()我发现 Laravel 使用了 275 个包含文件才到达 routes.php 文件,当它开始发布到我们的 API 时,它使用了 462 个,而在发布到 API 结束时,它使用了 575 个包含文件。

我们在 Laravel 之外使用定义 PDO 连接的单个 PHP 页面重建了相同的函数,以相同的方式循环数据查询,生成插入和更新查询,并使用以下统计数据完成相同的任务:

Concurrency Level:      100
Time taken for tests:   16.367 seconds
Complete requests:      2000
Failed requests:        228
   (Connect: 0, Receive: 0, Length: 228, Exceptions: 0)
Total transferred:      502228 bytes
Total body sent:        162804000
HTML transferred:       126228 bytes
Requests per second:    122.19 [#/sec] (mean)
Time per request:       818.366 [ms] (mean)
Time per request:       8.184 [ms] (mean, across all concurrent requests)
Transfer rate:          29.97 [Kbytes/sec] received
                        9713.76 kb/s sent
                        9743.73 kb/s total

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        3    9  14.7      6      98
Processing:   242  800 281.3    764    2187
Waiting:      241  799 281.3    764    2187
Total:        246  809 283.8    774    2195

Percentage of the requests served within a certain time (ms)
  50%    774
  66%    905
  75%    986
  80%   1040
  90%   1201
  95%   1328
  98%   1493
  99%   1618
 100%   2195 (longest request)

在发布这些内容时,服务器负载仅达到 12,且没有失败帖子。由于有了显著的改进,我们正在考虑将 API 代码从 Laraverl 中拉出,并为 Mysql 优化一台服务器,然后拥有多个从属服务器。每个从属服务器都只具有对本地主机的读取访问权限,以便 API 进行查询以确定每条记录应该是更新还是插入语句,然后在 MySQL 主服务器上执行查询。

虽然我已经四处寻找答案,但很多资源都是在 4GB-32GB RAM 是正常情况时编写的,而当你找到 512GB 的 RAM 时,它通常指的是 SSD。

答案1

针对您的 ulimit -a 结果的建议,

ulimit -n 24000    to enable more than current limit of 1024 Open Files

以上内容在 Linux 操作系统中是动态的。停止/启动服务将有权访问句柄。要使此操作在操作系统关闭/重新启动时保持不变,请查看此 URL 以获取类似的操作系统说明。这些说明将文件最大值设置为 500000,请暂时将容量设置为 24000。ulimit 请设置为 24000,这将允许 MySQL 使用请求的 10,000 个,并为其他应用程序留出备用空间

https://glassonionblog.wordpress.com/2013/01/27/increase-ulimit-and-file-descriptors-limit/

对 my.cnf [mysqld] 部分的建议(RPS = 每秒速率)

innodb_buffer_pool_size=36G  # from 240G because your innodb data+ndx ~ 22G
innodb_lru_scan_depth=100  # from 1024 to conserve 90% cpu cycles used for this function
max_connections=600  # from 500 - you are denying many connections today
innodb_io_capacity=1900  # from 200 to enable higher IOPS
read_rnd_buffer_size=192K  # from 256K to reduce handler_read_rnd_next RPS

免责声明:我是我的个人资料、网络个人资料中提到的网站内容的作者。

答案2

惊群效应。不要有如此多的 Apache 子进程。将其设置为不高于 CPU 中的核心(线程)数量。请记住,MySQL 也在争夺这些核心。

您的 值有冲突innodb_buffer_pool_size。将其设置为您拥有的数据量的两倍,但不要太大以免导致交换。然后设置innodb_buffer_pool_instances = 16

是“500”请求单身的 INSERT或者UPDATEIODKU?如果不是,让我们看看你在做什么,并努力使其成为单个 SQL 命令。这可能会将 MySQL 部分的速度提高 10 倍。

与此相关的问题是谁来决定“插入”和“更新”?

“JSON” 有什么意义?是否有一个很大的 JSON 字符串可以拆分成 500 个插入内容?或者 JSON 字符串是插入内容的“核心”?

为了更好地了解活动:您每秒执行多少个查询?每秒插入(或更新)多少行?

相关内容