# rm-rf.es | Administración de sistemas

Bitácora personal de un SysAdmin Gnu/Linux, Windows, BSD...

SLAMD Distributed Load Generation Engine


slamd logoPese a que Sun Microsystems ya no mantiene un desarrollo activo de la aplicación, SLAMD (SLAMD Distributed Load Generation Engine) sigue siendo una excelente opción para realizar todo tipo de pruebas de carga, rendimiento y stress a nuestras redes, servidores y aplicaciones.

SLAMD nos ofrece a apenas un click de distancia decenas de pruebas de stress, las cuales podemos personalizar según nuestros requerimientos, volumen de carga/stress a aplicar, etc. Por ejemplo tenemos distintos trabajos para hacer testing a LDAP (importar, exportar, búsquedas asíncronas, generadores de carga con búsquedas múltiples…), también HTTP (en este caso mucho más potente JMeter), pruebas SMTP, IMAP y POP3, scripting, SQL, Throughput de red, pruebas TCP, stress de CPU, etc. Una vez realizados los tests recibimos informes con una gran cantidad de información relevante que podemos exportar en HTML, PDF o texto plano, incluye cifras, máximos, mínimos y medias, gráficos…

informe  slamd

La forma más sencilla de hacerlo funcional no requiere instalación, podemos bajar todo el aplicativo, cliente, servidor y Tomcat en un único paquete, descomprimirlo y arrancar Tomcat:

$ wget http://files.unboundid.com/slamd/slamd-2.0.1.zip
$ unzip slamd-2.0.1.zip
$ cd slamd/bin/
$ ./catalina.sh  start

Accedemos a la aplicación a través de http://hostname:8080. La primera vez que accedemos tenemos que inicializar la base de datos interna, una vez realizado ya podemos comenzar las pruebas que queramos. Si necesitamos generar la carga distribuida desde varios servidores, únicamente tenemos que habilitar en ellos el cliente. Lo descomprimimos, modificamos el fichero de configuración indicando el servidor al que se conectará  y arrancamos:

$ ls -l slamd_client*
-rw-r--r-- 1 alex alex 5294716 2010-03-20 17:58 slamd_client-2.0.1.zip
$ unzip slamd_client-2.0.1.zip
$ ls -l slamd_client/slamd_client.conf
-rw-r--r-- 1 alex alex 1259 2010-03-20 17:58 slamd_client/slamd_client.conf
$ slamd_client/start_client.sh

Para poder ejecutar el cliente de forma independiente al servidor debemos tener instalado JAVA en el equipo. Os recomiendo de todas formas leer las guías de QuickStart (OpenDocument  |  PDF ) y la de Herramientas (OpenDocument  |  PDF ) para sacarle un mayor partido a la aplicación.

grafico slamd

Instalar y utilizar Apache JMeter sin GUI


Apache jmeterHoy vamos a ver los pasos necesarios (muy sencillos) para instalar y utilizar Apache JMeter sin GUI (entorno gráfico) en sistemas Red Hat, CentOS, etc.

JMeter es un proyecto de Apache Jakarta que puede ser utilizado como una herramienta de prueba de carga para analizar y medir el desempeño de una variedad de servicios, con énfasis en aplicaciones web.

Wikipedia

Lo primero es conocer las dependencias de JMeter, en este caso tenemos que instalar JDK, ya que funciona a través de java. Lo hacemos instalando la versión disponible desde yum o si queremos alguna concreta bajandola desde el sitio web de java:

# yum install java-1.6.0-openjdk.x86_64

Una vez instalado java, verificamos la versión y que es compatible (libre de bugs) con la versión de JMeter que vamos a utilizar:

# java -version
java version "1.6.0_22"
OpenJDK Runtime Environment (IcedTea6 1.10.6) (rhel-1.43.1.10.6.el6_2-x86_64)
OpenJDK 64-Bit Server VM (build 20.0-b11, mixed mode)

Pasamos entonces a bajar JMeter, en lugar de compilarlo, podemos bajar directamente los binarios precompilados, de modo que únicamente tengamos que descomprimirlo y tunear un poco algún parámetro para poder empezar a utilizarlo:

# wget http://apache.rediris.es//jmeter/binaries/apache-jmeter-2.6.tgz
# wget http://apache.rediris.es//jmeter/binaries/apache-jmeter-2.6.tgz.asc
# wget http://www.apache.org/dist/jmeter/KEYS

