Сразу оговорюсь что поставленную задачу можно решить несколькими способами. Этот один из возможных.
Статья рассчитана на тех, кто знает как настраиваются и работают Exim и Dovecot, и в ней я не будут останавливаться на базовых настройках этих сервисов.

Надеюсь что кто-то, прочитав заметку, получит необходимые знания или идеи для воплощения своего решения.

Задача построить отказоустойчивый сервис, с хранением почты на серверах, с доступом по IMAP.
Кластер будет обслуживать компанию с примерно с 60 филиалами, каждый из которых имеет свой домен 3-го уровня.

Главная задача сервиса, беспрерывный доступ к почте. Поэтому для хранилища будем использовать два географически разнесенных сервера, с синхронизацией почтовых каталогов.
Оба сервера будут активными, это значит что мы будем распределять нагрузку между нодами. Часть доменов будет обслуживать одна нода, часть доменов другая. В случае выхода из строя одной из нод, клиенты переключаются на другую.
В качестве фронтенда для распределения нагрузки маршрутизации клиентов будем использовать Nginx с модулем mail. Для приема почты, будем использовать два smtp сервера.

Схема:


STORAGE: Хранилище почтовых ящиков. Состоит из двух нод.
Каждая нода выделеный сервер с 2х4Тб HDD, расположенные на разных хостингах
DNS: storage-01.domain.ru и storage-02.domain.ru
ОС: FreeBSD,
ПО: Dovecot, Exim, Postgresql и Nginx

SMTP: Сервера обрабатывающие SMTP трафик, две ноды.
Виртуальные серверы расположенные на разных хостингах,
DNS: smtp-01.domain.ru и smtp-02.domain.ru
ОС: FreeBSD,
ПО: Exim, Postgresql

PROXY: Прокси сервер для пользовательского доступа к сервису IMAP, POP3, SMTP.
Виртуальный сервер. Единственное не продублированное звено в кластере, но в виду своей простоты поднимается в течении нескольких минут из снапшота.
DNS: mail.domain.ru
ОС: FreeBSD,
ПО: Nginx

STORAGE.
В качестве MDA был выбран Dovecot, поскольку он из коробки умеет кластер. Для хранения почты, был выбран формат Maildir, т.к. сразу захотелось дедупликацию, но об этом ниже.
Датасторы принимают почту только от своих smtp серверов и PROXY. Почту в мир отправляют сами, минуя smtp серверы. Можно их совсем спрятать, и исходящую почту отправлять через smtp ноды.
Путь в файловой системе к ящикам /usr/mail/домен 2-го уровня/домен 3-го уровня/ящик/
В авторизации в качестве логина используется полный ящик mail@ldomain.mdomain.ru

БД:
Описание таблиц:
mail таблица для хранения почтовых ящиков
  • id
  • mailbox — название почтового ящика
  • password — пароль в MD5
  • ldomain_id — id домена 3-го уровня из таблицы ldomain
  • mdomain_id — id домена 2-го уровня из таблицы mdomain
  • active — статус почтового ящика. вкл/выкл


ldomain таблица для описания доменов 3-го уровня
  • id
  • domain — название домена
  • active — статус домена. вкл/выкл

mdomain таблица для описания доменов 2-го уровня
  • id
  • domain — название домена
  • active — статус домена. вкл/выкл

maps таблица маршрутизации
  • id
  • ldomain_id — id домена 3-го уровня из таблицы ldomain
  • mdomain_id — id домена 2-го уровня из таблицы mdomain
  • storage1 — основоной сторадж
  • storage2 — резервный сторадж (пока не используется)

Как уже писал выше, нагрузку (почтовые домены) я распределяю по двум storage, в таблице maps определяет, на каком из storage находится домен 3-го уровня.

mail=# select * from maps limit 3;
 id | ldomain_id | mdomain_id |      storage1      |   storage2    
