【发布时间】:2015-06-23 23:25:55
【问题描述】:
我有一个监控系统,我的客户可以在其中注册他们的终端,并且他的终端会定期(5 分钟)向我的网站发送一个保活信号以通知它在线。客户还可以访问显示他所有终端的监控页面,并以 20 秒的间隔使用 ajax 更新其状态。
附加信息:终端是安卓设备,客户必须从google play安装一个应用程序。
问题是: 随着客户数量的增加,许多人同时访问监控页面,这几乎使服务器充满了许多请求,而另一方面。每次都有更多的终端涌入并充斥着更多的keepalive信号。因此,除了常见页面(登录、许多 CRUD 等)之外,我还有几十个通过互联网发送保活信号的物理终端淹没了我的数据库,并且许多用户访问监控页面以了解他们的终端在线。这似乎是一个定时炸弹。因为我不知道当终端数量达到数百并且还在增加时,mysql是否支持。
PLUS我们已经注意到我们的服务器在运行时会降低性能。我们重新启动它,它非常快,但随着时间的推移,它会失去性能
解决方案
我可以做些什么来提高性能或使模型更具可扩展性?这种监控系统有没有一种扩展性更强的设计模式?
如果我分离两个 mysql 数据库,一个用于常用(访问页面、cruds 等),另一个用于监控系统,会有什么好处?
仅将 MongoDB 用于系统的监控部分有什么好处吗?
其他信息:
mysql Ver 14.14 Distrib 5.5.43,适用于 Linux (x86_64),使用 readline 5.1
PHP 5.4.40 (cli)(构建时间:2015 年 4 月 15 日 15:55:28)
Jetty 8.1.14(用于与 android 应用程序通信的 java 服务器端)
服务器周一
Free memory ........: 17.84 Gb
Total memory........: 20 Gb
Used memory.........: 2.16 Gb
RAM.................: 20 Kb
JVM Free memory.....: 1.56 Gb
JVM Maximum memory..: 3.93 Gb
JVM Total available.: 1.93 Gb
**************************************
Total (cores).: 10
CPU idle......: 4.9%
CPU nice......: 0.0%
CPU system....: 4183000.0%
CPU total.....: 5.0%
CPU user......: 2.6%
**************************************
Total space (bytes)..: 600 Gb
Free space (bytes)...: 595.64 Gb
Usable space (bytes).: 595.64 Gb
模型和监控页面查询的一部分
这是终端表
CREATE TABLE IF NOT EXISTS `GM_PLAYER` (
`ID_PLAYER` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`DS_GCM_ID` VARCHAR(250) NULL,
`DT_CRIACAO` DATETIME NOT NULL,
`DS_PLAYER` VARCHAR(100) NOT NULL,
`DS_JANELA_HEIGHT` INT(11) NOT NULL DEFAULT '1024',
`DS_JANELA_WIDTH` INT(11) NOT NULL DEFAULT '768',
`DS_JANELA_POS_X` INT(11) NOT NULL DEFAULT '0',
`DS_JANELA_POS_Y` INT(11) NOT NULL DEFAULT '0',
`DS_WALLPAPER` VARCHAR(255) NULL DEFAULT NULL,
`FL_ATIVO` CHAR(1) NOT NULL DEFAULT 'N',
`FL_FULL_SCREEN` CHAR(1) NOT NULL DEFAULT 'S',
`FL_MOUSE_VISIBLE` CHAR(1) NOT NULL DEFAULT 'N',
`DS_SERIAL` VARCHAR(50) NULL DEFAULT NULL,
`VERSAO_APP` VARCHAR(20) NULL DEFAULT NULL,
`VERSAO_OS` VARCHAR(20) NULL DEFAULT NULL,
`FL_EXIBIR_STATUS_BAR` CHAR(1) NOT NULL DEFAULT 'S',
`ID_GRADE_PROGRAMACAO` BIGINT UNSIGNED NULL DEFAULT NULL,
`ID_CLIENTE` BIGINT UNSIGNED NULL,
`ID_PONTO` BIGINT UNSIGNED NULL,
`FL_ATIVO_SISTEMA` CHAR(1) NOT NULL DEFAULT 'S',
`FL_DEBUG` CHAR(1) NOT NULL DEFAULT 'N',
`VERSAO_APP_UPDATE` VARCHAR(20) NULL,
`FL_ESTADO_MONITOR` CHAR(1) NOT NULL DEFAULT 'L',
`FL_DEVICE_ROOTED` CHAR(1) DEFAULT 'N',
`DT_ATIVACAO` DATETIME ,
`DT_EXPIRA` DATETIME ,
`FL_EXCLUIDO` CHAR(1) DEFAULT 'N' ,
`ID_USUARIO` BIGINT UNSIGNED NOT NULL,
`ID_PACOTE` BIGINT UNSIGNED ,
`DS_IMG_BARRA` VARCHAR(255),
`FL_EXIBIR_HORA` CHAR(1),
`DS_TEXTO_BARRA` TEXT,
PRIMARY KEY (`ID_PLAYER`),
UNIQUE INDEX `UQ_GM_PLAYER_ID_PLAYER` (`ID_PLAYER` ASC),
INDEX `ID_GRADE_PROGRAMACAO` (`ID_GRADE_PROGRAMACAO` ASC),
INDEX `FK_GM_PLAYER_GM_CLIENTE_idx` (`ID_CLIENTE` ASC),
CONSTRAINT `FK_GM_PLAYER_GM_USUARIO` FOREIGN KEY (`ID_USUARIO`) REFERENCES `GM_USUARIO` (`ID_USUARIO`) ON DELETE RESTRICT,
CONSTRAINT `FK_GM_PLAYER_GM_GRADE_PROGRAMACAO` FOREIGN KEY (`ID_GRADE_PROGRAMACAO`) REFERENCES `GM_GRADE_PROGRAMACAO` (`ID_GRADE_PROGRAMACAO`) ON DELETE RESTRICT,
CONSTRAINT `FK_GM_PLAYER_GM_CLIENTE` FOREIGN KEY (`ID_CLIENTE`) REFERENCES `GM_CLIENTE` (`ID_CLIENTE`) ON DELETE RESTRICT
)
ENGINE = InnoDB
AUTO_INCREMENT = 5
DEFAULT CHARACTER SET = latin1;
另一个用过的表
CREATE TABLE IF NOT EXISTS `GM_CLIENTE` (
`ID_CLIENTE` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`DT_CRIACAO` DATETIME NOT NULL,
`DS_CLIENTE` VARCHAR(50) NOT NULL,
`FL_ATIVO` ENUM('S','N') NULL DEFAULT 'S',
`ID_CONTATO` BIGINT UNSIGNED NOT NULL,
`ID_ENDERECO` BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (`ID_CLIENTE`),
UNIQUE INDEX `UQ_Cliente_ID_CLIENTE` (`ID_CLIENTE` ASC),
INDEX `fk_GM_CLIENTE_GM_CONTATO1_idx` (`ID_CONTATO` ASC),
INDEX `fk_GM_CLIENTE_GM_ENDERECO1_idx` (`ID_ENDERECO` ASC),
CONSTRAINT `fk_GM_CLIENTE_GM_CONTATO1`
FOREIGN KEY (`ID_CONTATO`)
REFERENCES `GM_CONTATO` (`ID_CONTATO`)
ON DELETE RESTRICT,
CONSTRAINT `fk_GM_CLIENTE_GM_ENDERECO1`
FOREIGN KEY (`ID_ENDERECO`)
REFERENCES `GM_ENDERECO` (`ID_ENDERECO`)
ON DELETE RESTRICT)
ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARACTER SET = latin1;
CREATE TABLE GM_USUARIO_CLIENTE (
ID_USUARIO_CLIENTE INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
ID_CLIENTE BIGINT UNSIGNED ,
ID_USUARIO BIGINT UNSIGNED
);
这是我每次收到新的终端保活信号时都会更新的表格
CREATE TABLE IF NOT EXISTS `GM_LOG_PLAYER` (
`id_log_player` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`dt_criacao` DATETIME NOT NULL,
`id_player` BIGINT UNSIGNED NULL,
`qtd_midias_exibidas` INT(11) NULL,
`id_ultima_midia_exibida` BIGINT UNSIGNED NULL,
`up_time_android` bigint(20) unsigned default '0',
`up_time_app` bigint(20) unsigned default '0',
`mem_utilizada` BIGINT(20) NULL,
`mem_disponivel` BIGINT(20) NULL,
`hd_disponivel` BIGINT(20) NULL,
`hd_utilizado` BIGINT(20) NULL,
PRIMARY KEY (`id_log_player`),
UNIQUE INDEX `UQ_id_log_player` (`id_log_player` ASC),
INDEX `FK_GM_LOG_PLAYER_GM_PLAYER_idx` (`id_player` ASC),
INDEX `FK_GM_LOG_PLAYER_GM_MIDIA_idx` (`id_ultima_midia_exibida` ASC),
CONSTRAINT `FK_GM_LOG_PLAYER_GM_PLAYER`
FOREIGN KEY (`id_player`)
REFERENCES `GM_PLAYER` (`ID_PLAYER`)
ON DELETE CASCADE,
CONSTRAINT `FK_GM_LOG_PLAYER_GM_MIDIA`
FOREIGN KEY (`id_ultima_midia_exibida`)
REFERENCES `GM_MIDIA` (`ID_MIDIA`))
ENGINE = InnoDB
AUTO_INCREMENT = 3799
DEFAULT CHARACTER SET = latin1;
CREATE TABLE IF NOT EXISTS `GM_GRADE_PROGRAMACAO` (
`ID_GRADE_PROGRAMACAO` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`DT_CRIACAO` DATETIME NOT NULL,
`DS_GRADE_PROGRAMACAO` VARCHAR(100) NULL DEFAULT NULL,
`ID_USUARIO` BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (`ID_GRADE_PROGRAMACAO`),
UNIQUE INDEX `UQ_GM_GRADE_PROGRAMACAO_ID_GRADE_PROGRAMACAO` (`ID_GRADE_PROGRAMACAO` ASC),
INDEX `fk_GM_GRADE_PROGRAMACAO_GM_USUARIO1_idx` (`ID_USUARIO` ASC),
CONSTRAINT `fk_GM_GRADE_PROGRAMACAO_GM_USUARIO1`
FOREIGN KEY (`ID_USUARIO`)
REFERENCES `GM_USUARIO` (`ID_USUARIO`)
ON DELETE RESTRICT)
ENGINE = InnoDB
AUTO_INCREMENT = 3
DEFAULT CHARACTER SET = latin1;
这是通过ajax请求定期执行的查询来更新监控页面
SELECT * FROM (
SELECT
LOG.id_log_player ,
LOG.dt_criacao ,
DATE_FORMAT (LOG.DT_CRIACAO , '%d/%m/%Y %H:%i:%s') F_DT_CRIACAO ,
(CURRENT_TIMESTAMP - LOG.DT_CRIACAO) AS IDADE_REGISTRO ,
LOG.qtd_midias_exibidas ,
LOG.id_ultima_midia_exibida ,
LOG.up_time_android ,
LOG.up_time_app ,
LOG.mem_utilizada ,
LOG.mem_disponivel ,
LOG.hd_disponivel ,
LOG.hd_utilizado ,
PLA.FL_MONITOR_LIGADO,
CLI.DS_CLIENTE ,
PLA.ID_PLAYER id_player ,
PLA.DS_PLAYER ,
PLA.ID_CLIENTE ,
PLA.VERSAO_APP ,
PLA.FL_ATIVO PLA_FL_ATIVO ,
PLA.ID_GRADE_PROGRAMACAO ,
PLA.FL_DEVICE_ROOTED ,
PLA.DS_GCM_ID ,
PLA.FL_HDMI_LIGADO ,
-- IF(PLA.FL_ATIVO='N',0,IF(PLA.ID_GRADE_PROGRAMACAO IS NULL,0,IF(PLA.ID_GRADE_PROGRAMACAO='0',0,1))) ATIVO,
IF(PLA.FL_ATIVO='N',0,1) ATIVO,
DATE_FORMAT (LOG.DT_CRIACAO , '%Y%m%d%H%i%s') TIME_STAMP_CRIACAO ,
DATE_FORMAT (LOG.DT_CRIACAO , '%d/%m às %H:%i') F_DT_CRIACAO_MIN ,
-- (CURRENT_TIMESTAMP - LOG.DT_CRIACAO) ESPERA_NOVA_COMUNICACAO ,
--GRA.ID_GRADE_PROGRAMACAO GRA_ID_GRADE ,
GRA.DS_GRADE_PROGRAMACAO GRA_DS_GRADE_PROGRAMACAO,
MID.DS_PATH_THUMB THUMB_ULTMID
FROM GM_PLAYER PLA
LEFT JOIN GM_CLIENTE CLI USING ( ID_CLIENTE )
LEFT JOIN GM_USUARIO_CLIENTE GUC USING ( ID_CLIENTE )
LEFT JOIN GM_LOG_PLAYER LOG USING ( ID_PLAYER )
LEFT JOIN GM_GRADE_PROGRAMACAO GRA USING ( ID_GRADE_PROGRAMACAO )
-- LEFT JOIN GM_GRADE_PROGRAMACAO GRA ON ( PLA.ID_GRADE_PROGRAMACAO = GRA.ID_GRADE_PROGRAMACAO )
LEFT JOIN GM_MIDIA MID ON ( LOG.ID_ULTIMA_MIDIA_EXIBIDA = MID.ID_MIDIA )
WHERE PLA.ID_USUARIO = ?
AND PLA.FL_EXCLUIDO = 'N'
AND PLA.FL_ATIVO = 'S'
ORDER BY LOG.DT_CRIACAO DESC
) TBALL
GROUP BY ID_PLAYER
ORDER BY PLA_FL_ATIVO DESC , DT_CRIACAO DESC
EXPLAIN QUERY ABOVE(取自开发数据库)
+----+-------------+------------+--------+------------------------------------------------------+----------------------------------------------+---------+--------------------------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+------------------------------------------------------+----------------------------------------------+---------+--------------------------------------+-------+----------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 37752 | Using temporary; Using filesort |
| 2 | DERIVED | PLA | ALL | NULL | NULL | NULL | NULL | 44 | Using where; Using temporary; Using filesort |
| 2 | DERIVED | CLI | eq_ref | PRIMARY,UQ_Cliente_ID_CLIENTE | PRIMARY | 8 | imidiatv.PLA.ID_CLIENTE | 1 | NULL |
| 2 | DERIVED | GUC | ref | fk_GM_CLIENTE_has_GM_USUARIO_GM_CLIENTE1_idx | fk_GM_CLIENTE_has_GM_USUARIO_GM_CLIENTE1_idx | 8 | imidiatv.PLA.ID_CLIENTE | 1 | Using index |
| 2 | DERIVED | LOG | ref | FK_GM_LOG_PLAYER_GM_PLAYER_idx | FK_GM_LOG_PLAYER_GM_PLAYER_idx | 9 | imidiatv.PLA.ID_PLAYER | 858 | NULL |
| 2 | DERIVED | GRA | eq_ref | PRIMARY,UQ_GM_GRADE_PROGRAMACAO_ID_GRADE_PROGRAMACAO | PRIMARY | 8 | imidiatv.PLA.ID_GRADE_PROGRAMACAO | 1 | NULL |
| 2 | DERIVED | MID | eq_ref | PRIMARY,UQ_GM_MIDIA_ID_MIDIA | PRIMARY | 8 | imidiatv.LOG.id_ultima_midia_exibida | 1 | NULL |
+----+-------------+------------+--------+------------------------------------------------------+----------------------------------------------+---------+--------------------------------------+-------+----------------------------------------------+
提前致谢
【问题讨论】:
-
有多少个终端发送keyalive? (从中我可以计算出每秒有多少查询。)监控也是如此。监控
SELECT是什么样的?还有SHOW CREATE TABLE? -
我在钓鱼 (1) 是不是有太多的 qps 是问题所在,还是 (2) 是查询效率低下,应该改进。
-
@RickJames,早上好!今天我只有大约 80 个终端,但我希望它在一年内支持大约 1000 个。您请求的 SELECTs 和 CREATE TABLE 现已发布
标签: mysql linux performance database-performance query-performance