Importamos las keys de Apache para verificar la integridad del archivo descargado:

# gpg --import KEYS
# gpg --verify apache-jmeter-2.6.tgz.asc

Y ya podemos descomprimir y utilizar JMeter:

# tar -xzvf apache-jmeter-2.6.tgz
# mv apache-jmeter-2.6 /usr/local/jmeter
# cd /usr/local/jmeter/

Para un uso básico, simplemente especificamos que no vamos a utilizar GUI (-n), el plan a ejecutar (-t) y el log donde almacenar los resultados (-l):

# /bin/jmeter -n -t plans/miplandepruebas.jmx -l plans/registro_pruebas.log

Un problema común es tener problemas de memoria al ejecutar el plan, ya que los recursos asignados son insuficientes. Para modificarlo, editamos el fichero jmeter y aumentamos los límites de memoria en la variable HEAP, siempre en relación a los recursos de los que dispongamos:

# vi bin/jmeter
# This is the base heap size -- you may increase or decrease it to fit your
# system's memory availablity:
#HEAP="-Xms512m -Xmx512m"
HEAP="-Xms4096m -Xmx4096m"

Otro problema común es el de los límites de ficheros abiertos (open files) especificados en ulimit, sobre todo para pruebas de estrés importantes, deberemos adecuarlo según necesidades igualmente para la sesión en la que ejecutamos las pruebas:

# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 95066
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Limitar recursos por usuario en MySQL


MySQLYo, hasta el momento, la única forma que conocía de limitar recursos por usuario en MySQL era estableciendo la variable max_user_connections o en su defecto creando instancias independientes del servicio para distintas bases de datos. Revisando la documentación de MySQL me he dado cuenta de que es posible aplicar más restricciones de forma independiente para cada usuario, entre las que se encuentran:

  • Número de consultas que un usuario pueda hacer cada hora.
  • Número de updates que un usuario puede hacer cada hora.
  • Número de veces que un usuario puede acceder al servidor a la hora.
  • Número de conexiones simultaneas permitidas para cada usuario (como max_user_connections pero a nivel individual en lugar de global).

Estos límites tendrán un contador para cada acceso del usuario,excepto cuando su consulta sea servida a través de la cache. Este tipo de contextos se establecen en la tabla mysql.user y los podemos aplicar mediante GRANT. En el siguiente ejemplo estableceríamos todos estos límites para el usuario prueba cuando sus conexiones se realizan desde localhost y contra la base de datos test:

mysql> CREATE USER 'prueba'@'localhost' IDENTIFIED BY 'PASSWORD';
mysql> GRANT ALL ON test.* TO 'prueba'@'localhost'
->     WITH MAX_QUERIES_PER_HOUR 100
->          MAX_UPDATES_PER_HOUR 30
->          MAX_CONNECTIONS_PER_HOUR 200
->          MAX_USER_CONNECTIONS 10;

Para realizar modificaciones en estos límites a posteriori, utilizaremos a nivel global GRANT USAGE:

mysql> GRANT USAGE ON *.* TO 'prueba'@'localhost'
    ->    WITH MAX_QUERIES_PER_HOUR 50;

Para eliminar cualquier límite establecido ponemos el valor a 0:

mysql> GRANT USAGE ON *.* TO 'prueba'@'localhost'
    ->    WITH MAX_QUERIES_PER_HOUR 0;

Para poner a 0 los contadores de limites a nivel general podemos ejecutar el comando:

mysql> FLUSH USER_RESOURCES

También recargando las tablas de privilegios:

mysql> FLUSH PRIVILEGES

5 formas de encontrar y optimizar consultas MySQL problemáticas


MySQLA la hora de detectar problemas en servidores MySQL (cuellos de botella, uso excesivo de CPU, bajo rendimiento, lentitud, etc) es conveniente conocer las distintas opciones que nos ofrece MySQL para dar con el problema. Vamos a ver algunas de ellas:

Activar el Slow Query Log

Activar el log de consultas lentas en MySQL supondrá que en el momento que una consulta SQL supere el tiempo de ejecución establecido con la variable long_query_time quedará registrada en el log establecido. Para activarlo añadimos las siguientes directivas en el fichero de configuración my.cnf:

