• If you are still using CentOS 7.9, it's time to convert to Alma 8 with the free centos2alma tool by Plesk or Plesk Migrator. Please let us know your experiences or concerns in this thread:
    CentOS2Alma discussion

Too much imap IO makes server unresponsive... find the culprit

Frater

Regular Pleskian
When I first experienced an unresponsive server due to an over zealous Apple IMAP-client I found and used this python script.
http://www.patlathem.com/identifying-courier-imap-io-abusers/

This python-script is like iotop, but it focuses on imap and shows the user that's hogging down your server
It wasn't properly working after a Plesk upgrade, so I decided to see what it was doing and rewrite it in bash...
I know bash is a terrible language to script, but it's what I'm good in.


cat /usr/local/sbin/imapio2
Code:
#!/bin/bash

# Obtain the user that's running the imapd daemon
BIN=imapd
PROG=`which ${BIN}`
IMAPD_USER=`ps aux | grep -i "[0-9] ${PROG}" | awk '{print $1}' | sort | uniq -c | sort -n | tail -n1 | awk '{print $2}'`

# Create a TEMP-folder in /dev/shm (faster) and use its directory as a database (like /proc itself)
TMPDIR1=`mktemp -p /dev/shm -d ${0//*\/}.XXXXXXXXXX`

trap '{ echo "Quit..." ; rm -r ${TMPDIR1} ; exit 0; }' INT

while true ; do

  # find all folders in /proc created by imapd
  find /proc -mindepth 1 -maxdepth 1 -type d -user ${IMAPD_USER} -mtime -1 2>/dev/null >${TMPDIR1}/PIDS
  rm -r ${TMPDIR1}/USERS/ 2>/dev/null

  while read PID ; do
     if [ ! -d ${TMPDIR1}${PID} ] ; then
       # Create a folder in my TEMP-folder with the same name as in /proc
       # Also get the IP and EMAIL-address for this connection and save it in that same folder
       # set read and write counters to 0
       mkdir -p ${TMPDIR1}${PID} 2>/dev/null
       echo -n '0' >${TMPDIR1}${PID}/READ
       echo -n '0' >${TMPDIR1}${PID}/WRITE

       IP=`grep --binary-files=text -o 'TCPREMOTEIP=[0-9a-f.:]*' ${PID}/environ 2>/dev/null | awk -F= '{print$2}' | egrep -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | awk '{ printf("%-17s",$0)}'`
       NAME=`grep --binary-files=text -o 'AUTHENTICATED=.*' ${PID}/environ 2>/dev/null | awk -F= '{print$2}'`

       # In case the /proc/???? folder vanished while processing the structure skip to next /proc/????
       [ -z "${NAME}" ] && continue
       echo "${IP}${NAME}" >${TMPDIR1}${PID}/USER
     fi

     USER=`cat ${TMPDIR1}/${PID}/USER`
     # get info out of /proc/????/io
     READ=` grep '^read_bytes:'  ${PID}/io 2>/dev/null | awk '{print $2}'`
     WRITE=`grep '^write_bytes:' ${PID}/io 2>/dev/null | awk '{print $2}'`

     # Some sanity checking to avoid runtime errors in case the folder vanishes before it can be processed
     [ -z "${READ}"  ] && continue
     [ -z "${WRITE}" ] && continue

     # read old values out of /TMP/proc/???/READ and /TMP/proc/???/WRITE
     OLDREAD=`cat ${TMPDIR1}/${PID}/READ`
     OLDWRITE=`cat ${TMPDIR1}/${PID}/WRITE`


     # calculate the difference since last cycle
     DIFF_READ=$((${READ}   - ${OLDREAD}))
     DIFF_WRITE=$((${WRITE} - ${OLDWRITE}))

     # write new values to /TMP/proc/???/READ and /TMP/proc/???/WRITE
     echo ${READ}  >${TMPDIR1}/${PID}/READ
     echo ${WRITE} >${TMPDIR1}/${PID}/WRITE

     # create the cumulative folder for this USER/IP in /TMP/USERS/??????
     if [ ! -d "${TMPDIR1}/USERS/${USER}" ] ; then
       mkdir -p "${TMPDIR1}/USERS/${USER}"
       echo -n '0' >"${TMPDIR1}/USERS/${USER}/READ"
       echo -n '0' >"${TMPDIR1}/USERS/${USER}/WRITE"
     fi

     CUM_READ=`cat  "${TMPDIR1}/USERS/${USER}/READ"`
     CUM_WRITE=`cat "${TMPDIR1}/USERS/${USER}/WRITE"`

     echo $(( ${CUM_READ}  + ${DIFF_READ}))   >"${TMPDIR1}/USERS/${USER}/READ"
     echo $(( ${CUM_WRITE} + ${DIFF_WRITE}))  >"${TMPDIR1}/USERS/${USER}/WRITE"

  done<${TMPDIR1}/PIDS

  # get all folders with the cumulative values of this IP/USER combination
  find ${TMPDIR1}/USERS/ -mindepth 1 -maxdepth 1 -type d 2>/dev/null >${TMPDIR1}/USERNAMES

  echo -n '' >${TMPDIR1}/OUTPUT
  while read USERDIR ; do
     echo -n "${USERDIR##*/}:" | awk '{ printf("%-50s",$0)}' >>${TMPDIR1}/OUTPUT
     echo -e "\t\t`cat "${USERDIR}/READ"`\t\t`cat "${USERDIR}/WRITE"`" >>${TMPDIR1}/OUTPUT
  done<${TMPDIR1}/USERNAMES

  # Sort on write value and filter non-changed entries
  egrep -v '\s+0\s+0' ${TMPDIR1}/OUTPUT | sort -rn -t $'\t' -k5 >${TMPDIR1}/OUTPUTSORTED

  if [ -s ${TMPDIR1}/OUTPUTSORTED ] ; then
   printf "\ec"
   cat ${TMPDIR1}/OUTPUTSORTED
  fi

  sleep 1

done
 
Back
Top