Skip to content

Commit

Permalink
Added cluster viewing and analysis capabilities
Browse files Browse the repository at this point in the history
Added cluster viewing and analysis capabilities
  • Loading branch information
cc20110101 committed May 30, 2019
1 parent 556d1dc commit bd21dda
Show file tree
Hide file tree
Showing 9 changed files with 464 additions and 69 deletions.
3 changes: 2 additions & 1 deletion src/RedisView/AppView/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1128,7 +1128,7 @@ void MainWindow::about() {
"<br>"
"<b>RedisView</b><br><br>"
"作者 :王长春<br>"
"版本 :Community v1.6.5<br>"
"版本 :Community v1.6.6<br>"
"邮箱 :[email protected]<br>"
"地址 :<a href='https://sourceforge.net/projects/redisview/'>sourceforge</a> <a href='https://github.com/cc20110101/RedisView'>github</a> <a href='https://www.oschina.net/p/RedisView'>oschina</a><br>"
"版权 :Copyright 2018 Powered By CC<br>"
Expand All @@ -1139,6 +1139,7 @@ void MainWindow::about() {
void MainWindow::history() {
QMessageBox::about(this, tr("版本历史"),
tr(
"<br>2019/05/30&nbsp;&nbsp;Version 1.6.6&nbsp;&nbsp;新增集群信息查看分析功能.<br>"
"<br>2019/05/08&nbsp;&nbsp;Version 1.6.5&nbsp;&nbsp;修复设置含空格值失败Bug.<br>"
"<br>2019/04/08&nbsp;&nbsp;Version 1.6.4&nbsp;&nbsp;修复值初始化模式Bug.<br>"
"<br>2019/04/05&nbsp;&nbsp;Version 1.6.3&nbsp;&nbsp;修复键值过长显示不全Bug.<br>"
Expand Down
149 changes: 140 additions & 9 deletions src/RedisView/AppView/RedisInfoDialog.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
/**
* @file RedisInfoDialog.h
* @brief Redis服务端信息与分析
* @author 王长春
* @date 2019-05-30
* @version 001
* @copyright Copyright (c) 2018
*/
#include "RedisInfoDialog.h"
#include "ui_redisinfodialog.h"

Expand Down Expand Up @@ -53,6 +61,8 @@ RedisInfoDialog::RedisInfoDialog(RedisCluster *redisClient,

ui->_itemComboBox->addItem("All");
ui->_itemComboBox->addItem("Dbsize");
ui->_itemComboBox->addItem("Analysis");
ui->_itemComboBox->addItem("Clusterinfo");
ui->_itemComboBox->addItem("Server");
ui->_itemComboBox->addItem("Clients");
ui->_itemComboBox->addItem("Memory");
Expand All @@ -62,8 +72,6 @@ RedisInfoDialog::RedisInfoDialog(RedisCluster *redisClient,
ui->_itemComboBox->addItem("CPU");
ui->_itemComboBox->addItem("Cluster");
ui->_itemComboBox->addItem("Keyspace");

//on__queryPushButton_clicked();
}
}

Expand All @@ -89,27 +97,147 @@ void RedisInfoDialog::on__queryPushButton_clicked()
_byteArray.clear();
ui->_textBrowser->clear();
_strCmd = ui->_itemComboBox->currentText();
if(_strCmd == "All") {
_strCmd = "info";
} else if(_strCmd == "Dbsize") {

if(_strCmd == "Dbsize") {
if(!_redisClient->dbsize(llRet))
llRet = -1;
_appendInfo = QString("# Dbsize\r\nmaster_total_key:%1\r\n").arg(llRet);
_appendInfo = QString("# Dbsize\r\nall_master_total_key:%1\r\n").arg(llRet);
ui->_textBrowser->insertPlainText(_appendInfo);
return;
} else if(_strCmd == "Analysis") {
int index = -1;
QMap<QString,QString> infoMap;
QStringList infoList;
for(int i = 0; i < _vClients.size(); ++i) {
if(!_vClients[i]._master)
continue;
_byteArray.clear();
infoMap.clear();
_cmdRsult.clear();
_strCmd = "info";
_cmdRsult = _redisClient->command(_strCmd, "", i);
if(_cmdRsult.size() <= 0)
continue;
_redisClient->formatToText(_cmdRsult[0], _byteArray , iRet);
_strCmd = QTextCodec::codecForLocale()->toUnicode(_byteArray);
infoList = _strCmd.split("\r\n",QString::SkipEmptyParts);
for(int j = 0; j < infoList.size(); ++j) {
index = infoList[j].indexOf(":");
if(index == -1) {
infoMap[infoList[j]] = "nil";
continue;
}
infoMap[infoList[j].mid(0, index)] = infoList[j].mid(index + 1);
}
_appendInfo = QString("# Analysis");
_appendInfo += QString("\r\n");
_appendInfo += tr("主机实例:");
_appendInfo += QString("%1:%2").arg(_vClients[i]._host).arg(_vClients[i]._port);
_appendInfo += QString("\r\n");
_appendInfo += tr("最大内存:");
_appendInfo += QString("%1").arg(infoMap.value("maxmemory","null"));
_appendInfo += QString("\r\n");
_appendInfo += tr("使用内存:");
_appendInfo += QString("%1").arg(infoMap.value("used_memory","null"));
_appendInfo += QString("\r\n");
_appendInfo += tr("内存碎片率:");
_appendInfo += QString("%1").arg(infoMap.value("mem_fragmentation_ratio","null"));
_appendInfo += QString("\r\n");
_appendInfo += tr("客户端连接数:");
_appendInfo += QString("%1").arg(infoMap.value("connected_clients","null"));
_appendInfo += QString("\r\n");
_appendInfo += tr("拒绝连接请求数:");
_appendInfo += QString("%1").arg(infoMap.value("rejected_connections","null"));
_appendInfo += QString("\r\n");
_appendInfo += tr("每秒执行命令数:");
_appendInfo += QString("%1").arg(infoMap.value("instantaneous_ops_per_sec","null"));
_appendInfo += QString("\r\n");
_appendInfo += tr("内存限制被删除键数:");
_appendInfo += QString("%1").arg(infoMap.value("evicted_keys","null"));
_appendInfo += QString("\r\n");
_appendInfo += tr("连接从实例数:");
_appendInfo += QString("%1").arg(infoMap.value("connected_slaves","null"));
_appendInfo += QString("\r\n");
if(infoMap.value("evicted_keys","0").toLongLong() > 0) {
_appendInfo += QString("\r\n");
_appendInfo += tr("当evicted_keys>0时,表示碎片过多或空间不足,可以通过碎片整理、增加maxmemory参数值或进行集群扩容解决!");
}
if(infoMap.value("rejected_connections","0").toLongLong() > 0) {
_appendInfo += QString("\r\n");
_appendInfo += tr("当rejected_connections>0时,表示客户端数量过多,请减小不必要的应用或通过增加maxclients参数值解决!");
}
if(infoMap.value("instantaneous_ops_per_sec","0").toLongLong() > 12000) {
_appendInfo += QString("\r\n");
_appendInfo += tr("当instantaneous_ops_per_sec>12000时,表示该实例压力较大,可以通过slot迁移或进行集群扩容解决!");
}
if(infoMap.value("maxmemory","-1").toLongLong() > 0) {
if(infoMap.value("used_memory","0").toLongLong() * 100 / infoMap.value("maxmemory","-1").toLongLong() > 60) {
_appendInfo += QString("\r\n");
_appendInfo += tr("当内存使用率大于60%时,可以通过数据清理、slot迁移或进行集群扩容解决!");
}
}
if((infoMap.value("used_memory","0").toLongLong()
* infoMap.value("mem_fragmentation_ratio","0").toInt()
+ infoMap.value("used_memory","0").toLongLong())
> infoMap.value("maxmemory","0").toLongLong()) {
_appendInfo += QString("\r\n");
_appendInfo += tr("当使用内存*(1+内存碎片率)>最大内存时,表示碎片过多或空间不足,可以通过碎片整理、增加maxmemory参数值或进行集群扩容解决!");
}
ui->_textBrowser->append(_appendInfo);
ui->_textBrowser->append("\r\n");
}

if(_isClusterMode) {
_byteArray.clear();
infoList.clear();
infoMap.clear();
_strCmd = "cluster info";
_cmdRsult = _redisClient->command(_strCmd, "", ui->_hostComboBox->currentIndex());
if(_cmdRsult.size() <= 0)
return;
_redisClient->formatToText(_cmdRsult[0], _byteArray , iRet);
_strCmd = QTextCodec::codecForLocale()->toUnicode(_byteArray);
infoList = _strCmd.split("\r\n",QString::SkipEmptyParts);
for(int k = 0; k < infoList.size(); ++k) {
index = infoList[k].indexOf(":");
if(index == -1) {
infoMap[infoList[k]] = "nil";
continue;
}
infoMap[infoList[k].mid(0, index)] = infoList[k].mid(index + 1);
}
if(infoMap.value("cluster_state","no") == "ok") {
ui->_textBrowser->append(tr("集群状态:正常"));
ui->_textBrowser->append("\r\n");
} else {
ui->_textBrowser->append(tr("集群状态:异常"));
ui->_textBrowser->append("\r\n");
}
}
return;
} else if(_strCmd == "Clusterinfo") {
if(!_isClusterMode) {
ui->_textBrowser->append(tr("非集群模式"));
return;
}
_strCmd = "cluster info";
} else if(_strCmd == "All") {
_strCmd = "info";
} else {
_strCmd = QString("info %1").arg(_strCmd);
}

_cmdRsult = _redisClient->command(_strCmd, "", ui->_hostComboBox->currentIndex());
for(int i = 0; i < _cmdRsult.size(); ++i) {
_redisClient->formatToText(_cmdRsult[i], _byteArray , iRet);
ui->_textBrowser->append(QTextCodec::codecForLocale()->toUnicode(_byteArray));
_strCmd = QTextCodec::codecForLocale()->toUnicode(_byteArray);
ui->_textBrowser->append(_strCmd);
}

if(ui->_itemComboBox->currentText() == "All") {
if(!_redisClient->dbsize(llRet))
llRet = -1;
_appendInfo = QString("# Dbsize\r\nmaster_total_key:%1\r\n").arg(llRet);
_appendInfo = QString("# Dbsize\r\nall_master_total_key:%1\r\n").arg(llRet);
ui->_textBrowser->insertPlainText(_appendInfo);
}
}
Expand All @@ -127,8 +255,11 @@ void RedisInfoDialog::on__hostComboBox_currentTextChanged(const QString &arg1)

void RedisInfoDialog::on__itemComboBox_currentTextChanged(const QString &arg1)
{
if(arg1 == "Dbsize" || arg1 == "Analysis" || arg1 == "Clusterinfo")
ui->_hostComboBox->setEnabled(false);
else
ui->_hostComboBox->setEnabled(true);
on__queryPushButton_clicked();
Q_UNUSED(arg1);
}

void RedisInfoDialog::on__textBrowser_textChanged()
Expand Down
8 changes: 8 additions & 0 deletions src/RedisView/AppView/RedisInfoDialog.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
/**
* @file RedisInfoDialog.h
* @brief Redis服务端信息与分析
* @author 王长春
* @date 2019-05-30
* @version 001
* @copyright Copyright (c) 2018
*/
#ifndef REDISINFODIALOG_H
#define REDISINFODIALOG_H

Expand Down
2 changes: 1 addition & 1 deletion src/RedisView/Public/Define.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@


// 定义字符串
#define WindowTitle "RedisView Community v1.6.5"
#define WindowTitle "RedisView Community v1.6.6"
#define IniFileName "conf.ini"


Expand Down
49 changes: 49 additions & 0 deletions src/RedisView/RedisLib/RedisClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,55 @@ bool RedisClient::getReplicationInfo(QMap<QString,QString> &infoMap) {
return _bRet;
}

/**
* 获取Redis信息
* @param[out] infoMap信息
* @return 成功是ture,否false
* @see
* @note
*/
bool RedisClient::getRedisInfo(QMap<QString,QString> &infoMap) {
_sErrorInfo.clear();
_cmd.clear();
_cmd.append("info");

_cmdResult = command(_cmd);
if(_cmdResult[0] == '-') {
if(parseRespError(_cmdResult,_sValue))
_sErrorInfo = _sValue;
else
_sErrorInfo = "parser resp error info failed";
_bRet = false;
} else if(_cmdResult[0] == '$') {
QString sValue;
if(parseRespBulkString(_cmdResult,sValue, _iRet)) {
if(_iRet == -1) {
_bRet = false;
_sErrorInfo = "value is nil";
} else {
int index = -1;
QStringList infoList = sValue.split("\r\n",QString::SkipEmptyParts);
for(int i = 0; i < infoList.size(); ++i) {
index = infoList[i].indexOf(":");
if(index == -1) {
infoMap[infoList[i]] = "nil";
continue;
}
infoMap[infoList[i].mid(0, index)] = infoList[i].mid(index + 1);
}
_bRet = true;
}
} else {
_sErrorInfo = "parser resp bulk string info failed";
_bRet = false;
}
} else {
_bRet = false;
_sErrorInfo = QString("parser resp type failed:") + _cmdResult[0];
}
return _bRet;
}

/**
* 判断是否是集群模式下主节点
* @param[out] value 是否集群主
Expand Down
9 changes: 9 additions & 0 deletions src/RedisView/RedisLib/RedisClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,15 @@ class RedisClient : public QObject, public RedisRespParser
*/
bool getReplicationInfo(QMap<QString,QString> &infoMap);

/**
* 获取Redis信息
* @param[out] infoMap信息
* @return 成功是ture,否false
* @see
* @note
*/
bool getRedisInfo(QMap<QString,QString> &infoMap);

/**
* 判断是否是集群模式下主节点
* @param[out] value 是否集群主
Expand Down
Binary file modified src/RedisView/Resources/en.qm
Binary file not shown.
Loading

0 comments on commit bd21dda

Please sign in to comment.