log-slow-queries=/var/log/mysql-slow-queries.log
long_query_time = 5

Este tema ya lo traté en un artículo anterior, para profundizar en ello acceded a la entrada a través del siguiente enlace: Slow Queries en MySQL.

Usar SHOW PROCESSLIST

Tanto desde la propia shell desde MySQL como usando mysqladmin podemos visualizar a tiempo real las consultas SQL que se están ejecutando en el servidor:

mysql> show processlist;
+----+------+-----------+------+---------+------+-------+------------------+
| Id | User | Host      | db   | Command | Time | State | Info             |
+----+------+-----------+------+---------+------+-------+------------------+
| 35 | root | localhost | NULL | Query   |    0 | NULL  | show processlist |
+----+------+-----------+------+---------+------+-------+------------------+
1 row in set (0.00 sec)

Como podéis observar, nos muestra el estado de la consulta (State), la base de datos, el comando que está ejecutando, el usuario, el host y el tiempo de ejecución, siendo este último de los puntos más importantes. Recordad que podéis formatear la salida con \G:

mysql> show processlist \G
*************************** 1. row ***************************
     Id: 35
   User: root
   Host: localhost
     db: NULL
Command: Query
   Time: 0
  State: NULL
   Info: show processlist
1 row in set (0.00 sec)

Y con mysqladmin desde la shell bash:

$ mysqladmin processlist -u root --pXXXX
+----+------+-----------+----+---------+------+-------+------------------+
| Id | User | Host      | db | Command | Time | State | Info             |
+----+------+-----------+----+---------+------+-------+------------------+
| 42 | root | localhost |    | Query   | 0    |       | show processlist |
+----+------+-----------+----+---------+------+-------+------------------+

Si queréis ver el contenido completo de la consulta SQL que se está ejecutando probablemente necesitéis utilizar SHOW FULL PROCESSLIST; en lugar de SHOW PROCESSLIST:

mysql> SHOW FULL PROCESSLIST;
+----+------+-----------+------+---------+------+-------+-----------------------+
| Id | User | Host      | db   | Command | Time | State | Info                  |
+----+------+-----------+------+---------+------+-------+-----------------------+
| 35 | root | localhost | NULL | Query   |    0 | NULL  | SHOW FULL PROCESSLIST |
+----+------+-----------+------+---------+------+-------+-----------------------+
1 row in set (0.00 sec)

Optimizar las consultas SQL con EXPLAIN

Gracias a EXPLAIN podemos obtener toda la información sobre el modo en el que una consulta SQL se ejecutaría en el servidor. Es extremadamente útil para conocer la configuración de índices en las tablas, los índices que podrían ser configurados para mejorar su rendimiento, el número de filas que se revisan, el tipo de query, etc.

Aquí tenéis un ejemplo de EXPLAIN contra la tabla City de la base de datos de muestra de MySQL (world). Para profundizar en el funcionamiento de EXPLAIN os recomiendo revisar la documentación oficial de MySQL.

mysql> EXPLAIN select * from City;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | City  | ALL  | NULL          | NULL | NULL    | NULL | 4079 |       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
mysql> EXPLAIN select * from City \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: City
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 4079
        Extra:
1 row in set (0.00 sec)

Activar el log general

Una medida quizás un poco agresiva y que no debería ser ejecutada en servidores de producción. Este log (General Query Log) registrará todas las consultas SQL que se ejecuten en el servidor. Para activarlo debemos especificar la ruta del log mediante –general_log_file= (MySQL 5.1.29+). También podemos activarlo y desactivarlo a tiempo real desde la shell MySQL del siguiente modo:

mysql> SET GLOBAL general_log = 'OFF';
mysql> SET GLOBAL general_log = 'ON';

MySQL Query Analyzer

Si pese a las opciones anteriores seguís sin poder detectar las consultas SQL problemáticas y optimizarlas, quizás MySQL Query Analyzer sea una opción factible. Es un software de pago perteneciente a la versión Enterprise que de forma gráfica monitoriza las consultas SQL del servidor y detecta el origen de los problemas. A mi entender, las otras opciones deberían ser suficiente (junto con buenos conocimientos de DBA todo sea dicho) para detectar y solucionar cualquier problema que se presente.

 

