如何实现邮件服务分布式部署与负载均衡

前言

公司这几天给我分配的任务是实现我司邮件服务器分布式部署,我司邮件服务器采用的是Postfix + Dovecot + Mysql的组合,并且基于Docker进行了部署。我在网上搜寻了许多的解决方案,在阅读了[一天不进步,就是退步]的博文后,我进行了系统架构设计,并成功地实现了邮件服务器分布式部署。本文理论上不仅适用于邮件服务器,其他许多基于TCP的服务器都可参考本文实现方式。

系统架构与说明

系统的架构图如下:


邮件服务器负载均衡架构图

我们来分析一下该架构,从下往上看,该架构将系统分为了存储层,邮件处理层以及代理层,下面是对各层的说明。

存储层

在邮件服务器中,会涉及到邮件的存储,因为是分布式结构,所以要考虑各个邮件服务器之间数据的一致性,一般有两种解决方案:

  1. 使用NFS等网络文件系统,它使用一台服务器专门用于文件存储,然后通过网络将其文件夹挂载(mount)到各服务器中,类似于Windows的文件共享。该方法的好处是操作简单,相当于多台服务器使用同一存储空间,保证了数据的一致性,缺点也显而易见,太依赖于同一台数据存储服务器,当它宕机,所有挂载它的服务器全部GG。
  2. 采用分布式文件存储,相当于每一台服务器都使用各自的存储空间,该方法的好处是:对比于方案1,它一台服务器宕机,不会涉及所有服务器用户,只会涉及到它服务器下的用户,缺点是实现比较困难,因为需要维护服务器与用户之间的关系,保证数据的一致性。
    因为我还没想到如何实现方案二中用户与邮件服务器的对应关系,所以本文采用方案1进行系统部署。也希望知道方案2如何实现的朋友能在下方评论告知本人,万分感谢!
    关于数据库,因为本文主要讲的是邮件服务器实现分布式,在此便不对数据库相关进行展开了。

邮件处理层

该层存在多个并行的邮件服务器,用于处理邮件的传输与管理,如果多个邮件服务器在同一台主机(IP)上,则SMTP、IMAP/POP3需要使用不同的端口号,如果在不同的主机(IP)上,则端口号随意。该层的邮件服务器可自由地进行扩充。

代理层

该层连接外网与邮件处理层,实现了各邮件服务器的代理,并且外网要访问邮件服务器,必须通过该层代理(除非邮件服务器涉及端口也暴露在外网上)。在代理服务器上,我选用的是Nginx服务器,它拥有非常强大的反向代理功能,并且通过它能非常简单的实现多种协议的负载均衡。

实现流程

准备工作

因为资源有限,系统在部署时,没那么多主机,于是使用Docker模拟多台服务器进行交互,本次部署需要用到以下环境与工具:

  • Linux环境,我使用的发行版是Ubuntu 16.04
  • Docker,我使用的版本是18.03.1-ce
  • 已在Docker中创建好的邮件服务器镜像(后面我会发在基于Docker搭建邮件服务器的教程,敬请期待)

NFS服务器

那么,首先我们来进行NFS服务器的搭建。
先来编写Dockerfile吧:

# 提取镜像
FROM centos:6
# 更新源
RUN yum -y update
# 下载nfs服务器
RUN yum -y install nfs-utils rpcbind
# 创建共享目录
RUN mkdir -p /home/data
# 将共享目录添加到nfs中
RUN echo '/home/data  *(insecure,rw,sync,no_root_squash,no_all_squash,sync)' >> /etc/exports
# 因为nfs的端口号是不固定的,所以这里将nfs端口号改为固定的端口号
RUN echo -e "RQUOTAD_PORT=30001\nLOCKD_TCPPORT=30002\nLOCKD_UDPPORT=30002\nMOUNTD_PORT=30003\nSTATD_PORT=30004" >> /etc/sysconfig/nfs
# 拷贝启动脚本到镜像中
COPY pd.sh /opt/pd.sh
# 开启镜像便执行启动脚本
CMD ["sh","/opt/pd.sh","&"]

这里说明一下,这里为什么选用的是Centos 6而不是最新的Centos 7呢? 是因为docker中Centos 7在使用systemctl命令时,会报:

Failed to get D-Bus connection: Operation not permitted

这样的错误,它会给我们构建镜像带来麻烦,所以推荐大家以后在docker中选用Centos时,最好还是选择Centos 6的版本。启动脚本pd.sh的代码如下所示:

#!/bin/bash
service rpcbind start
service nfs start
service nfs restart
# 为了开启容器后不退出,在前台加一个死循环,保证进程一直存在
while [ 1 = 1 ]
do
  sleep 1;
done

编写好Dockerfile后,便可以进行镜像构建啦:

docker build -t nfs .

构建成功如下图所示:


构建nfs镜像

因为容器一般用作服务,是无状态的,最好不要用于存储数据,所以我们需要在宿主机上为容器创建一个数据存储目录:

mkdir -p /home/data
# 为目录开启所有权限
chmod 777 -R /home/data

接着使用nfs镜像创建容器:

docker run -dit --privileged -p 111:111 -p 30001:30001 -p 30002:30002 -p 30003:30003 -p 30004:30004  -v /home/data:/home/data --name=nfs-server nfs

