systemadmin.es » Sistema de ficheros » Uso de los threads de NFS

Uso de los threads de NFS

En un servidor NFS, mediante el fichero /proc/net/rpc/nfsd podemos hacernos una idea del estado del servicio. Hoy vamos a ver el significado de la linea th.

Un ejemplo del fichero sería:

$ cat /proc/net/rpc/nfsd
rc 0 6671596 875517006
fh 351 0 0 0 0
io 738666746 3982364348
th 32 6006 36721.284 7532.056 2336.704 2441.997 1132.242 114.302 52.948 34.700 18.690 10.416
ra 64 46200169 49090 30766 16462 11972 10878 7780 7874 6044 5386 41789739
net 882193724 0 882189762 9448
rpc 882190850 0 0 0 0
proc2 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
proc3 22 3 347659355 691506 121853078 315329478 0 88134489 5082870 751855 43470 0 0 101862 0 28 3 80 1482946 1041 5 0 761589
proc4 2 0 0

En este caso la linea th (threads) es esta:

th 32 6006 36721.284 7532.056 2336.704 2441.997 1132.242 114.302 52.948 34.700 18.690 10.416

Los valores son:

  • Total de threads definidos
  • Veces que han estado todos los threads en uso
  • 10 valores representando el tiempo en que cierto porcentaje de threads han estado en uso.

En el caso del ejemplo, podemos ver:

  • Esta configurado para usar 32 threads
  • En el tiempo que lleva levantado el servicio ha estado 6006 veces usando todos los threads
  • El primer 10% de los threads estaban en uso 36721.284 segundos, el el segundo 10% (entre el 10 y el 20% de los threads) 7532.056 segundos… y así el resto.

Por lo tanto, mediante estas estadísticas podemos valorar si hace falta reducir o ampliar el número de threads (procesos) dedicados al NFS.

Si deseamos profundizar en como se calculan estos valores, podemos mirar el fichero fs/nfsd/stats.c la función static int nfsd_proc_show(struct seq_file *seq, void *v). En ella podemos encontrar el siguiente código:

        /* thread usage: */
        seq_printf(seq, "th %u %u", nfsdstats.th_cnt, nfsdstats.th_fullcnt);
        for (i=0; i<10; i++) {
                unsigned int jifs = nfsdstats.th_usage[i];
                unsigned int sec = jifs / HZ, msec = (jifs % HZ)*1000/HZ;
                seq_printf(seq, " %u.%03u", sec, msec);
        }

Como vemos, se basa en nfsdstats.th_usage, el cual se actualiza en el loop principal de NFS (fs/nfsd/nfssvc.c):

        for (;;) {
                /*
                 * Find a socket with data available and call its
                 * recvfrom routine.
                 */
                while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
                        ;
                if (err == -EINTR)
                        break;
                else if (err < 0) {
                        if (err != preverr) {
                                printk(KERN_WARNING "%s: unexpected error "
                                        "from svc_recv (%d)\n", __func__, -err);
                                preverr = err;
                        }
                        schedule_timeout_uninterruptible(HZ);
                        continue;
                }

                update_thread_usage(atomic_read(&nfsd_busy));
                atomic_inc(&nfsd_busy);

                /* Lock the export hash tables for reading. */
                exp_readlock();

                svc_process(rqstp);

                /* Unlock export hash tables */
                exp_readunlock();
                update_thread_usage(atomic_read(&nfsd_busy));
                atomic_dec(&nfsd_busy);
        }

El código de la función es el siguiente:

static inline void
update_thread_usage(int busy_threads)
{
        unsigned long prev_call;
        unsigned long diff;
        int decile;

        spin_lock(&nfsd_call_lock);
        prev_call = nfsd_last_call;
        nfsd_last_call = jiffies;
        decile = busy_threads*10/nfsdstats.th_cnt;
        if (decile>0 && decile <= 10) {
                diff = nfsd_last_call - prev_call;
                if ( (nfsdstats.th_usage[decile-1] += diff) >= NFSD_USAGE_WRAP)
                        nfsdstats.th_usage[decile-1] -= NFSD_USAGE_WRAP;
                if (decile == 10)
                        nfsdstats.th_fullcnt++;
        }
        spin_unlock(&nfsd_call_lock);
}

Como vemos siguiendo el código, se basa en un simple contador que según el porcentaje de threads en uso incrementa una o otra variable del array nfsdstats.th_usage.

Relacionados

Imprimir Imprimir

Deja un comentario:

XHTML - Tags permitidos:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>