Zimbra Performans Optimizasyonu ve Kaynak Yönetimi

Üretim ortamında Zimbra yönetiyorsanız, er ya da geç performans sorunlarıyla yüz yüze gelirsiniz. 500 kullanıcılı bir sistemde “neden bu kadar yavaş?” sorusunu yanıtlamak için geceleri terminal başında oturmak, bu işin kaçınılmaz bir parçası. Bu yazıda Zimbra’yı gerçekten optimize etmek için uyguladığım yöntemleri, JVM ayarlarından MySQL ince ayarlarına, Postfix kuyruğundan disk I/O yönetimine kadar paylaşacağım.

Neden Zimbra Yavaşlar?

Zimbra aslında birçok bileşenin bir arada çalıştığı karmaşık bir yapı. Jetty web sunucusu, OpenLDAP, MySQL (veya MariaDB), Postfix, Amavis, ClamAV, memcached ve daha fazlası. Bu bileşenlerden herhangi biri darboğaz oluşturduğunda tüm sistem yavaşlar.

Tipik sorun kaynaklarına bakacak olursak:

  • JVM heap yetersizliği: mailboxd servisi varsayılan olarak düşük memory ile başlar
  • MySQL buffer pool boyutu: varsayılan değerler küçük sistemler için ayarlanmış
  • Amavis iş parçacığı sayısı: varsayılan 2 thread çoğu kurulum için yetersiz
  • Postfix kuyruk problemi: spam burst’leri sırasında kuyruk patlar
  • Disk I/O: özellikle spinning disk kullanan sistemlerde lucene index operasyonları katil olur

Bunları tek tek ele alalım.

JVM Heap ve mailboxd Optimizasyonu

Zimbra’nın kalbi mailboxd’dur ve Java üzerinde çalışır. JVM ayarları yanlışsa diğer her şeyi düzeltin yine de olmaz.

Mevcut JVM ayarlarınızı görmek için:

su - zimbra
zmlocalconfig -e mailboxd_java_heap_size
zmlocalconfig mailboxd_java_options

Üretim sisteminde önerdiğim ayarlar 8GB RAM’li bir sunucu için şöyle:

su - zimbra
zmlocalconfig -e mailboxd_java_heap_size=4096
zmlocalconfig -e mailboxd_java_options="-server -Dhttps.protocols=TLSv1.2,TLSv1.3 
  -Djava.awt.headless=true 
  -XX:+UseG1GC 
  -XX:MaxGCPauseMillis=200 
  -XX:+ParallelRefProcEnabled 
  -XX:+DisableExplicitGC 
  -verbose:gc 
  -XX:+PrintGCDetails 
  -XX:+PrintGCDateStamps 
  -Xloggc:/opt/zimbra/log/gc.log"

Burada dikkat edilmesi gereken noktalar:

  • UseG1GC: Java 8 ve üzeri için Garbage First collector, büyük heap’lerde CMS’den çok daha iyi
  • MaxGCPauseMillis=200: GC pause süresini 200ms ile sınırla, daha agresif yapabilirsiniz ama dikkatli olun
  • ParallelRefProcEnabled: referans işlemesini paralel yap, GC süresini ciddi ölçüde kısaltır
  • DisableExplicitGC: kodun System.gc() çağrılarını engeller, RMI gibi şeyler bunu kötüye kullanır

Değişikliği uygulamak için mailboxd’u yeniden başlatmak gerekir:

su - zimbra
zmcontrol stop
zmcontrol start

GC loglarını izlemek için şunu kullanabilirsiniz:

tail -f /opt/zimbra/log/gc.log | grep -E "GC pause|heap"

Eğer GC loglarında sık sık Full GC görüyorsanız heap’i büyütün. Eğer young generation GC’leri çok sıklıkla oluyorsa -XX:NewRatio değerini ayarlamayı düşünün.

MySQL/MariaDB Optimizasyonu

Zimbra’nın veritabanı katmanı genellikle gözardı edilir ama büyük kurulumlarda asıl darboğaz buradadır. Önce mevcut durumu anlayalım:

su - zimbra
mysql -u zimbra -p$(zmlocalconfig -s zimbra_mysql_password) zimbra 
  -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool%';"

Bu çıktıda Innodb_buffer_pool_reads yüksekse disk’ten okuma yapıyorsunuz demektir, buffer pool yetersiz.