上命令的含义是开启一个名为nfs-server的容器,将nfs-server的111,30001,30002,30003,30004端口映射到本地对应端口,并且将上一步创建的目录映射到nfs-server中。可以使用“docker ps -a”查看nfs-server是否开启成功:

nfs-server开启成功

容器开启后,先为宿主机安装nfs客户端:

apt-get -y install nfs-common

安装后,在宿主机创建目录用于挂载nfs服务器目录:

mkdir -p /home/email
# 为目录开启所有权限
chmod 777 -R /home/data

将nfs服务器目录挂载到宿主机目录:

# 查看nfs服务器已开放目录,其中ip为nfs-server的ip
# 虽然端口已经映射出来了,但是使用127.0.0.1还是连接不上,只能使用nfs-serve的容器ip
showmount -e 172.17.0.2
# 进行挂载
mount -t nfs 172.17.0.2:/home/data /home/email -o proto=tcp -o nolock

至此,完成了NFS服务器的部署。

Nginx服务器

因为需要使用的nginx服务器的stream模块,所以我们需要先从nginx官网上获取nginx的tar包进行编译,我选的是nginx-1.13.4.tar.gz,下载好后,我们进行编译安装:

# 编译需要的工具
sudo apt-get -y install gcc g++ libpcre3 libpcre3-dev  libssl-dev zlib1g-dev 
# 解压tar包
tar -zxvf nginx-1.13.4.tar.gz
# 该目录为编译安装的目录
mkdir nginx
cd nginx-1.13.4/
# 配置 --prefix=安装路径
./configure --prefix=../nginx --with-stream
# 编译
make
# 安装
make install
cd ../nginx 
ls

可以看到生成了如下目录


nginx目录

接下来,我们将nginx构建为docker镜像,编写Dockerfile:

FROM ubuntu:14.04
COPY nginx /opt/nginx
WORKDIR /opt/nginx
CMD ["sbin/nginx", "-g", "daemon off;"]

编写好Dockerfile后,便可以进行镜像构建啦:

docker build -t nginx .

为了方便配置修改与目录查看,需要将宿主机中nginx目录映射到nginx-email中,并且nginx-email的目地是为了反向代理邮件服务器,所以需要将nginx-email的25,110,143等邮件协议端口映射到宿主机对应端口中:

docker run -itd --name=nginx-email -p 25:25 -p 110:110 -p 143:143 -v /opt/nginx:/opt/nginx nginx

至此,完成了nginx服务器的部署。

整合NFS + 邮件服务器 + Nginx

首先,开启多个邮件服务容器email-server,因为是同一宿主机,所以在映射时需要修改其端口号,并且将宿主机挂载NFS的目录映射到email-server容器内,具体操作流程:

# 开启server-email-1
docker run -dit --name server-email-1 -p 1101:110 -p 251:25  -p 1431:143 -v /home/email:/home/vmail --link mysql email:2.0
# 开启server-email-2
docker run -dit --name server-email-2 -p 1102:110 -p 252:25  -p 1432:143 -v /home/email:/home/vmail --link mysql email:2.0
开启了多个邮件服务器

开启了邮件服务器后,我们便可以配置nginx反向代理了,在conf/nginx.conf文件最下方加入stream模块:

stream {
    upstream smtp {
        # weight代表权重,这里因为要负载均衡,所以都为1
        server 172.17.0.1:251 weight=1;
        server 172.17.0.1:252 weight=1;
    }
    upstream pop3 {
        server 172.17.0.1:1101 weight=1;
        server 172.17.0.1:1102 weight=1;
    }
    upstream imap {
        server 172.17.0.1:1431 weight=1;
        server 172.17.0.1:1432 weight=1;
    }
    server {
        listen 25;
        proxy_pass smtp;
    }
    server {
        listen 110;
        proxy_pass pop3;
    }
    server {
        listen 143;
        proxy_pass imap;
    }
}

保存后,启动nginx-email:

docker run -itd --name=nginx-email -p 25:25 -p 110:110 -p 143:143 -v /opt/nginx:/opt/nginx nginx

测试是否实现代理:

telnet 127.0.0.1 143
IMAP代理

测试是否实现负载均衡:

# 关闭其中一个邮件服务器
docker stop server-email-1
# 尝试链接IMAP服务
telnet 127.0.0.1 143
image.png

由此可见,已完成了邮件服务分布式部署与均衡负载。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,629评论 18 139
  • 分布式系统面临的第一个问题就是数据分布,即将数据均匀地分布到多个存储节点。另外,为了保证可靠性和可用性,需要将数据...
    olostin阅读 4,558评论 2 26
  • 开放源代码已经成为一些大型网站的基本原则。而在这些网站成长的过程中,一些优秀的实践经验和规则也出现在他们的结构中。...
    零一间阅读 1,009评论 0 4
  • 农夫播下了爱的种子 从此收获许多的爱 亲人的关爱 朋友的挚爱 孩子的喜爱 家长的厚爱 农夫播下了早起的种子 与时间...
    梁兰芳阅读 356评论 0 0
  • An enumeration is a list of related values that define a ...
    三十一_iOS阅读 560评论 0 0