ExtMail开源邮箱系统-当单个域名邮箱数量太多时导致管理后台域名列表打不开的处理办法
用了ExtMail开源邮箱系统,当单个域名下邮箱数量多达30多万个时,发现管理后台打不开域名列表菜单,一直返回504,报超时错误。查了下日志,然后看了下代码发现域名列表,会调用以下几个函数get_domain_usage、get_users_list、get_aliases_list执行超时,先来看下这个函数:
sub get_users_list {
my $self = shift;
my $SQL = "SELECT * FROM mailbox WHERE domain=?";
my $rs = $self->get_entries($SQL, $_[0]);
my $arr = []; # null ARRAY ref
foreach my $ref (sort by_username @$rs) {
push @$arr, {
mail => $ref->{username},
cn => $ref->{name},
domain => $ref->{domain},
uidnumber => $ref->{uidnumber},
gidnumber => $ref->{gidnumber},
uid => $ref->{uid},
netdiskquota => $ref->{netdiskquota},
active => $ref->{active} ? 1 : 0,
quota => $ref->{quota},
passwd => $ref->{password},
clearpw => $ref->{clearpwd},
mailhost => $ref->{mailhost},
maildir => $ref->{maildir},
homedir => $ref->{homedir},
expire => $ref->{expiredate},
create => $ref->{createdate},
disablepwdchange => $ref->{disablepwdchange} ? 1 : 0,
disablesmtpd => $ref->{disablesmtpd},
disablesmtp => $ref->{disablesmtp},
disablewebmail => $ref->{disablewebmail},
disablenetdisk => $ref->{disablenetdisk},
disableimap => $ref->{disableimap},
disablepop3 => $ref->{disablepop3},
question => $ref->{question},
answer => $ref->{answer},
}
}
scalar @$arr ? $arr : undef;
}
这个函数去根据域名把对应域名的所有邮箱记录都查出来,那30多万条记录查询失败。找到问题了就好办了
改成SUM累加一条语句搞定。
解决方案:
第一步:
MySQL.pm文件(/var/www/extsuite/extman/libs/Ext/Mgr路径下)
增加两个函数:
sub _count_users_fast {
my ($self, $domain) = @_;
my $dbh = $self->{backend}->{dbh};
return $dbh->selectrow_array(
"SELECT COUNT(*) FROM mailbox WHERE domain=?", undef, $domain
);
}
sub _count_aliases_fast {
my ($self, $domain) = @_;
my $dbh = $self->{backend}->{dbh};
return $dbh->selectrow_array(
"SELECT COUNT(*) FROM alias WHERE domain=?", undef, $domain
);
}
在OverView.pm中下面两行代码:(/var/www/extsuite/extman/libs/Ext/MgrApp路径下)
my $curalias = ($buf = $mgr->get_aliases_list($m)) ? scalar @$buf : '0';
my $curusers = ($buf = $mgr->get_users_list($m)) ? scalar @$buf : 0;
改成:
my $curalias = $self->_count_aliases_fast($m);
my $curusers = $self->_count_users_fast($m);
第二步:
MgrApp.pm(/var/www/extsuite/extman/libs/Ext目录下)
保留接口名 get_domain_usage,只把 “全表拉回再循环” 改成 “一条 SUM 语句”:
把原来的 get_domain_usage 整段替换为
sub get_domain_usage {
my ($self, $domain) = @_;
my $dbh = $self->{dbh};
# 一条 SQL 直接求和,不再拉 30 万条记录
my ($quota, $ndquota) = $dbh->selectrow_array(
"SELECT SUM(quota), SUM(netdiskquota)
FROM mailbox
WHERE domain = ?",
undef,
$domain
);
return {
quota => $quota || 0,
ndquota => $ndquota || 0,
};
}
重启邮箱服务,再次访问域名列表返回就很快了。