----+------------+------------+--------------------+---------------
 56 |         56 |          2 | storage-01.domain.ru | storage-02.domain.ru
 57 |         57 |          2 | storage-02.domain.ru | storage-01.domain.ru
 58 |         58 |          2 | storage-01.domain.ru | storage-02.domain.ru

(3 строк)

Опираясь на эту таблицу Exm-ы стораджей и smtp нод будут определять куда слать письма. А Nginx, к какому стораджу подключать пользователей.

Cоздание БД и таблиц:
 psql -Upgsql template1
 ctreate database mail;
 \q

CREATE TABLE mail (
	"id" BIGSERIAL PRIMARY KEY,
	"mailbox" CHARACTER VARYING(32) not null,
	"password" CHARACTER VARYING(128),
	"ldomain_id" int NOT NULL,	 
	"mdomain_id" int NOT NULL,
	active BOOLEAN DEFAULT TRUE NOT NULL,
	CONSTRAINT "mail_ldomain_id_check" CHECK (("ldomain_id" > 0))
);

CREATE TABLE "ldomain" (
    "id" BIGSERIAL PRIMARY KEY,
    "domain" CHARACTER VARYING(32) NOT NULL,
    "active" BOOLEAN DEFAULT TRUE NOT NULL,
    CONSTRAINT ldomain_k UNIQUE (domain)
);

CREATE TABLE "mdomain" (
    "id" BIGSERIAL PRIMARY KEY,
    "domain" CHARACTER VARYING(32) NOT NULL,
    "active" BOOLEAN DEFAULT TRUE NOT NULL,
    CONSTRAINT mdomain_k UNIQUE (domain)
);

CREATE TABLE "maps" (
    "id" SERIAL PRIMARY KEY,
    "ldomain_id"  int NOT NULL,
    "mdomain_id"  int NOT NULL,
    "storage1" CHARACTER VARYING(32) NOT NULL,
    "storage2" CHARACTER VARYING(32) NOT NULL,
    CONSTRAINT maps_ldomain_k UNIQUE (ldomain_id)
);


Dovecot
Dovecot выполняет функцию MDA. Я оставлю за рамками этой статьи базовую настройку Dovecot, остановлюсь только на тех моментах, которые важны для связки его с DB и MTA
/usr/local/etc/dovecot/dovecot.conf
protocols = imap pop3 lmtp # для связки с Exim буду использовать LMTP

/usr/local/etc/dovecot/dovecot-sql.conf.ext
driver = pgsql
connect = host=localhost dbname=mail user=mail password=password
default_pass_scheme = MD5

iterate_query =     SELECT mail.mailbox || '@' || ldomain.domain || '.' || mdomain.domain AS user 	FROM mail 	    INNER JOIN mdomain ON ( mail.mdomain_id = mdomain.id ) 	    INNER JOIN ldomain ON ( mail.ldomain_id = ldomain.id ) 

password_query =     SELECT mail.mailbox || '@' || ldomain.domain || '.' || mdomain.domain AS mail, mail.password 	FROM mail 	    INNER JOIN mdomain ON ( mail.mdomain_id = mdomain.id ) 	    INNER JOIN ldomain ON ( mail.ldomain_id = ldomain.id ) 		WHERE mailbox = '%n' AND 		    ldomain.domain || '.' || mdomain.domain = '%d' AND 		    mail.active = true AND 		    ldomain.active = 'true'

user_query =     SELECT '/usr/mail/' || ldomain.domain || '.' || mdomain.domain || '/' || mail.mailbox  AS home  	FROM mail 	    INNER JOIN ldomain ON ( mail.ldomain_id = ldomain.id ) 	    INNER JOIN mdomain ON ( mail.mdomain_id = mdomain.id ) 		WHERE mail.mailbox = '%n' AND 			ldomain.domain || '.' || mdomain.domain = '%d'

