A veces hay que aplicar alguna configuración de emergencia para resolver un problema urgente, pero la misma puede afectar a los usuarios que están conectados actualmente a un servidor. Existe una variedad de causas diferentes que pueden perjudicar a los usuarios actuales de un servicio. Por ejemplo puede hace falta reiniciar Apache, o directamente detenerlo porque es necesario reiniciar un servidor de bases de datos. También podría ser necesario reiniciar directamente el sistema operativo por un problema de hardware (se llenó un disco y hay que ampliar su capacidad, o agregar más memoria RAM). Sea como sea, los Sysadmins en general buscamos un horario fuera de oficina para este tipo de "actividades", pero en caso de emergencias, no queda otra alternativa que hacerlo en horarios de oficina. En este caso puede ser útil saber si hay usuarios actualmente conectados al servidor, para afectar a la menor cantidad de gente posible.
En este caso, supongamos que se trata de un servidor Web Apache. Por alguna razón hay que ejecutar una tarea que requiere el reinicio o la baja temporal del servidor.
Para conocer cuáles son todas las conexiones de red relacionadas al servicio apache, es posible listar utilizando la herramienta netstat
todas las conexiones TCP (excepto aquellas locales) filtrando luego con grep
aquellas relacionadas al proceso "apache2" o a los puertos 80
(HTTP) y 443
(HTTPS):
netstat -tpn | grep -v "127.0.0" | grep "apache\|443\|80"
Veamos un ejemplo:
root@debian7:~# netstat -tpn | grep -v "127.0.0" | grep "apache\|443\|80" tcp 0 0 192.168.57.29:443 192.168.105.221:2827 ESTABLISHED 6484/apache2 tcp 0 0 192.168.57.29:443 192.168.105.221:2830 ESTABLISHED 6444/apache2 tcp 0 0 192.168.57.29:443 192.168.105.102:51882 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4225 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4221 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2818 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4233 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.102:51881 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2831 ESTABLISHED 6440/apache2 tcp 0 0 192.168.57.29:443 192.168.105.102:51888 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2815 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2814 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.116:52167 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4231 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.102:51885 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4263 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2823 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.102:51883 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4234 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4247 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2820 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2828 ESTABLISHED 6489/apache2 tcp 0 0 192.168.57.29:443 192.168.105.125:2738 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2826 ESTABLISHED 6488/apache2 tcp 0 0 192.168.57.29:443 192.168.105.129:4220 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.125:2736 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.102:51873 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4248 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.125:2739 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4238 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4264 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2829 ESTABLISHED 6471/apache2 tcp 0 0 192.168.57.29:443 192.168.105.116:52166 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4218 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4261 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4235 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4243 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2822 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4232 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.102:51886 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4259 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4260 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4228 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2821 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4224 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4222 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.116:52164 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.102:51894 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4244 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4245 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4246 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2817 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.125:2740 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4255 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.125:2735 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.116:52165 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.125:2737 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2816 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4262 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.129:4223 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2812 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.116:52168 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.116:52163 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.102:51884 TIME_WAIT - tcp 0 0 192.168.57.29:443 192.168.105.221:2813 TIME_WAIT -
Se observa que existen algunas conexiones establecidas (en estado "ESTABLISHED") y otras recientemente cerradas (en estado "TIME_WAIT").
El estado "TIME_WAIT" significa que la conexión ha sido cerrada, pero el socket aún permanece en espera para manejar posibles paquetes que aún estén (dando vueltas) en la red. Es posible filtrar estas conexiones para que el comando sólo muestre las establecidas:
root@debian7:~# netstat -tupn | grep -v "127.0.0" | grep "apache\|443\|80" | grep "ESTABL" tcp 0 0 192.168.57.29:443 192.168.105.114:52071 ESTABLISHED 8359/apache2 tcp 0 0 192.168.57.29:443 192.168.105.114:52073 ESTABLISHED 8315/apache2 tcp 0 0 192.168.57.29:443 192.168.105.114:52072 ESTABLISHED 8298/apache2 tcp 0 0 192.168.57.29:443 192.168.105.114:52074 ESTABLISHED 8340/apache2 tcp 0 0 192.168.57.29:443 192.168.105.114:52070 ESTABLISHED 8334/apache2 tcp 0 0 192.168.57.29:443 192.168.105.114:52069 ESTABLISHED 8353/apache2
¿Y qué hay de las sesiones PHP?
Ahora bien, este método es muy común y conocido por todos, aunque existe otra forma de monitorear la actividad de un servidor Web, siempre que corra una aplicación PHP. Esta consiste en ver las fechas de modificación de los archivos de sesiones de PHP, por defecto almacenados en el directorio /var/lib/php5
. Estos archivos almacenan los datos de cada sesión y su tiempo de vida por defecto puede ser obtenido consultando a la variable session.gc_maxlifetime
, dentro del archivo php.ini
. Cada vez que una aplicación PHP ejecuta una llamada a session_start()
se crea un archivo correspondiente en dicho directorio.
Por ejemplo, el servidor en cuestión posee las siguiente sesiones PHP abiertas:
root@debian7:~# ls -rlt /var/lib/php5/ && date total 16948 -rw------- 1 www-data www-data 3569 Dec 28 13:18 sess_6ihle7mveadphq3ur8bu6eiq8nvq31fd -rw------- 1 www-data www-data 3569 Dec 28 13:24 sess_fd9v10ti77msb4n0la0du2ntav50hpr7 -rw------- 1 www-data www-data 3569 Dec 28 13:31 sess_vt9alv5hp5vvrq30cr8logo0dlu9d5g9 -rw------- 1 www-data www-data 28222 Dec 28 13:45 sess_moa8m54ik06b0q0c62drt0nptfgu6c35 -rw------- 1 www-data www-data 18021 Dec 28 13:59 sess_rm3set0u2ast757oalfch6gge5m2md7e -rw------- 1 www-data www-data 3569 Dec 28 14:14 sess_f900h3uldn82eeqmn4834v3jje73sl33 -rw------- 1 www-data www-data 20802 Dec 28 14:20 sess_aq6k06bcq4mfcgol9cn53t1ighroi6lp -rw------- 1 www-data www-data 3569 Dec 28 14:22 sess_k5nb6k7j8i3bhlsqgcp28kh00gmbv0e4 -rw------- 1 www-data www-data 3569 Dec 28 14:24 sess_fdulgi93fva8kd7sbps21orsstirpvli -rw------- 1 www-data www-data 16584 Dec 28 14:25 sess_r44qh20qrk1as90ad2bittmkt80hku2m -rw------- 1 www-data www-data 30787 Dec 28 14:26 sess_8rdhfsjs5t78qua4dqidguoc8aeaokb0 -rw------- 1 www-data www-data 4037 Dec 28 14:35 sess_879s40oi7ek6bl319rtuolktpjgd2a4c -rw------- 1 www-data www-data 3569 Dec 28 15:00 sess_ri4vcn03rdd41k0l832nkvvrn26fmh9b -rw------- 1 www-data www-data 3569 Dec 28 15:21 sess_5usjq9lq28tf82smk25v8lo4b63a1tkt -rw------- 1 www-data www-data 3569 Dec 28 15:24 sess_tn88b6glp69j00c8olu9fd8uh3gs1cug -rw------- 1 www-data www-data 4668 Dec 29 07:57 sess_t00s2ud392i0mn4lfkk5mv5mlhshb6tt -rw------- 1 www-data www-data 7783 Dec 29 09:01 sess_asuf1cvu9erppvcf3ckgjbpi5f2a28cq -rw------- 1 www-data www-data 12669 Dec 29 09:49 sess_i5fjmbucs9p7bb8pdeh0223dsjep19e4 -rw------- 1 www-data www-data 14659 Dec 29 09:53 sess_m3n6r8c59h2jbsel8hcqt0ngpsa6970p -rw------- 1 www-data www-data 6037 Dec 29 09:56 sess_v45jhl05t1e3gaghk48qpr4l2leu1lh2 -rw------- 1 www-data www-data 3569 Dec 29 10:02 sess_knnloejo8r7uikiverb144cn040rtl0u -rw------- 1 www-data www-data 12663 Dec 29 10:04 sess_9ske3kr35hv578bi0ub428l0th885881 -rw------- 1 www-data www-data 7577 Dec 29 10:17 sess_d4lf6o75n4ankv8028640le5aj84s703 -rw------- 1 www-data www-data 9860 Dec 29 10:26 sess_fv4co92lsk5371btsevtn1tvu81puauq -rw------- 1 www-data www-data 8893 Dec 29 10:36 sess_32ofkuqfb4oic6b2b1ofv1ik8lto369n -rw------- 1 www-data www-data 7367 Dec 29 10:44 sess_558im9kt3oo5tattndq1mntvsk4ba4g2 -rw------- 1 www-data www-data 3569 Dec 29 11:07 sess_ashkg3re988593i0i4c4vfvp0g997mgg -rw------- 1 www-data www-data 11896 Dec 29 11:16 sess_ovh5ni9pomqdp4hbgasn9m8blv8bi947 -rw------- 1 www-data www-data 3569 Dec 29 11:22 sess_5tadm79fqncr8jrf9227g0bg0oaa4dmf -rw------- 1 www-data www-data 2200724 Dec 29 11:30 sess_989enmkfj5gqvmqfata2klbukdnm25eo -rw------- 1 www-data www-data 33649 Dec 29 12:01 sess_flfs55omvgta2dbto4pc78jm8e8pk0ur -rw------- 1 www-data www-data 12984 Dec 29 12:01 sess_fb1rgo07kf3abmrgspvlam7ptffcrbim -rw------- 1 www-data www-data 3569 Dec 29 12:10 sess_vkb3cq3t0mhopb6kopr8u69q62f7n9fd -rw------- 1 www-data www-data 9867 Dec 29 12:27 sess_5m3tnbp3t36rrponaark9ounsijgk7lo -rw------- 1 www-data www-data 37915 Dec 29 12:28 sess_9umn1u1hr5tsto8apiogqcfuqqbqrpup -rw------- 1 www-data www-data 9962 Dec 29 12:31 sess_auh2b24oudsld2624u1i2ua76kbr17o2 -rw------- 1 www-data www-data 15667 Dec 29 12:34 sess_9tdhiioos9ni4d3n4hf1u8e1vcno3qu5 -rw------- 1 www-data www-data 17931 Dec 29 12:38 sess_qqbs15j95mfl0oop3e1mgqhmapfl1pqi -rw------- 1 www-data www-data 9091 Dec 29 12:41 sess_m9hgndln3cforb0bhp4dl389a1le7cno -rw------- 1 www-data www-data 3569 Dec 29 12:42 sess_ts1un02dkrjrbg9iipb11fte2b2kan2b -rw------- 1 www-data www-data 22727 Dec 29 12:51 sess_5nh74vf280g6ietpjfn5hipr7qns69ql -rw------- 1 www-data www-data 8887 Dec 29 13:06 sess_jo1qig0joorpjor8c184bm0qauof44id -rw------- 1 www-data www-data 27509 Dec 29 13:09 sess_80rcnk9ajnt61ng6fcd1r3rl5a1faarn -rw------- 1 www-data www-data 8836 Dec 29 13:09 sess_icqniclij5ch43639fero85f8dcfe0kd -rw------- 1 www-data www-data 14701 Dec 29 13:11 sess_eeih2pq4nsodmgvfjrljc9rr6hkt6ogn -rw------- 1 www-data www-data 12969 Dec 29 13:14 sess_323j6u3c3c87ngdou1n2sek17kr4pm30 -rw------- 1 www-data www-data 160650 Dec 29 13:15 sess_i9htolt4dsqi5bhen21o1didksg25jpm -rw------- 1 www-data www-data 6444 Dec 29 13:15 sess_nk6tuc2qjiiifqh7cqkgpq1kq95ulkec -rw------- 1 www-data www-data 11415 Dec 29 13:20 sess_nv18780l0q9rjo808km451ch6jeucn90 -rw------- 1 www-data www-data 43898 Dec 29 13:20 sess_8hg76lqvfoa53p52t7posl6i2jbh6pkg -rw------- 1 www-data www-data 7515 Dec 29 13:22 sess_khsmbkcav7fpq43j6pdf1kodu5vljcsp -rw------- 1 www-data www-data 3569 Dec 29 13:23 sess_1ja524tdcbu625glj1k88hnj9pkov00m -rw------- 1 www-data www-data 19759 Dec 29 13:25 sess_ds1657pu39edlf6fltr7qp1br599lgdi -rw------- 1 www-data www-data 3569 Dec 29 13:25 sess_at7a3a1n02tm26adsj2q4tau02sk11k1 -rw------- 1 www-data www-data 3569 Dec 29 13:25 sess_nflhadktcmigg2gfrauijrlo99n5suvb -rw------- 1 www-data www-data 47287 Dec 29 13:26 sess_stgd934e6ec5nntktl52mlo2mkv04b8n -rw------- 1 www-data www-data 22236 Dec 29 13:27 sess_piu5956d23tckcll86sqh1m5v2lmdp2d -rw------- 1 www-data www-data 3569 Dec 29 13:28 sess_o7le7pqfjc7qo30kr9u6gro0vf5f2gjn -rw------- 1 www-data www-data 14002797 Dec 29 13:29 sess_93r6vci7jgog3tbv7tdjmprptlcukcd6 -rw------- 1 www-data www-data 172870 Dec 29 13:30 sess_i7dpqkco4vs4tl0vgod879lbadj1op3h -rw------- 1 www-data www-data 28380 Dec 29 13:31 sess_5s9cid8qk7m88crol47qie8botaavsvh Tue Dec 29 13:31:57 ART 2015
Se observa un número importante de sesiones PHP abiertas, algunas iniciadas muy recientemente (comparar con la fecha del servidor). Esto significa que, por más que no hayan conexiones TCP establecidas con el servidor Apache, hay usuarios que tienen sesiones PHP abiertas. Lo cual indica que probablemente estén trabajando con la aplicación y es probable que algunos (o muchos) vayan a generar tráfico hacia el servidor Web a corto plazo.
Evidentemente, controlar la fecha de creación/modificación de los archivos correspondientes a las sesiones PHP nos puede dar una imagen más precisa del uso actual del servidor Web.
Otro ejemplo con netstat
Veamos un ejemplo más de la evolución de las conexiones TCP hacia el servidor Apache. Si el servidor está ocioso, la salida netstat (tal como se ha filtrado en el ejemplo previo) debería ser vacía, sin resultados. Entonces, partiendo desde un servidor Web ocioso, abrir algunas conexiones HTTP hacia el mismo desde un navegador e inmediatamente cerrarlo.
13:38:13 - El servidor Apache se encuentra ocioso:
root@debian6:~# date && netstat -tupn | grep -v "127.0.0" | grep "apache\|:443\|:80" Tue Dec 29 13:38:13 ART 2015
No hay coincidencias, no hay ningún tipo de conexión relacionada con Apache.
13:38:26 - Apache recibe la primera petición desde un cliente:
root@debian6:~# date && netstat -tupn | grep -v "127.0.0" | grep "apache\|:443\|:80" Tue Dec 29 13:38:26 ART 2015 tcp6 0 0 10.8.100.53:80 192.168.133.15:18117 ESTABLISHED 3756/apache2
Se observa la primera conexión establecida con el servidor.
13:38:39 a 13:38:43 - Apache recibe una serie de peticiones desde el mismo cliente:
root@debian6:~# date && netstat -tupn | grep -v "127.0.0" | grep "apache\|:443\|:80" Tue Dec 29 13:38:39 ART 2015 tcp6 0 0 10.8.100.53:80 192.168.133.15:18117 TIME_WAIT - tcp6 0 0 10.8.100.53:80 192.168.133.15:45548 ESTABLISHED 3757/apache2 root@debian6:~# date && netstat -tupn | grep -v "127.0.0" | grep "apache\|:443\|:80" Tue Dec 29 13:38:43 ART 2015 tcp 0 0 10.8.100.53:80 192.168.133.15:18830 SYN_RECV - tcp6 0 0 10.8.100.53:80 192.168.133.15:18117 TIME_WAIT - tcp6 0 0 10.8.100.53:80 192.168.133.15:45548 ESTABLISHED 3757/apache2
El tráfico hacia el servidor fluye. En este punto, el cliente cierra el navegador (cerrando así las conexiones TCP contra el servidor Web).
13:39:13 - Apache está ocioso nuevamente y todas las conexiones TCP han sido cerradas, pero quedan sockets en espera (en estado "TIME_WAIT"):
root@debian6:~# date && netstat -tupn | grep -v "127.0.0" | grep "apache\|:443\|:80" Tue Dec 29 13:39:13 ART 2015 tcp6 0 0 10.8.100.53:80 192.168.133.15:18117 TIME_WAIT - tcp6 0 0 10.8.100.53:80 192.168.133.15:45548 TIME_WAIT -
13:39:53 - Apache permanece ocioso, aunque ahora queda sólo un socket TCP en espera (timeout):
root@debian6:~# date && netstat -tupn | grep -v "127.0.0" | grep "apache\|:443\|:80" Tue Dec 29 13:39:53 ART 2015 tcp6 0 0 10.8.100.53:80 192.168.133.15:45548 TIME_WAIT -
13:39:59 - Apache permanece ocioso y todos los sockets TCP han sido liberados (timeout):
root@debian6:~# date && netstat -tupn | grep -v "127.0.0" | grep "apache\|:443\|:80" Tue Dec 29 13:39:59 ART 2015
Siguiendo la línea de tiempo de este experimento, se observa que la última petición fue originada antes de las 13:38:43 y todas las conexiones han sido finalizadas después de las 13:39:53. Por ende, se puede deducir que las conexiones TCP permanecen abiertas durante algo más de un minuto.
Es posible verificar esta configuración de la pila TCP/IP en el kernel Linux consultando a la variable net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait
:
root@debian6:~# sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 120
El tiempo de espera para sockets en estado TIME_WAIT es de 120 segundos, lo cual coincide con el experimento.
Además de estas técnicas y herramientas, existe un módulo de Apache llamado mod_status
que da información de estado del servidor. Puede ser útil para algunos Administradores de Sistemas, pero aún no lo he probado pues mi idea era resolver esta cuestión utilizando las herramientas de línea de comando a mi alcance.
La página de manual de netstat posee información detallada acerca de los estados de las conexiones TCP:
man netstat
Enlaces de interés
lognormal - Linux TCP/IP tuning for scalability
The TCP/IP Guide - TCP Connection Termination