web-dev-qa-db-fra.com

Servir des actifs précompilés avec nginx

Est-il possible de servir des actifs précompilés directement avec nginx? Servir les actifs de manière dynamique avec Rails est 20 fois plus lent (4000 req/sec vs 200 req/sec dans ma virtualbox).

Je suppose que cela peut être fait avec une règle de réécriture dans nginx.conf. Le problème est, cependant, que ces noms de fichiers incluent le hachage md5 du contenu, donc je ne comprends pas vraiment ce qui peut être fait avec cela.

Si ce n'est pas possible, je ne comprends pas l'idée avec Rails 3.1 pipelines d'actifs. Réduire la bande passante client et le temps de chargement des pages au prix de la charge du serveur x20?

Des idées?

UPD: Donc, j'ai réussi à configurer mon nginx et Rails en quelque sorte, quand tout dans mon application est servi à la vitesse de ~ 3500-4000 requêtes/sec .

Tout d'abord, j'ai ajouté deux hôtes virtuels, l'un servant de proxy de mise en cache à un autre et j'ai découvert que les actifs étaient servis à la vitesse que je souhaitais (4k). Ensuite, j'ai connecté mon Rails application avec memcached (rien de spécial jusqu'à présent, une seule ligne dans application.rb: ActionController::Base.cache_store = :mem_cache_store, "localhost")

Ensuite, j'ai ajouté des choses comme expires_in 1.hour, :public => true if !signed_in?; à mes contrôleurs pour changer la politique de mise en cache par défaut de Rails contenu et augmentation de la vitesse d'environ 500 requêtes/seconde pour mes pages dynamiques (avant cela, c'était près de 200, et c'était ~ 50 avant de commencer tout ça).

Maintenant, lorsque mes fichiers de configuration nginx ressemblent à ceci:

nginx.conf:

...
proxy_cache_path  /tmp/blog keys_zone=one:8m max_size=1000m inactive=600m;
proxy_temp_path /tmp;
gzip  off;
include /opt/nginx/conf/sites-enabled/*;

sites/blog:

server {
        listen   8080;
        server_name  blindsight;

        root   /home/mike/Rails/blog/public;
        Rails_env production;

        # serve static content directly
        location ~* \.(ico|jpg|gif|png|swf|html)$ {
          if (-f $request_filename) {
            expires max;
            break;
          }
        }

        passenger_enabled on;

        location ~ /\.ht {
          deny  all;
        }
}

sites-activé/principal:

server {

    listen   80;
    server_name  blindsight;

    location /authorize
    {
       proxy_pass_header Cookie;
       proxy_pass_header Set-Cookie;
       proxy_pass http://127.0.0.1:8080;
    }

    location /admin
    {
       proxy_pass_header Set-Cookie;
       proxy_pass_header Cookie;
       proxy_pass http://127.0.0.1:8080;
    }

    location / {
    root /home/mike/Rails/blog/public;

        # All POST requests go directly
        if ($request_method = POST) {
          proxy_pass http://127.0.0.1:8080;
          break;
        }

    proxy_redirect off;
    proxy_pass_header Cookie;
    proxy_ignore_headers Set-Cookie;
    proxy_hide_header Set-Cookie;
    proxy_set_header Host $Host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_cache one;
    proxy_cache_key blog$request_uri;
    proxy_cache_valid 200 302  5s;
    proxy_cache_valid 404      1m;
    proxy_pass http://127.0.0.1:8080;

    }

Tout est rapide comme un éclair sanglant :) Merci les gars.

35
Jake Jones

Bien que je n'ai pas d'expérience de travail avec Rails, je suppose que vous utilisez nginx + passager avec la directive proxy_pass. Il semble que vos "actifs statiques" aient des URL dynamiques pour servir les actifs, ce qui vous empêche de configurer nginx pour servir le contenu directement à partir de nginx via des chemins d'emplacement spécialisés comme l'extrait de code suivant:

#  static content
location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|xml)$ {
  # access_log        off;
  expires           15d;
}

Si c'est correct, mon conseil est d'essayer d'utiliser la directive proxy_cache de nginx. Cela vous permettra de contrôler la fréquence à laquelle nginx va au passager pour "régénérer" la réponse nginx enregistrée précédemment demandée et mise en cache. Cette réponse de panne de serveur devrait vous aider à démontrer l'utilisation. Avec proxy_cache, vous pouvez mettre en cache toute réponse telle que des images générées dynamiquement ou même simplement du contenu json/javascript/html.

Vous pouvez également essayer le module memcached , qui vous donnera un contrôle plus fin sur la mise en cache. L'inconvénient est que vous devez réellement pousser vos fichiers dans memcache avec du code pour le remplir. L'avantage est que vous pouvez mettre en cache votre contenu de manière centralisée dans une sorte de cluster memcached.

12
pcting

Après d'en haut avec quelques bits supplémentaires, j'ai glané de l'interweb:

Pour Rails 3.1:

location ~* ^/assets/ {
    # Per RFC2616 - 1 year maximum expiry
    # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
    expires 1y;
    add_header Cache-Control public;

    # Some browsers still send conditional-GET requests if there's a
    # Last-Modified header or an ETag header even if they haven't
    # reached the expiry date sent in the Expires header.
    add_header Last-Modified "";
    add_header ETag "";
    break;
}

Pour Rails 3.0 utilisation

location ~* ^/(images|javascripts|stylesheets)/ {
    ... copy block from above ...
}
35
Ben Walding

Essayez d'ajouter ceci à votre configuration NGINX:

 serveur {
 
 ... 
 
 emplacement ~ * ^/actifs {
 expire au maximum; 
 add_header Cache-Control public; 
 pause; 
} 
 
 ... 
 
} 
6
bodacious

Eh bien, je sais que c'est une vieille question, mais le passager autonome le fait comme suit:

    # Rails asset pipeline support.
    location ~ ^/assets/ {
        error_page 490 = @static_asset;
        error_page 491 = @dynamic_request;
        recursive_error_pages on;

        if (-f $request_filename) {
            return 490;
        }
        if (!-f $request_filename) {
            return 491;
        }
    }
    location @static_asset {
        gzip_static on;
        expires max;
        add_header Cache-Control public;
        add_header ETag "";
    }
    location @dynamic_request {
        passenger_enabled on;
    }
2
James Lim

vous devriez peut-être exécuter rake assets:precompile Il collera les actifs précompilés sous/public/assets /

1
Tom van Leeuwen