Zimbra’nın MySQL konfigürasyon dosyası /opt/zimbra/conf/my.cnf üzerinden yönetilir ama doğrudan düzenlemek yerine local override kullanmak daha güvenli:

cat > /opt/zimbra/conf/my.cnf.custom << 'EOF'
[mysqld]
# InnoDB Buffer Pool - toplam RAM'in %40-50'si
innodb_buffer_pool_size = 3G
innodb_buffer_pool_instances = 4

# Log dosyası boyutları
innodb_log_file_size = 512M
innodb_log_buffer_size = 64M

# Flush davranışı - SSD için 2, spinning disk için 1
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT

# Bağlantı ve thread ayarları
max_connections = 200
thread_cache_size = 16
table_open_cache = 2048

# Query cache (MySQL 5.7 ve altı için)
query_cache_size = 0
query_cache_type = 0

# Slow query log - sorun tespiti için açık tutun
slow_query_log = 1
slow_query_log_file = /opt/zimbra/log/mysql-slow.log
long_query_time = 2
EOF

Önemli bir not: innodb_log_file_size değiştirirken önce MySQL’i durdurmanız ve eski log dosyalarını silmeniz gerekir, aksi takdirde başlatma başarısız olur.

su - zimbra
mysql.server stop
rm -f /opt/zimbra/db/data/ib_logfile*
mysql.server start

Postfix Kuyruk ve SMTP Optimizasyonu

Yoğun saatlerde Postfix kuyruğu şişebilir. Bu durum hem gecikmelere hem de sistem kaynaklarının boşa harcanmasına neden olur. Mevcut kuyruk durumunu görmek için:

su - zimbra
postqueue -p | tail -n 1
mailq | grep -c "^[A-F0-9]"

Postfix performans ayarları için /opt/zimbra/conf/postfix_main.cf dosyasına eklemeler yapabilirsiniz:

# /opt/zimbra/conf/postfix_main.cf.local oluşturun
cat >> /opt/zimbra/conf/postfix_main.cf << 'EOF'

# Eş zamanlı teslimat limitleri
default_process_limit = 100
smtp_destination_concurrency_limit = 20
smtp_destination_rate_delay = 0

# Kuyruk yönetimi
maximal_queue_lifetime = 5d
bounce_queue_lifetime = 1d
qmgr_message_active_limit = 20000
qmgr_message_recipient_limit = 20000

# SMTP bağlantı önbellekleme
smtp_connection_cache_on_demand = yes
smtp_connection_cache_destinations =
smtp_connection_reuse_time_limit = 300s

# Header boyutu limitleri
header_size_limit = 4096000
message_size_limit = 52428800
EOF

su - zimbra
postfix reload

Kuyrukta takılı kalmış mesajları yeniden denemek için:

su - zimbra
postsuper -r ALL
postqueue -f

Amavis ve ClamAV Ayarları

Spam ve antivirüs taraması CPU açısından en pahalı operasyonlardan biridir. Amavis worker sayısını optimize etmezseniz yoğun dönemlerde kuyruk birikir.

# Mevcut Amavis worker sayısını kontrol et
grep -E "max_servers|max_children" /opt/zimbra/conf/amavisd.conf

Amavis konfigürasyonunu güncellemek için:

su - zimbra
zmlocalconfig -e zimbraAmavisMaxServers=10

Bu değer CPU çekirdek sayısının 2 katına kadar çıkabilir. 8 çekirdekli bir sistemde 10-16 arası makul bir değer.

ClamAV bellek kullanımını optimize etmek için:

cat > /opt/zimbra/conf/clamd.conf.custom << 'EOF'
# Bellek optimizasyonu
MaxScanSize 150M
MaxFileSize 100M
MaxRecursion 10
MaxFiles 15000
StreamMaxLength 100M

# Performans
ScanArchive yes
ArchiveBlockEncrypted no
PhishingSignatures yes
PhishingScanURLs yes
EOF

Memcached ve Oturum Yönetimi

Zimbra, memcached’i route cache için kullanır. Düzgün yapılandırılmış memcached, LDAP yükünü önemli ölçüde azaltır.

su - zimbra
# Mevcut memcached ayarlarını görüntüle
zmlocalconfig memcached_server_port
zmlocalconfig memcached_bind_address

