GNU/Linux, Open Source, Cloud Computing, DevOps y más...

Uso excesivo de CPU al convertir imágenes con ImageMagick

No hay comentarios

En ciertas versiones de ImageMagick se da el problema (seguramente debido a un bug) de que cuando se intenta convertir o manipular una imagen, ya sea desde la línea de comandos (comando convert) o a través de una de las numerosas API’s existentes (por ejemplo PHP), el uso de CPU se dispara más allá del 100% (debido a que este problema se da en sistemas multiprocesador) haciendo que nuestro sistema se vuelva tremendamente lento. Aparte de este uso excesivo de CPU, el proceso de conversión se queda bloqueado, no alcanzando a terminar nunca. Esto ocurre incluso con imágenes pequeñas con un tamaño de pocos kilobytes.

Tras investigar el problema, he llegado a la conclusión de que efectivamente se trata de un bug en las versiones de ImageMagick compiladas con la opción –enable-openmp en máquinas con varios procesadores o varios cores.


Error: Your Requested widget " ai_widget-6" is not in the widget list.
  • [do_widget_area above-nav-left]
    • [do_widget_area above-nav-right]
      • [do_widget_area footer-1]
        • [do_widget id="wpp-4"]
      • [do_widget_area footer-2]
        • [do_widget id="recent-posts-4"]
      • [do_widget_area footer-3]
        • [do_widget id="recent-comments-3"]
      • [do_widget_area footer-4]
        • [do_widget id="archives-4"]
      • [do_widget_area logo-bar]
        • [do_widget id="oxywidgetwpml-3"]
      • [do_widget_area menu-bar]
        • [do_widget id="search-3"]
      • [do_widget_area sidebar]
        • [do_widget id="search-4"]
        • [do_widget id="ai_widget-2"]
        • [do_widget id="categories-5"]
        • [do_widget id="ai_widget-3"]
        • [do_widget id="ai_widget-4"]
        • [do_widget id="ai_widget-5"]
      • [do_widget_area sub-footer-1]
        • [do_widget id="text-4"]
      • [do_widget_area sub-footer-2]
        • [do_widget_area sub-footer-3]
          • [do_widget_area sub-footer-4]
            • [do_widget_area upper-footer-1]
              • [do_widget id="search-2"]
              • [do_widget id="recent-posts-2"]
              • [do_widget id="recent-comments-2"]
              • [do_widget id="archives-2"]
              • [do_widget id="categories-2"]
              • [do_widget id="meta-2"]
            • [do_widget_area upper-footer-2]
              • [do_widget_area upper-footer-3]
                • [do_widget_area upper-footer-4]
                  • [do_widget_area widgets_for_shortcodes]
                    • [do_widget id="search-5"]
                    • [do_widget id="ai_widget-6"]
                  • [do_widget_area wp_inactive_widgets]
                    • [do_widget id="wpp-2"]
                    • [do_widget id="text-1"]
                    • [do_widget id="recent-posts-3"]
                    • [do_widget id="categories-3"]
                    • [do_widget id="archives-3"]
                    • [do_widget id="icl_lang_sel_widget-3"]

                  Por tanto, lo primero que debemos hacer para saber si la solución de este artículo nos servirá, es comprobar si la máquina dispone de varios procesadores o de varios núcleos: Cómo saber cuántos procesadores y núcleos tiene una máquina Linux.

                  A continuación comprobaremos si nuestra versión de ImageMagick tiene activada la característica OpenMP.

                  ~# convert --version
                  Version: ImageMagick 6.5.7-8 2010-12-02 Q16 https://www.imagemagick.org
                  Copyright: Copyright (C) 1999-2009 ImageMagick Studio LLC
                  Features: OpenMP 
                  

                  Si el comando anterior muestra la línea «Features: OpenMP», entonces todo encaja y nuestro problema de carga excesiva de CPU puede solucionarse de tres formas distintas:

                  1. Actualizando a una nueva versión de ImageMagick o a una anterior suficientemente estable que no presente el bug causante del problema.
                  2. Recompilando ImageMagick con la opción –disable-openmp para que no se haga uso de la característica de multiprocesador.
                  3. Forzando a ImageMagick a utilizar sólo uno de los núcleos disponibles en el sistema para realizar la conversión.

                  Esta última es quizás la mejor solución a nuestro problema, pues probablemente ya habremos probado a actualizar ImageMagick a otra versión, y en muchos casos lo habremos instalado como un paquete de alguna de las distribuciones Linux disponibles, por lo que no nos resultará viable volver a compilar. Hay que destacar que el procedimiento que se mostrará a continuación realmente no soluciona el problema, sino que se trata de un workaround, un «truco» que nos permitirá utilizar ImageMagick sin que se reproduzca el mal uso de los recursos del sistema.


                  Error: Your Requested widget " ai_widget-6" is not in the widget list.
                  • [do_widget_area above-nav-left]
                    • [do_widget_area above-nav-right]
                      • [do_widget_area footer-1]
                        • [do_widget id="wpp-4"]
                      • [do_widget_area footer-2]
                        • [do_widget id="recent-posts-4"]
                      • [do_widget_area footer-3]
                        • [do_widget id="recent-comments-3"]
                      • [do_widget_area footer-4]
                        • [do_widget id="archives-4"]
                      • [do_widget_area logo-bar]
                        • [do_widget id="oxywidgetwpml-3"]
                      • [do_widget_area menu-bar]
                        • [do_widget id="search-3"]
                      • [do_widget_area sidebar]
                        • [do_widget id="search-4"]
                        • [do_widget id="ai_widget-2"]
                        • [do_widget id="categories-5"]
                        • [do_widget id="ai_widget-3"]
                        • [do_widget id="ai_widget-4"]
                        • [do_widget id="ai_widget-5"]
                      • [do_widget_area sub-footer-1]
                        • [do_widget id="text-4"]
                      • [do_widget_area sub-footer-2]
                        • [do_widget_area sub-footer-3]
                          • [do_widget_area sub-footer-4]
                            • [do_widget_area upper-footer-1]
                              • [do_widget id="search-2"]
                              • [do_widget id="recent-posts-2"]
                              • [do_widget id="recent-comments-2"]
                              • [do_widget id="archives-2"]
                              • [do_widget id="categories-2"]
                              • [do_widget id="meta-2"]
                            • [do_widget_area upper-footer-2]
                              • [do_widget_area upper-footer-3]
                                • [do_widget_area upper-footer-4]
                                  • [do_widget_area widgets_for_shortcodes]
                                    • [do_widget id="search-5"]
                                    • [do_widget id="ai_widget-6"]
                                  • [do_widget_area wp_inactive_widgets]
                                    • [do_widget id="wpp-2"]
                                    • [do_widget id="text-1"]
                                    • [do_widget id="recent-posts-3"]
                                    • [do_widget id="categories-3"]
                                    • [do_widget id="archives-3"]
                                    • [do_widget id="icl_lang_sel_widget-3"]

                                  Limitar el número de núcleos utilizado con MAGICK_THREAD_LIMIT

                                  La forma de obligar a ImageMagick a utilizar un sólo núcleo o procesador a la hora de realizar una conversión de una imagen es utilizando la variable de entorno MAGICK_THREAD_LIMIT. Esta variable debe tener el valor 1 y estar disponible en el entorno de ejecución del comando convert. Para ello editaremos el fichero añadiremos al fichero /etc/environment la línea MAGICK_THREAD_LIMIT=1:

                                  ~# cat /etc/environment
                                  PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
                                  LANG="es_ES.UTF-8"
                                  LANGUAGE="es_ES.UTF-8"
                                  MAGICK_THREAD_LIMIT=1
                                  

                                  A continuación abriremos una nueva shell de comandos, ya que la actual no cargará dicha variable de entorno hasta que volvamos a iniciar sesión en el sistema.

                                  Cómo establecer la variable MAGICK_THREAD_LIMIT en PHP

                                  Si en lugar de utilizar ImageMagick desde la línea de comandos lo hacemos a través de las librerías disponibles para distintos lenguajes de programación como PHP, la solución anterior no funcionará y tendremos que cargar la variable MAGICK_THREAD_LIMIT=1 en el entorno de ejecución del intérprete PHP.

                                  Me estoy refiriendo siempre al caso de utilizar las funciones nativas que utilizaremos en nuestro código, como «$im = new Imagick(«file.png»);» o «$im->readImageBlob($svgin);», ya que si realizamos la conversión a través del comando «system(‘convert -resize 800×600 file1.png file2.png’);» estaremos llamando al comando convert del mismo modo que en el apartado anterior, en cuyo caso la solución sí es válida.

                                  PHP desde la línea de comandos

                                  env MAGICK_THREAD_LIMIT=1 php test.php
                                  

                                  PHP ejecutado desde módulo mod_fcgid de Apache

                                  En este caso cargaríamos la variable MAGICK_THREAD_LIMIT del comando /usr/bin/php5-cgi, que normalmente es ejecutado por un script intermedio correspondiente a un virtualhost concreto de Apache, el llamado FCGIWrapper que podremos encontrar en el fichero vhosts.conf correspondiente:

                                  <Files ~ (\.php)>
                                     SetHandler fcgid-script
                                     FCGIWrapper /var/www/cgi-bin/cgi_wrapper/cgi_wrapper .php
                                     Options +ExecCGI
                                     allow from all
                                  </Files>
                                  

                                  ~# cat /var/www/cgi-bin/cgi_wrapper/cgi_wrapper
                                  #! /bin/sh
                                  export MAGICK_THREAD_LIMIT=1
                                  exec /usr/bin/php5-cgi
                                  
                                   

                                  Sobre el autor

                                  Daniel López Azaña
                                  Arquitecto de soluciones Cloud AWS & Linux Sysadmin Freelance

                                  Emprendedor, generador de ideas y mente inquieta. Apasionado de las nuevas tecnologías, especialmente de los sistemas Linux y del software libre. Me gusta escribir además sobre actualidad tecnológica, Cloud Computing, AWSi, DevOps, DevSecOps, seguridad, desarrollo web y programación, SEO, ciencia, innovación, emprendimiento, etc.

                                  DanielUso excesivo de CPU al convertir imágenes con ImageMagick

                                  Artículos relacionados

                                  Deja una respuesta

                                  Tu dirección de correo electrónico no será publicada.