/usr/local/etc/dovecot/conf.d/10-auth.conf
auth_username_format = %Lu # формат для авторизации mail@ldomain.mdomain.ru
!include auth-sql.conf.ext

/usr/local/etc/dovecot/conf.d/10-mail.conf
mail_location =  maildir:/usr/mail/%d/%n/Maildir #Путь в файловой системе к ящикам /usr/mail/домен 2-го уровня/домен 3-го уровня/ящик/


Синхронизация хранилищ
Изначально, я настроил синхронизацию средствами самого Dovecot (dsync) но, в процессе эксплуатации вылезла очень неприятная проблема. Как оказалось, проблема была связана с типом хранилища Maildir. Dsync стал сбоить, плодить копии писем отжирая свободное место на дисках. К тому моменту я уже не мог перевести все почтовые ящики на dbox (фирменный формат Dovecot) поэтому пришлось отказаться от синхронизации посредством dsync. В целом же, к этому механизму других претензий не было.
Пришлось обратиться к rsync, нехитрым скриптом он берет из базы те домены которые обслуживаются сервером на котором он запускается и синхронизирует их каталоги на второй сервер. Соответсвенно, на втором сервере такой же скрипт гонит на первый свои каталоги. Конечно этот механизм менее надежен так как rsync запускается по расписанию, есть окно между запусками в котором если сервер выйдет из строя мы потеряем письма.

скрипт запускается с двумя параметрами — имя_локального_сервера имя_удаленного_сервера
#mailrsync.pl storage-01.domain.ru storage-02.domain.ru 

скрипт синхронизации:
#!/usr/local/bin/perl
use DBI;
use threads;
use Net::Nslookup;
use Sys::Hostname;

@host = split('\.',hostname); 
$dbn="mail";
$dbuser="mail";
$dbpass = "password"
$curdata=`date +%Y-%m`; chop $curdata;
$conn=DBI->connect("DBI:Pg:dbname=$dbn;host=localhost","$dbuser","$dbpass") or die "Cannot connect";
($localhostname,$remotehost)=@ARGV;
$mail_dir = "/usr/mail/";