# Memcached bellek sınırını artır (MB cinsinden)
zmlocalconfig -e memcached_serverport=11211

Memcached durumunu kontrol etmek için:

echo "stats" | nc localhost 11211 | grep -E "bytes|curr_items|evictions|hits|misses"

evictions değeri yüksekse memcached’e daha fazla bellek ayırmanız gerekiyor. get_hits / (get_hits + get_misses) oranı %80’in altına düşüyorsa cache etkinliği sorunlu demektir.

Disk I/O ve Lucene Index Yönetimi

Zimbra’nın arama motoru Lucene, düzenli index işlemleri yapar. Bu işlemler özellikle gece yarısı bakım penceresinde disk’i kasıp kavurabilir.

Index durumunu kontrol etmek ve manuel olarak optimize etmek:

su - zimbra
# Tüm mailbox'lar için index boyutunu kontrol et
zmprov getAllAccounts | while read account; do
  echo -n "$account: "
  zmprov getMailboxInfo "$account" | grep indexSize
done 2>/dev/null | head -20

# Index optimizasyonu - dikkatli kullanın, CPU ve disk yoğun
zmcontrol status | grep -E "Index|Search"

Disk I/O’yu gerçek zamanlı izlemek için:

# iostat ile disk performansı
iostat -x 1 10 | grep -E "Device|sda|sdb|nvme"

# Zimbra'ya özel I/O istatistikleri
iotop -o -P -d 2 | grep zimbra

SSD kullanmıyorsanız kritik öneme sahip olan ayar:

# /etc/fstab'da Zimbra partition'ı için
# noatime,nodiratime ekleyin, örnek:
# /dev/sdb1 /opt/zimbra ext4 defaults,noatime,nodiratime 0 2

# Çalışan sistemde test için:
mount -o remount,noatime,nodiratime /opt/zimbra

Gerçek Dünya Senaryosu: 800 Kullanıcılı Kurumsal Ortam

Geçen yıl yönettiğim bir kurumsal müşteride 800 kullanıcılı Zimbra kurulumu vardı. Belirtiler şunlardı: sabah 09:00-10:00 arası web arayüzü yavaşlıyor, arama fonksiyonu zaman aşımına uğruyor, bazı kullanıcılar mail gönderirken “temporary failure” hatası alıyordu.

Teşhis süreci:

# mailboxd heap kullanımını kontrol et
su - zimbra
zmprov ms $(zmhostname) zimbraMailboxdJavaMaxHeapSize

# Aktif bağlantı sayısı
netstat -ant | grep :7071 | grep ESTABLISHED | wc -l
netstat -ant | grep :443 | grep ESTABLISHED | wc -l

# Son 1 saatteki hata logları
grep -i "error|exception|OutOfMemory" /opt/zimbra/log/mailboxd.log | 
  grep "$(date -d '1 hour ago' '+%Y-%m-%d %H')" | 
  sort | uniq -c | sort -rn | head -20

Tespit ettiğimiz sorunlar ve çözümler:

  • JVM heap 1GB olarak ayarlıydı, 4GB’a çıkardık
  • MySQL buffer pool 128MB’dı, 2GB’a çıkardık
  • Amavis sadece 2 worker çalışıyordu, 8’e çıkardık
  • Gece 03:00’de çalışan index optimizasyon job’u sabah 08:45’te hala devam ediyordu, backup ve index işlerini farklı zaman dilimlerine aldık

Sonuç: Sabah yoğunluk saatlerinde response time %65 iyileşti.

Monitoring ve Proaktif Yönetim

Sorun oluştuktan sonra değil, oluşmadan önce fark etmek için izleme şart.

#!/bin/bash
# /usr/local/bin/zimbra-health-check.sh
# Zimbra sağlık kontrolü scripti

ZIMBRA_USER="zimbra"
LOG="/var/log/zimbra-health.log"
ALERT_EMAIL="[email protected]"

check_service() {
    local service=$1
    if ! su - $ZIMBRA_USER -c "zmcontrol status" | grep "$service" | grep -q "Running"; then
        echo "$(date): KRITIK - $service servisi calışmıyor!" >> $LOG
        echo "Zimbra $service servisi durdu!" | mail -s "Zimbra Alert" $ALERT_EMAIL
    fi
}