Como habréis podido observar, la combinación de estas opciones en distintos ordenes nos permitirá arreglar muchos problemas con consultas SQL, primero detectamos los problemas con los logs de slow_queries o SHOW PROCESSLIST y después optimizamos con EXPLAIN las consultas detectadas en los pasos anteriores.

MySQL tools: benchmarking con mysqlslap


MySQLMySQL, a partir de la versión 5.1 integra una utilidad llamada mysqlslap que permite estresar y hacer benchmarking del servidor MySQL. Gracias a mysqlslap podremos comparar el rendimiento del servidor ante cambios realizados en las bases de datos, motores de almacenamiento y configuraciones así como con X número de clientes interactuando con las bases de datos, cierto tipo de consultas SQL, etc.

Si queremos comenzar haciendo tests básicos podemos dejar que sea la propia utilidad la que genere de forma aleatoria las consultas SQL, únicamente tenemos que especificar el usuario MySQL con el cual se van a realizar:

$ mysqlslap -u foo -pxxxx --auto-generate-sql
Benchmark
	Average number of seconds to run all queries: 0.007 seconds
	Minimum number of seconds to run all queries: 0.007 seconds
	Maximum number of seconds to run all queries: 0.007 seconds
	Number of clients running queries: 1
	Average number of queries per client: 0

En este test se ha realizado la conexión de un único usuario (foo) que ha realizado pruebas aleatorias entre las que se incluye la creación de una tabla, la inserción y consulta de datos en ella y la eliminación de la tabla. Si queréis ver con detalle cada una de las consultas que se realizan en el test podéis añadir la cantidad de verbose con el parámetro -v (a más v más verbose):

$ mysqlslap -vvv -u foo -pxxxx --auto-generate-sql

Estos test realmente no sirven de mucho, así que conviene saber como personalizarlos, añadir más usuarios concurrentes en las pruebas y consultas SQL personalizadas. El número de usuarios concurrentes se especifica con el parámetro

--concurrency=

, vamos a realizar la misma prueba pero con 50 usuarios concurrentes:

$ mysqlslap -u foo -pxxxx --concurrency=50 --auto-generate-sql
Benchmark
	Average number of seconds to run all queries: 0.389 seconds
	Minimum number of seconds to run all queries: 0.389 seconds
	Maximum number of seconds to run all queries: 0.389 seconds
	Number of clients running queries: 50
	Average number of queries per client: 0

Otro parámetro interesante es

--iterations=

, mediante el cual podemos especificar el número de veces que se repetirá el test. Vamos a ejecutarlo 4 veces:

$ mysqlslap -u foo -pxxxx --concurrency=50 >--iterations=4 --auto-generate-sql
Benchmark
	Average number of seconds to run all queries: 0.389 seconds
	Minimum number of seconds to run all queries: 0.389 seconds
	Maximum number of seconds to run all queries: 0.389 seconds
	Number of clients running queries: 50
	Average number of queries per client: 0

También podemos modificar el número de consultas a realizar en el test con el parámetro

--number-of-queries=

, serán repartidas entre el número de usuarios que ejecutan el test:

$ mysqlslap -u foo -pxxxx --concurrency=50 >--iterations=4 --number-of-queries=300 --auto-generate-sql
Benchmark
	Average number of seconds to run all queries: 0.233 seconds
	Minimum number of seconds to run all queries: 0.217 seconds
	Maximum number of seconds to run all queries: 0.242 seconds
	Number of clients running queries: 50
	Average number of queries per client: 6

Otro parámetro de extrema utilidad es

--engine=

, que nos permite especificar el tipo de motor a utilizar para la creación de la tabla (MyISAM, Innodb…) y así poder realizar varios tests y verificar cual es el más adecuado.

$ mysqlslap -u foo -pxxxx --concurrency=50 --iterations=4 --number-of-queries=300 --engine=innodb --auto-generate-sql
Benchmark
	Running for engine innodb
	Average number of seconds to run all queries: 1.873 seconds
	Minimum number of seconds to run all queries: 1.724 seconds
	Maximum number of seconds to run all queries: 2.197 seconds
	Number of clients running queries: 50
	Average number of queries per client: 6

Para poder personalizar al máximo el test de benchmarking conviene poder especificar la creación de tablas y consultas a realizar. Con

--create=

especificamos la creación de la tabla y con

--query=

la consulta a realizar. Este es el ejemplo disponible en la documentación de MySQL y el resultado de la prueba:

$ mysqlslap --delimiter=";" \
  --create="CREATE TABLE a (b int);INSERT INTO a VALUES (23)" \
  --query="SELECT * FROM a" --concurrency=50 --iterations=200
Benchmark
	Average number of seconds to run all queries: 0.038 seconds
	Minimum number of seconds to run all queries: 0.011 seconds
	Maximum number of seconds to run all queries: 0.061 seconds
	Number of clients running queries: 50
	Average number of queries per client: 1

Si no queremos introducir nuestras propias consultas SQL pero sí que queremos personalizar la creación de la tabla, podemos especificar parámetros como el número de columnas VARCHAR con

--number-char-cols

, el número de columnas INT con

--number-int-cols=

, etc.

Esta es una pequeña muestra de las posibilidades que nos brinda esta utilidad de MySQL y su gran utilidad para las pruebas de rendimiento de bases de datos en entornos de desarrollo y pre-producción. Si queréis profundizar más en las posibilidades de mysqlslap os recomiendo revisar la documentación de MySQL.

Optimización de WordPress (III): los Plugins


Siguiendo con los artículos de optimización de WordPress voy a indicar los que a mi parecer son los plugins más importantes en WordPress.

Hay que tener en cuenta que los plugins suelen ser el principal problema de utilización de recursos en WP, así que cuantos menos tengamos, mejor. Por eso conviene escoger con mucho cuidado los plugins a utilizar. Estos son los que personalmente recomiendo:

  • Clean Options Limpia de la base de datos restos de plugins antiguos y registros innecesarios en la tabla options, una de las más importantes de WP y que afectan directamente al rendimiento del sitio.
  • WP-Optimize: Permite optimizar la base de datos con un solo click así como eliminar revisiones de entradas y cambiar el nombre de usuario admin por uno personalizado.
  • WP Super Cache: Sin duda alguna el plugin más importante que existe en WordPress para sitios con una cantidad importante de visitas.
  • Akismet: Este plugin ya viene por defecto en WP y permite que tu blog no se llene de comentarios SPAM.

En relación con optimización estos son los cuatro plugins esenciales (a mi parecer). Por supuesto para otros objetivos como el SEO habría que seleccionar algún plugin más (WordPress Related Posts, All in One SEO Pack…).

Artículos anteriores sobre optimización de WordPress:

Optimización de WordPress: las cabeceras, fichero header.php

Optimización de WordPress: el fichero .htaccess

Optimización de WordPress (II): el fichero .htaccess


El fichero oculto .htaccess se utiliza en servidores web Apache, se encuentra en la raíz de nuestro sitio web y en él podemos configurar una serie de directivas de Apache sin necesidad de ser configuradas a nivel global en el servidor.

Entre otras cosas, podemos configurar sistemas de autenticación, url’s amigables, compresión del sitio web, etc. Para optimizar nuestro WordPress hoy añadiremos lo siguiente en dicho fichero:

Activación de caché por Apache con los módulos mod_expires y mod_headers

Antes de nada tenéis que aseguraros que el servidor web apache bajo el que está vuestro sitio web tiene compilados los módulos mod_expires y mod_headers.

El funcionamiento de este sistema es que podemos decir al navegador de la gente que visita nuestra web que ciertos ficheros (normalmente imagenes, css, javascript, etc) pueden ser cacheados durante un tiempo determinado. Si añadís el siguiente código al fichero .htaccess le diréis a los navegadores que cacheen durante un mes esos ficheros. Esto supone que la segunda vez que esta persona acceda a vuestra página no tendrá que volver a descargar las imágenes, css, javascript, etc lo que implica menor uso de transferencia de datos y mayor velocidad en el acceso web:

ExpiresActive On
ExpiresDefault A0
# expiracion de 1 mes para archivos estaticos
<FilesMatch "\.(gif|jpg|jpeg|png|swf|js|css|ico)$">
ExpiresDefault "access plus 1 months"
</FilesMatch>

Activación de compresión por Apache con el módulo mod_deflate

El módulo de Apache (apache 2) mod_deflate permite que el contenido que el servidor proporciona al cliente final (usuario) sea comprimido antes de ser enviado a través de la red. Esto supone que el tamaño de los datos enviados será mucho menor y por consiguiente la carga será más rápida. Hay que tener en cuenta que en ciertos servidores y ciertos tipos de web la activación de este sistema puede hacer que el uso de recursos en el servidor aumente así que conviene probarlo con cautela.

Para activarlo tendríais que añadir lo siguiente a vuestro fichero .htaccess, veréis que le decimos que sirva comprimidos los ficheros html, css y javascript:

# BEGIN GZIP
<ifmodule mod_deflate.c>
AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript
</ifmodule>
# END GZIP

Enlace al artículo anterior:

Optimización de WordPress: las cabeceras, fichero header.php

Optimización de WordPress (I): el fichero header.php


En esta serie de artículos intentaré ofrecer unos cuantos consejos para optimizar en la medida de lo posible aquellos blogs que utilizan WordPress.

Uno de los puntos flojos de WordPress es su excesivo uso de cpu, memoria y recursos de servidor en general, sobre todo con la inclusión de plugins, temas, etc. En este artículo vamos a empezar optimizando el fichero que genera la cabecera HTML del blog, header.php.

El objetivo de estos cambios es reducir el número de consultas MySQL y ejecución de llamadas PHP al servidor, haciendo lo más estática posible la cabecera de nuestro blog. Para ello, evitaremos que se llame a la base de datos para buscar el nombre del blog, la ubicación de los css, javascript o feed.

Lo primero que debemos hacer es encontrar el fichero header.php, que se encontrará en la carpeta del tema que usemos. Los temas están en la ruta “/wp-content/themes/”, en nuestro caso vamos a trabajar con un tema que se llama stardust, así que la ruta del fichero header.php es:

/wp-content/themes/stardust/header.php

Comenzamos con las modificaciones, empezamos configurando el título del blog de forma estática, eliminando la llamada php, que lo busca en la base de datos MySQL:

Antes:

<title><?php bloginfo('name'); ?><?php wp_title(); ?></title>

Después:

<title>Este es el título de mi blog</title>

Cambiamos también las declaraciones meta y el charset de la página, que siempre será igual (aunque no sepáis para que sirve, es seguro hacer este cambio):

Antes:

<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />

Después:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

La siguiente línea la podemos eliminar directamente:

<meta name="generator" content="WordPress <?php bloginfo('version'); ?>" /> <!-- leave this for stats please -->

Las llamadas a las rutas de los ficheros de estilos css también podemos configurarlas directamente:

Antes:

<link rel="stylesheet" type="text/css" href="<?php bloginfo('stylesheet_url'); ?>" media="screen" />

Después:

<link rel="stylesheet" type="text/css" href="/wp-content/themes/stardust/style.css" media="screen" />

Nota: Si no sabéis la ruta exacta al fichero css, podéis buscarlo por FTP (se llama style.css) dentro de la carpeta de vuestro tema o en el navegador pulsar Ctrl+U para ver el código fuente y buscar la línea anterior.

También podemos llamar de forma estática al fichero favicon.ico, que es el icono de favoritos y la página:

Antes:

<link rel="shortcut icon" href="<?php bloginfo('template_url'); ?>/favicon.ico" />

Después:

<link rel="shortcut icon" href="/wp-content/themes/stardust/favicon.ico" />

La URL para los pingback va a ser siempre la misma, con lo que también podemos modificara:

Antes:

<link rel="pingback" href="<?php bloginfo('pingback_url'); ?>" />

Después (cambiad miblog.es por vuestro blog):

<link rel="pingback" href="http://miblog.es/xmlrpc.php" />

También podemos configurar como estáticas las rutas a los ficheros javascript que utilicemos en el blog. Esto depende de cada blog y la ruta en la que estén, para orientaros, será algo así:

Antes:

<script type="text/javascript" src="<?php bloginfo('template_url'); ?>/js/miscript.js"></script>

Después:

<script type="text/javascript" src="/wp-content/themes/stardust/js/miscript.js"></script>

Con estos cambios hemos reducido drásticamente las llamadas php/mysql al servidor y por consiguiente aligerado en gran medida la rapidez de carga de nuestra web y su uso de recursos. Hay que tener en cuenta que cada tema puede variar y tener diferentes llamadas php, es cuestión de retocar la cabecera investigando el fichero según sus necesidades.