sub domains {
    $q = "SELECT ldomain.domain,mdomain.domain,maps.storage1 
                                 FROM mail 
                                     INNER JOIN ldomain on (mail.ldomain_id = ldomain.id) 
                                     INNER JOIN mdomain on (mail.mdomain_id = mdomain.id) 
                                     INNER JOIN maps on (maps.ldomain_id=ldomain.id) 
                                        WHERE maps.storage1='".$localhostname."'
                                             AND mail.mailbox ='dir'";
   $domain = $conn->prepare($q)
         or die "Can't prepare statement: $DBI::errstr";
    $domain->execute();
    while (  my @domain = $domain->fetchrow_array ) {
                @domains=(@domains,$domain[0].".".$domain[1]);
           }
    print "count of domains: ".($#domains + 1)."\n";
    $dt = 2; # количество доменов в одном треде
    $count = ($#domains / $dt );
    print "count: ".$count."\n";
    $i1 = 0;
     for ($i2 = 0; $i2< $count; $i2++){
            if ($dt > $#domains  ){$dt = $#domains ;}
             print $dt."\n";
            print "loop: ".$i2."\n";
        
            foreach $item (@domains[$i1..$m]){
               print "in \@domains: ".$mail_dir.$item."\n";
               @stack = (@stack,$mail_dir.$item."/");
            }
            push @threads,threads->create(\&sync,\@stack);
           $i1 = $dt+1;
           $dt = $dt + 2;
           @stack=();
      }
}

sub sync {
    print "sync\n";
   foreach $target (@stack){
         system(`/usr/local/bin/rsync -H --delete-during -azz -e "/usr/bin/ssh -i /root/.ssh/dovecot_dsa" $target vmail\@$remotehost:$target`);
         print $target."\n";
    }

}

domains();
foreach $thread (@threads) {
                 $thread->join();
           }


На этом с Dovecot, все.

Exim
определяем локальные домены, исходя из записей в таблице maps, для того чтобы Exim «знал» свои домены.
domainlist LOCAL_DOMAINS =       ${lookup pgsql{    	    SELECT ldomain.domain || '.' || mdomain.domain AS domainname 		FROM ldomain, mdomain,maps 		    WHERE ldomain.domain || '.' || mdomain.domain = LOWER('${quote_pgsql:$domain}') 		        AND ldomain.active = 'true' 		        AND  maps.storage1 = 'storage-01.domain.ru' 	                AND maps.ldomain_id = ldomain.id}}


в hostlist relay_from_hosts указываю адреса smtp нод и прокси, от них я принимаю почту без авторизации (клиенты авторизуются на прокси).
 relay_from_hosts = localhost : smtp01.domain.ru : smtp02.domain.ru : mail.domain.ru 

Входящую почту отдаю через LMPT Dovecot-у. В остальном все стандартно. Запросы к БД для поиска ящиков и паролей такие же как в листинге для Dovecot-a

SMTP ноды
БД, такая же как на стораджах, за исключением того, что в таблице mail отсутствует поле password, т.к. пользователи не подключаются к этим серверам. smtp ноды обрабатывают исключительно входящий из мира трафик. По базе проверяют существует ли ящик, пропуская дальше письма только для существующих ящиков.

Exim 
Стандартный конфиг, за исключением запроса для определения маршрута
ROUTE_LIST =  "${lookup pgsql{                   SELECT  COALESCE(storage1,'') || ' : ' || COALESCE(storage2,'') 		        FROM (                                 SELECT storage1,storage2                                     FROM maps                                         INNER JOIN ldomain ON ( maps.ldomain_id = ldomain.id ) 		                        INNER JOIN mdomain ON ( maps.mdomain_id = mdomain.id ) 			                    WHERE ldomain.domain || '.' || mdomain.domain =  '${quote_pgsql:$domain}' 	                      UNION ALL 	                        SELECT storage1,storage2 	                            FROM co_maps 	                                INNER JOIN co_domain ON ( co_maps.domain_id = co_domain.id ) 	                                    WHERE co_domain.domain  =  '${quote_pgsql:$domain}') AS foo}}"


SQL запрос вытягивает имя стораджа для получателя, затем адрес стораджа указывается в роутере, в директиве route_list. Таким образом письмо отправляется на тот сторадж где находится активный домен для этого ящика.
begin routers

DATASTORE:
    driver = manualroute
    domains = DOMAINS
    transport = remote_smtp
    condition = MAILS
    route_list = * ROUTE_LIST
    no_more

Запросы к БД для поиска ящиков и паролей такие же как в листинге для Dovecot.

PROXY
В качестве прокси может выступать тот же Dovecot, но я выбрал Nginx, он показался проще и понятней в этом плане. Стояла одна задача, каким то образом указывать nginx-у куда отправлять пользователя.

nginx.conf на PROXY
cat /usr/local/etc/nginx/nginx.conf
worker_processes  1;
worker_rlimit_nofile 8192;
pid /var/run/nginx.pid;
error_log  /var/log/nginx-error.log debug;
error_log  /var/log/nginx-error.log  notice;
error_log  /var/log/nginx-error.log  info;

events {
  worker_connections  8192;
  multi_accept on;
  use kqueue;
}

mail {
    ssl_certificate /usr/local/etc/ssl/proxy.crt;
    ssl_certificate_key /usr/local/etc/ssl/proxy.key;
    ssl_session_timeout 5m;
    xclient off;

    auth_http  storage-01.domain.ru:8185/auth;

    pop3_capabilities	"LAST" "TOP" "USER" "PIPELINING" "UIDL" "RESP-CODES" "EXPIRE" "IMPLEMENTATION";
    imap_capabilities	"IMAP4" "IMAP4rev1" "UIDPLUS" "IDLE" "LITERAL+" "QUOTA" "LIST-EXTENDED";
    smtp_capabilities	"SIZE 52428800" "8BITMIME" "PIPELINING" "STARTTLS" "HELP";

    server {
          smtp_auth	login plain;
          listen 25;
          protocol smtp;
          proxy on;
          starttls on;
    }
    
    server {
          smtp_auth	login plain;
          listen 587;
          protocol smtp;
          proxy on;
          starttls on;
    }
    
    server {
          listen 110;
          protocol pop3;
          proxy on;
          starttls on;
    }
    server {
          listen 995;
          protocol pop3;
          proxy on;
          starttls on;
    }
    
    server {
          listen 143;
          protocol imap;
          proxy on;
          starttls on;
    }
    server {
          listen 993;
          protocol imap;
          proxy on;
          starttls on;
    }
}

Обратите внимание на директиву auth_http storage-01.domain.ru:8185/auth;
На сторадже(на обоих!) тоже работает Nginx, но в режими web сервера, с одной лишь целью — обрабатывать запрос storage-01.domain.ru:8185/auth
Этот запрос в случае удачной авторизации клиента возвращает статус авторизации, имя сторажда и порт сервиса
"Auth-Status", "OK";
"Auth-Server", "storage-01.domain.ru";
"Auth-Port", "143";

После чего, nginx на PROXY отправляет клиента на сторадж который вернулся в ответе.
Можно было конечно исключить nginx на сторадже, но для этого пришлось бы и на PROXY держать базу с пользователями. В общем могли быть варианты.

Ниже конфиг Nginx на сторадже, с модулем на perl для реализации вышеописанного.
worker_processes  4;
worker_rlimit_nofile 8192;
error_log  /var/log/nginx-error.log  info;

events {
  worker_connections  8192;
  multi_accept on;
}
http {
    perl_modules  perl/lib;
    perl_require  mailauth.pm;
    perl_require  Digest.pm;    
    access_log off;

    server {
	listen 8185;
	ssl_certificate /usr/local/etc/ssl/storage-01.crt;
	ssl_certificate_key /usr/local/etc/ssl/storage-01.key;
	ssl_session_timeout 5m;

	location /auth {
	    perl  mailauth::handler;
	    proxy_set_header X-Real-IP $remote_addr;
	}
    }
}


модуль mailauth.pm
package mailauth;
use nginx;
use DBI;
use Net::Nslookup;
use Digest::MD5 qw(md5_hex);

$pg_user = "mail";
$pg_pass = "password";
$passhost = "localhost";
$mapshost = "localhost";

our $auth_ok;
$protocol_ports->{'pop3'}=110;
$protocol_ports->{'imap'}=143;
$protocol_ports->{'smtp'}=25;
$protocol_ports->{'smtpssl'}=465;
 
sub handler {
     $r = shift;
         $Passdbh=DBI->connect("DBI:Pg:dbname=mail;host=$passhost","$pg_user","$pg_pass");
        if (!$Passdbh) {
             $r->header_out("Auth-Status", "OK") ;
             $r->header_out("Auth-Server", '0.0.0.0');
             $r->header_out("Auth-Port", $protocol_ports->{$r->header_in("Auth-Protocol")});
             $r->send_http_header("text/html"); 
             return OK;
             exit;
         };

         $Mapsdbh=DBI->connect("DBI:Pg:dbname=mail;host=$mapshost","$pg_user","$pg_pass"); 
         $auth_ok=0;
         $mailbox = $r->header_in("Auth-User");
         our $get_pass_from_db=$Passdbh->prepare("SELECT password FROM mail 
                                                INNER JOIN ldomain ON ( mail.ldomain_id = ldomain.id ) 
                                                INNER JOIN mdomain ON ( mail.mdomain_id = mdomain.id ) 
                                                WHERE mail.mailbox || '\@' || ldomain.domain || '.' || mdomain.domain = ? ");

    $get_pass_from_db->execute($mailbox);
    @row=$get_pass_from_db->fetchrow_array();
    $passfromDB=@row[0];

    $md5passFromConnect = md5_hex($r->header_in("Auth-Pass"));

    if ( $passfromDB eq $md5passFromConnect ){
            $auth_ok=1;
    }
    if ($auth_ok==1){
          @domain = split('\@',$mailbox);
          $get_server_from_maps = $Mapsdbh->prepare(
                           "SELECT storage1  FROM maps
                                  INNER JOIN ldomain ON ( maps.ldomain_id = ldomain.id )                                   INNER JOIN mdomain ON ( maps.mdomain_id = mdomain.id )                                        WHERE ldomain.domain || '.' || mdomain.domain = ? "
           );

        $get_server_from_maps->execute(@domain[1]);
        @row=$get_server_from_maps->fetchrow_array();
        $server_from_maps = nslookup(host => $row[0], type => "A");
        $r->header_out("Auth-Status", "OK") ;
        $r->header_out("Auth-Server", $server_from_maps);
        $r->header_out("Auth-Port", $protocol_ports->{$r->header_in("Auth-Protocol")});
    } else {
        $r->header_out("mail:", $r->header_in("Auth-User"));
        $r->header_out("Auth-Status", "Invalid login or password") ;
    }

  $r->send_http_header("text/html");

  return OK;
}

sub db_fail {
    $r->header_out("Auth-Status", "OK") ;
    $r->header_out("Auth-Server", '127.0.0.1');
    $r->send_http_header("text/html");
}

1;
__END__


Настройка балансировки, и переключение на резервную ноду
Сейчас переключение на резервную ноду происходит в ручном режиме. Просто в таблице maps меняется значение в поле storage1. Т.К. все сервера увешены мониторингом этого пока было достаточно.

ЗАКЛЮЧЕНИЕ
Кластер работает уже 3 года. За это время пережил несколько падений одной из нод ( в результате эта нода переехала в другой ДЦ).

Кому-то может показатся эта конструкция сложной, запутанной и «велосипедом». Но хочу сделать акцент на том, что архитектура данного решения исходила из решения использовать дешевое, «ненадежное» железо. В результате имеем надежный сервис с минимальной стоимостью аренды серверов.

Возможно заметка получилась не достаточно понятной, и я не отобразил какие то важные детали. В комментариях, если будут, буду дополнять.

ПС. Статья получилась длинной, поэтому про дедупликацию и еще одном, не упомянутом здесь сервисе управления этим кластером расскажу в следующей заметке, если это вызовет интерес.

Спасибо за внимание!
Поделиться с друзьями
-->

Комментарии (15)


  1. hexman
    22.03.2017 10:35

    Всё время мучал вопрос, ответ на который Вы дали только в самом конце :)
    «переключение на резервную ноду» -> " Просто в таблице maps меняется значение в поле storage1"
    Как то много баз у Вас. Но на это можно взглянуть и со стороны отказоустойчивости. Быть может правильнее было б 2е ноды, с резервированием под Postgresql отдать? Так кончено дороже наверное, но архитектурно, как по мне правильнее. Но могу ошибаться. А вообще если настроить реплики и между Вашми 4мя Postgresql, то так и без 2х дополнительных нод выйдет наддёжнее. К примеру на SMTP, Postgresql друг друга подхватывают, и на Storage так же. Ну это как вариант, что первое в голову пришло, или я не внимательно прочёл, и у Вас так и есть?
    Что касается продолжения статьи, то разумеется пишите. Любопытно.


    1. borisovEvg
      22.03.2017 11:24

      Бд на SMTP нодах нужны для того чтобы определить «свои» домены и отсеивать письма на несуществующие ящики. Можно конечно было бы подключаться к БД стораджей и от туда брать нужную информацию, но я подумал, что будет в случае если оба стораджа будут не доступны? в моем случае вся входящая почта будет скапливаться на SMTP нодах. Решил что так нормально. Синхронизации БД нет. Для себя решил что это излишнее, тк все манипуляции с добавлением, удалением, модификацией ящиков и доменов осуществляется с сервиса управления, который непосредственно подключается ко всем БД и модифицирует каждую из них. Мне показалось это достаточно.


  1. MagicEx
    22.03.2017 11:23
    +1

    С dsync такие же проблемы возникли после 2.2.16 версии.
    Используем его только в качестве hot backup, вторая нода не принимает юзеров. После 2.2.16 начались дубли писем. Опытным путем выяснили, что происходит это, когда на клиенте настроены фильтра, переносящие письма из Инбокса в другие папки. Если они успевают отработать достаточно быстро, то возникают дубли при репликации.
    Решили это отключением синхронизации со вторичной ноды на первичную (ранее было active-active).
    Полного решения проблемы не нашли :(
    Про дедупликацию очень интересно, пишите.


  1. a_tarsov
    22.03.2017 12:56

    Интерес есть, да ещё какой!
    Именно сейчас, готовимся к подобному действу.
    Пишите продолжение! Мы обойдем ваши грабли и будем искать только свои))


  1. casuss
    22.03.2017 13:35
    +1

    Вместо

    dsync
    — lsyncd не пробовали для синхронизации стораджей?


    1. vc43
      22.03.2017 22:06

      На FreeBSD его вроде нет, про аналоги не слышал. Если бы не распределение нагрузки, то для обычного «тёплого» бекапа хватило бы синхронизации через снапшоты zfs с последующим ручным переключением на резервный сервер.


  1. borisovEvg
    22.03.2017 13:43

    Интересная штука, не знал о таком, нужно попробовать! Спасибо за наводку


  1. zystem
    22.03.2017 21:52

    посмотрите еще на
    http://isync.sourceforge.net


  1. vc43
    22.03.2017 21:53

    На 1ТБ писем rsync будет работать минут 15, проверено.


    1. vc43
      22.03.2017 22:10

      Так же просьба уточнить насчет pop3, он корректно отрабатывает у клиентов при переключении на резервный сервер?


      1. borisovEvg
        22.03.2017 22:15

        pop3 клиентов ничтожное количество. А что с ними может быть не так? они же не держат сессию, подключаются периодически, забирают что есть и отключаются. Но могу специально попробовать, скажите только что воспроизводить, переключение в момент закачки клиентом большого письма?


        1. vc43
          23.03.2017 08:22

          Пришлось однажды восстановить почту dovecot 1.2 из бекапа. Бекап делался rsync и восстанавливался тоже через rsync. После восстановления клиенты, которые настроены на pop3, заново приняли все письма (стоял срок хранения писем на сервере 30 дней). То есть интересна ситуация: клиент1 получал почту с сервера1, потом сервер1 отключили и клиент1 стал получать почту с сервера2.


          1. borisovEvg
            23.03.2017 08:52

            такого не произойдет, если идет постоянная синхронизация. У вас там Maildir был? У него все просто. Видимо у вас в архиве эти письма были в каталоге new.a


    1. borisovEvg
      22.03.2017 22:18

      Чтобы полностью забить канал между нодами в 100мб/с приходится запускать rsync в несколько потоков. Вообще к нему вопросов никаких нет, отрабатывает всегда четко! Единственный минус, о чем писал в заметке, это окно между выполнениями.


  1. brestows
    22.03.2017 23:44

    Я сейчас что-то подобное реализуются, только PROXY у меня совмещен с web клиентом, и данные по пользователям беру из базы web клиента, это требует первого входа на новый адрес через web, но это и так требуется, что бы пользователь сменил одноразовый пароль и получить повареную книгу компании. Ваша схема интересная, спасибо, с удовольствием почитаю продолжения.