check_heap() {
    local heap_used=$(su - $ZIMBRA_USER -c 
        "zmjava -cp /opt/zimbra/lib/jars/zimbra.jar 
        com.zimbra.common.util.SystemUtil" 2>/dev/null | 
        grep -oP 'heap=K[0-9]+')
    
    local heap_max=$(su - $ZIMBRA_USER -c 
        "zmlocalconfig mailboxd_java_heap_size" | awk '{print $3}')
    
    if [ ! -z "$heap_used" ] && [ ! -z "$heap_max" ]; then
        local percent=$((heap_used * 100 / heap_max))
        if [ $percent -gt 85 ]; then
            echo "$(date): UYARI - Heap kullanımı %$percent" >> $LOG
        fi
    fi
}

check_queue() {
    local queue_size=$(su - $ZIMBRA_USER -c "mailq | grep -c '^[A-F0-9]'" 2>/dev/null)
    if [ "$queue_size" -gt 500 ]; then
        echo "$(date): UYARI - Postfix kuyruğu: $queue_size mesaj" >> $LOG
        echo "Zimbra kuyruk uyarısı: $queue_size mesaj birikmiş" | mail -s "Zimbra Queue Alert" $ALERT_EMAIL
    fi
}

check_service "mailboxd"
check_service "postfix"
check_service "amavis"
check_service "mysql"
check_heap
check_queue

Bu scripti crontab’a ekleyin:

echo "*/5 * * * * root /usr/local/bin/zimbra-health-check.sh" >> /etc/cron.d/zimbra-health

Periyodik Bakım Görevleri

Düzenli yapılması gereken bakım işlemleri için bir script:

#!/bin/bash
# /usr/local/bin/zimbra-maintenance.sh
# Haftalık bakım scripti - pazar gecesi 02:00'de çalıştırın

su - zimbra << 'ZIMBRAEOF'

# Eski oturumları temizle
echo "Eski oturumlar temizleniyor..."
zmprov purgeAccountCalendarCache

# Log rotasyonu
echo "Eski loglar arşivleniyor..."
find /opt/zimbra/log -name "*.log.*" -mtime +30 -delete
find /opt/zimbra/log -name "*.log" -size +500M -exec gzip {} ;

# Silinmiş mesajları temizle
echo "Soft deleted mesajlar temizleniyor..."
zmprov purgeDeletedMessages

# LDAP cache temizliği
echo "LDAP cache yenileniyor..."
ldap restart

# Postfix kuyruk temizliği
echo "Stuck mesajlar yeniden deneniyor..."
postsuper -r ALL

echo "Bakım tamamlandı: $(date)"
ZIMBRAEOF

Kapasite Planlaması

Sisteminizin ne zaman yetersiz kalacağını öngörmek için şu metrikleri düzenli takip edin:

  • Disk büyümesi: du -sh /opt/zimbra/store/* ile mail store büyümesini haftalık ölçün
  • Kullanıcı başına ortalama mailbox boyutu: büyük artışlar backup politikasını veya kota uygulamasını gözden geçirmenizi gerektirebilir
  • Peak saatlerde aktif kullanıcı sayısı: grep "zimbraAuthToken" /opt/zimbra/log/access_log | cut -d' ' -f4 | sort | uniq -c | sort -rn | head -5
  • SMTP throughput: grep "status=sent" /var/log/zimbra.log | wc -l ile günlük gönderilen mesaj sayısı
  • GC frekansı: GC log’larından haftalık trend analizi

Sonuç

Zimbra optimizasyonu tek seferlik yapılıp unutulan bir iş değil. Sistemin büyüdükçe, kullanıcı sayısı arttıkça ve kullanım alışkanlıkları değiştikçe ayarları güncellemeniz gerekir. JVM heap ile başlayın, büyük etki yaratır. MySQL buffer pool ikinci önceliğiniz olsun. Amavis worker sayısını çekirdek sayınıza göre ayarlayın. Ve mutlaka izleme kurun; sorun oluştuktan sonra log karıştırmak yerine önceden uyarı almak hayat kalitesini ciddi ölçüde artırır.

Bu yazıda paylaştığım değerlerin hepsini körce kopyalamayın. Her ortam farklıdır; RAM’iniz, disk tipiniz, kullanıcı sayınız ve kullanım profiliniz benzersizdir. Değerleri uygulayın, izleyin, sonuçlara göre ince ayar yapın. Gerçek optimizasyon böyle olur.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir