0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Postfix/Dovecot 性能検証(POP3処理性能)

Last updated at Posted at 2022-11-10

環境

  • マシンA(自宅)
    • AMD Ryzen7 4800H(8core/16thread) 16GBメモリ
    • Windows 11 Home(ホストOS:VMware Workstation 16 Player): Thunderbird(POP3)
    • Red Hat Enterprise Linux release 8.4 (Ootpa)(ゲストOS):postfix/dovecot
    • ホスト4core/ゲスト4coreの割り当て。
  • マシンB(AWS)
    • t3.xlarge(4vCPU/16GBメモリ)
    • Red Hat Enterprise Linux release 8.6 (Ootpa):postfix/dovecot

検証手順

postfixの設定は本番を意識したものではなくなる早で検証開始する目的

#vi /etc/postfix/main.cf
#変更内容ポイント
myhostname = 環境の値を設定
inet_interfaces = all
home_mailbox = Maildir/

#最後に追加
message_size_limit = 0
mailbox_size_limit = 0

変更後再起動

# systemctl restart postfix

dovecotの設定は本番を意識したものではなくなる早で検証開始する目的

vi /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:~/Maildir

vi /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = no

vi /etc/dovecot/conf.d/10-ssl.conf
ssl = no

変更後再起動

# systemctl restart dovecot

メールデータの作成(添付ファイルでサイズ膨らませる)
※これをベースにサイズと件数のバリエーションをshell scriptで簡単に組める。

dd if=/dev/urandom of=/tmp/500m bs=1M count=500
echo "mail body" | mailx -a /tmp/500M -s 'test' test@localhost.localdomain

※注意:500MBのメールデータを意図しても実際のPOPサーバー内のファイルは708760764まで膨らむ。

参考shell script

#!/bin/bash

a=0
while [ "$a" -lt $1 ]
do
    a=$(expr $a + 1)
    echo "mail body" | mailx -a /tmp/1M -s 'test' test@xxx.yyy.zzz
done

※性能差(上記ddの結果)

  • 自宅マシンの性能
    • 524288000 bytes (524 MB, 500 MiB) copied, 9.20449 s, 57.0 MB/s
  • AWSの性能
    • 524288000 bytes (524 MB, 500 MiB) copied, 6.27526 s, 83.5 MB/s

※ネットワークレイテンシーの違い

  • 自宅VM内の論理通信

    • pingのavgが0.75msec
  • 自宅とパブリックAWS通信

    • pingのavgが7msec
    • 環境によっては二桁msecとなる場合もある。これが様々なクライアント、サーバーアプリに悪影響を与える。
  • ケース1
    thunderbirdで500MBデータをPOP3取得
    結果:8MB/s で1分数十秒程度
    CPU使用率はクライアント、サーバーともに使用率低。(1POPで1コア程度なのでCPU使い切るにはクライアント多重度をあげる必要あり。)
    結果は自宅内と自宅とAWS間で大差出ず。
    ※時間計測はWindowsのリソースモニタを目視し、Thunderbird固有処理(クライアント固有処理)ではなくPOP3通信が連続していると思われる期間を計測。

  • ケース2
    WinScpで500MBファイルの転送
    60MB/s 10sec 自宅内
    30MB/s 20sec 自宅とAWS間
    ※上記のPOPでの8MB/sがネットワークネックでないと判断できる。
    ※POPのほうがSCPよりもアプリケーションの処理コストが高い。
    ※レイテンシーに影響されやすいアプリケーション実装。(POP比較)

  • ケース3
    ※自宅とAWS間のみ
    thunderbird(500MB=1M*500 POP3)
    5MB/s で約2分ちょい。
    1MBファイルを500通のメールを取得

  • ケース4
    ※自宅とAWS間のみ
    thunderbird(500MB=2621448B*2000 POP3)
    3.x MB/s で約3分半。

  • ケース5
    POP3アプリケーション観点。アプリのオーバーヘッドをみるため(ノイズを省く)自宅内のみで比較
    50Kのメールを1000件受信するケース
    ①Thunerbird:3.1MB/sで23秒
    ②Javaフェッチのみ:20MB/sで4秒
    ③Java(シングルスレッドでシーケンシャルに処理し、メール情報をファイル出力):0.6MB/sで118秒
    ※Javaのサンプルソースは本ページの最後に記載。
    ※メールデータ分析処理のようなメールをバッチ処理するアプリケーションではアプリの実装によって性能が大きく異なる。

検証サマリ

環境 アプリケーション 処理 結果 備考
自宅内 WinSCP 500MBファイル転送 ネットワークスループット:60MB/s 実行時間:10sec
自宅-AWS WinSCP 500MBファイル転送 ネットワークスループット:30MB/s 実行時間:20sec WinSCPはネットワークレイテンシーに影響されやすい。
自宅内 Thunderbird 500MBファイルを添付したメールを1通POP3取得 8MB/s で1分数十秒程度
自宅-AWS Thunderbird 500MBファイルを添付したメールを1通POP3取得 8MB/s で1分数十秒程度 SCPのアプリコスト(プロトコルオーバーヘッド)が高い。
自宅-AWS Thunderbird 1MBファイルを添付したメールを500通POP3取得 5MB/s で2分超 メール数に応じてPOPプロトコルオーバーヘッドが大きくなる。
自宅-AWS Thunderbird 2621448Bファイルを添付したメールを2000通POP3取得 3MB/s で約3分半超。 メール数に応じてPOPプロトコルオーバーヘッドが大きくなる。
自宅-AWS Thunderbird 50KBファイルを添付したメールを1000通POP3取得 3.1MB/s で23秒。
自宅-AWS Java(フェッチのみ) 50KBファイルを添付したメールを1000通POP3取得 20MB/s で4秒。 ネットワークスループットMAXに近い処理
自宅-AWS Java(フェッチ+永続化) 50KBファイルを添付したメールを1000通POP3取得 0.6MB/s で118秒。 シングルスレッド、シーケンシャルな最も非効率な処理

総論

ネットワーク環境、アプリの実装、プロトコルの複雑度、対象データの特性によって処理性能やネットワーク負荷が大きく異なる。

今後

【チューニング余地ありそうなもの】
/etc/dovecot/conf.d/10-mail.conf

#Max number of mails to keep open and prefetch to memory. This only works with
#some mailbox formats and/or operating systems.
#mail_prefetch_count = 0

※大量のメールデータを取り扱うアプリケーションで効果ありそう。

/etc/dovecot/conf.d/20-pop3.conf

#Allow only one POP3 session to run simultaneously for the same user.
#pop3_lock_session = no

※いわゆるセッションの使いまわし。ネットワークレイテンシー高い環境下で効果ありそう。

参考

Java POP3アプリ(ググってコピペしてきたもの)。フェッチオンリーとしているのは実際のメールデータ処理をすべてコメントアウトしている。これがケース5の②に該当。コメントアウトを外すとケース5の③になる。
JavaMailがデータをネットワーク越しにもってきているのは確実だが、一時領域としてどう内部的に格納しているのかは未調査。

package sample;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;

import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeMultipart;
public class FetchOnly {


	public static void main(String[] args){
		long start = System.currentTimeMillis();
		Folder folder = null;
		try {
			Properties props = new Properties();
			props.put("mail.pop3.host", "192.168.47.128");
			props.put("mail.pop3.port", "110");
			Session session = Session.getDefaultInstance(props);
			Store store = session.getStore("pop3");
			store.connect("test", "test");
			folder = store.getFolder("INBOX");
			//folder.open(Folder.READ_ONLY);
			folder.open(Folder.READ_WRITE);

			// メッセージ一覧を取得
			Message[] arrayMessages = folder.getMessages();
			for (int lc = 0; lc < arrayMessages.length; lc++) {

				// メッセージの取得
				Message message = arrayMessages[lc];

				// 件名の取得と表示
				String subject = message.getSubject();
				//System.out.print("件名:" + subject + "\r\n");

				// 受信日時を表示
				String sentDate = message.getSentDate().toString();
				//System.out.print("受信日時:" + sentDate + "\r\n");

				// 本文の取得と表示
				MimeMultipart mltp = (MimeMultipart)message.getContent();
				BodyPart body1 = mltp.getBodyPart(0);
				//System.out.print("本文:" + body1.getContent().toString() + "\r\n");

				// 1:添付ファイルボディを取得
				BodyPart body2 = mltp.getBodyPart(1);
				String fileName = body2.getFileName();
				//System.out.print("添付ファイル名:" + fileName + "\r\n");

				// 2:添付ファイルのストリームを取得
				InputStream ins = body2.getInputStream();

				// 3:出力ストリームに出力しながらファイルを保存する
				OutputStream outs = new FileOutputStream("C:\\Users\\m2tor\\Desktop\\save.txt"); 
//				int out;
//				while ((out = ins.read()) != -1) {
//					outs.write(out);
//				}

				ins.close();
				outs.close();

				message.setFlags(new Flags(Flags.Flag.DELETED), true); // 対象メールをメールサーバから削除する.

			}
			folder.close(true);
			System.out.println("メッセージ処理件数:" + arrayMessages.length);
			long end = System.currentTimeMillis();
			System.out.println("処理時間(秒):" + (end - start)/1000);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(folder.isOpen()) {
					folder.close(false);	
				}

			} catch (MessagingException e) {
				// TODO 自動生成された catch ブロック
				e.printStackTrace();
			}
		}

	}
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?