3

我有一个非常奇怪的问题。

我在 Ubuntu 上运行一个非常繁忙的 LAMP Web 服务(每天有超过一百万的访问者),最近我遇到了 apache 响应缓慢的问题。

奇怪的是,网络服务器机器和数据库机器都没有达到任何限制。CPU 使用率和内存看起来都还不错(它们基本上甚至没有达到最大值的 10%)。Apache 有足够的空闲进程来处理传入的请求。目前它每秒大约有 350 到 500 个请求,并且配置为 800 个。

我玩过 Mysql 设置(innodb)但没有成功。我检查了慢查询日志、进程列表等,没有任何慢查询或任何阻碍系统的迹象。

目前我能做的唯一一件事就是让系统保持速度,就是在用户访问时禁用一些数据库调用。换句话说,限制每次用户访问时进行的数据库调用量。但我必须这样做的事实让我感到震惊,因为机器远未达到极限。

我用 iotop 检查了磁盘使用情况,也不是很多。两台服务器都是双 AMD 16 核机器,配备 Vertex 4 SSD 和 16GB RAM。

我开始有点迷路了,所以我想知道:你们对我还可以尝试或寻找什么有什么建议吗?

小更新:如果我运行以下查询,它会出现 21343。这可能意味着我的 12G 的 innodb_buffer_pool_size 太低了?我有可能遇到这个问题吗?

SELECT CEILING(Total_InnoDB_Bytes/POWER(1024,2)) RIBPS FROM
(SELECT SUM(data_length+index_length) Total_InnoDB_Bytes
FROM information_schema.tables WHERE engine='InnoDB') A;

这是两台机器的配置设置、top 和 iftop。

Apache:
Timeout 30
KeepAlive On
MaxKeepAliveRequests 0
KeepAliveTimeout 2
StartServers 100
MinSpareServers 100
MaxSpareServers 200
MaxClients          1000
MaxRequestsPerChild 0



Mysql:
default-character-set = utf8
skip-external-locking
skip-name-resolve
skip-locking
open_files_limit = 102400
wait_timeout = 30
interactive_timeout = 30
key_buffer              = 16M
max_allowed_packet      = 16M
thread_stack            = 256K
thread_cache_size       = 50
max_connections        = 50000
table_cache            = 4096
thread_concurrency     = 8
innodb_thread_concurrency = 8
innodb_buffer_pool_size=12G
innodb_additional_mem_pool_size=10M
innodb_log_file_size=1500M
innodb_log_buffer_size=8M
innodb_flush_log_at_trx_commit = 0
tmp_table_size         = 128M
max_heap_table_size    = 128M
query_cache_limit       = 5M
query_cache_size        = 128M
log_slow_queries        = /var/log/mysql/mysql-slow.log
long_query_time = 3

Top output apacheserver:
Tasks: 842 total,   1 running, 841 sleeping,   0 stopped,   0 zombie
Cpu(s):  3.0%us,  0.5%sy,  0.0%ni, 96.3%id,  0.0%wa,  0.0%hi,  0.2%si,  0.0%st
Mem:  16446884k total, 11921852k used,  4525032k free,   183140k buffers
Swap:  9541624k total,    58596k used,  9483028k free,  7439992k cached

Top output mysql server:
Tasks: 197 total,   1 running, 196 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.2%us,  0.2%sy,  0.0%ni, 99.5%id,  0.0%wa,  0.0%hi,  0.1%si,  0.0%st
Mem:  16446544k total, 16197496k used,   249048k free,   147632k buffers
Swap: 16755756k total,   277020k used, 16478736k free,  1976760k cached

iftop apache server:
TX:             cumm:  5.68MB   peak:   4.84Mb  rates:   4.56Mb  3.11Mb  3.25Mb
RX:                     973KB            647Kb            643Kb   556Kb   556Kb
TOTAL:                 6.63MB           5.48Mb           5.19Mb  3.65Mb  3.79Mb

iftop mysql server
TX:             cumm:   954B    peak:   1.36Kb  rates:      0b    541b    347b
RX:                    4.59KB           4.69Kb           4.69Kb  2.89Kb  1.67Kb
TOTAL:                 5.52KB           4.69Kb           4.69Kb  3.41Kb  2.01Kb
4

3 回答 3

1

我发现速度变慢是由 iptables 达到其连接限制引起的。我查看了系统日志文件,发现以下错误:nf_conntrack:表已满,正在丢弃数据包。

提高 sysctl.conf 文件中的 nf_conntrack 值解决了该问题。

于 2013-11-14T11:08:40.047 回答
1

随着最新信息和评论的添加,这一切都开始变得有意义了。

您的插入语句锁定表,导致瓶颈,可能是因为您的用户日志表中的索引。

所以(假设的)流程是

  • 用户请求页面

  • 插入用户日志表需要 x 毫秒,在 x 毫秒的持续时间内,表(或索引或​​自动增量列)被锁定,不允许在同一个表上执行其他插入语句

  • 下一个用户在前一个插入完成之前出现,因此在插入用户日志表之前必须等待。有这么多用户,即使服务器只是坐着,队列也会迅速增长,响应时间很慢。

解决方案(?):

这是大多数数据库系统的主要问题。前段时间我遇到过类似的问题,并通过创建一个包含单列(当然没有索引)的表来解决它,我在其中插入了我想要运行的 sql 语句。然后运行一个连接到数据库并在单个事务中执行所有语句的 cronjob(每 5 分钟)。我的流量要低得多,硬件也差得多,所以您可能需要对上述解决方案进行一些微调。

您可以尝试的其他事情包括:

  • 删除用户日志表的所有索引和自动增量

  • 创建一个具有相同值但没有 id 的辅助表,然后插入到真实的用户日志表并从辅助表中删除。(和第一个类似)

  • 使用 memcached 或 redis 等快速存储来存储用户日志,并运行守护程序或 cron 以导出统计信息

  • 使用异步数据库插入,例如使用监听套接字并将数据插入用户日志表的守护进程。然后,您的脚本与要插入的数据联系守护程序,守护程序立即响应,但将插入命令附加到 FIFO 队列中并在可能的情况下插入。

PS。插入和更新语句在高流量网页中发生时总是需要特别小心。选择语句要容易得多,只要您有适当的索引,您就不必担心它们

于 2013-11-13T11:29:30.947 回答
0

反应慢

数字在哪里?

目前它每秒大约有 350 到 500 个请求,并且配置为 800

您如何在 Apache 中配置每秒请求数?

没有任何缓慢查询的迹象....long_query_time = 3

但似乎每个请求都会导致多个数据库调用 - 因此对于您没有看到的每个请求,可能会有长达 3 秒的倍数。真的,您应该记录所有查询的性能统计信息(旋转的 rust 设备可能更适合于此)

根据您提供的数字,性能不太可能是由于 i/o(0 等待)。处理 12Gb 数据确实需要很长时间(仅 DDR3 上的延迟大约为 0.5 秒,而最佳带宽将其减少到大约 5 秒)但您的 sys 和 usr 时间太低,这意味着这不是问题。

因此,开始寻找问题的最合乎逻辑的地方是网络服务器和数据库之间的网络延迟。

你在使用普通的 ORM 吗?切换到工厂(或至少延迟加载)可能会带来很大的改进。

检查数据包丢失和冲突,确保您的 NIC 配置正确(速度、双工),在 NIC 驱动程序上启用延迟中断。

还要确保网络服务器上的调度没有问题(例如,所有东西都固定在同一个核心上)。

于 2013-11-13T10:27:53.013 回答