{"id":154,"date":"2015-12-31T09:10:15","date_gmt":"2015-12-31T08:10:15","guid":{"rendered":"http:\/\/www.jacquescortes.fr\/blog\/?p=154"},"modified":"2016-01-05T22:56:48","modified_gmt":"2016-01-05T21:56:48","slug":"api-throttling-et-rate-limiting","status":"publish","type":"post","link":"http:\/\/www.jacquescortes.fr\/blog\/2015\/12\/api-throttling-et-rate-limiting\/","title":{"rendered":"API throttling et rate limiting"},"content":{"rendered":"<p>Nous allons aujourd&rsquo;hui aborder\u00a02 concepts : l&rsquo;API throttling et le rate limiting.<\/p>\n<p>Le premier sert \u00e0 prot\u00e9ger d&rsquo;un trop grand nombre de requ\u00eates simultan\u00e9es sur une API REST par exemple, ou tout serveur HTTP et m\u00eame cluster de serveurs HTTP (au niveau du load balancer).<\/p>\n<p>Le deuxi\u00e8me sert \u00e0 s&rsquo;auto-limiter en se fixant un nombre maximum d&rsquo;actions par p\u00e9riode donn\u00e9e.<br \/>\nCela peut \u00eatre un nombre d&rsquo;octets par seconde pour limiter l&rsquo;usage de bande passante ou bien un nombre de requ\u00eates par minute vers un r\u00e9f\u00e9rentiel commun au SI qui n&rsquo;a pas lui m\u00eame une protection avec une gestion de quota par exemple.<\/p>\n<h1>API throttling<\/h1>\n<p>&nbsp;<\/p>\n<h2>C\u00f4t\u00e9 serveur<\/h2>\n<p>Dans la conception d&rsquo;une API REST, il est bien dans les tests de charge de mesurer la limite du nombre de requ\u00eates simultan\u00e9es que peut accepter la plateforme et de mettre en place un syst\u00e8me emp\u00eachant de d\u00e9passer cette limite pour ne pas d\u00e9grader le fonctionnement pour l&rsquo;ensemble des utilisateurs.<\/p>\n<p>L&rsquo;exemple classique est l&rsquo;application mobile qui suite \u00e0 un coup de pub re\u00e7oit un succ\u00e8s non pr\u00e9vu.<br \/>\nSi rien n&rsquo;est fait, les utilisateurs vont constater des dysfonctionnements tels qu&rsquo;ils risquent de ne plus revenir.<br \/>\nDes dysfonctionnements du genre login particuli\u00e8rement long (plus d&rsquo;une minute), double d\u00e9bit sur la carte bleue lors d&rsquo;un paiement, etc&#8230;<br \/>\nLe plus sage est de mettre en place un syst\u00e8me qui va r\u00e9pondre un code d&rsquo;erreur HTTP lors du d\u00e9passement de la limite.<br \/>\nLe code HTTP pr\u00e9vu pour \u00e7a est le code <strong>429 Too many requests<\/strong>.<\/p>\n<p><a href=\"http:\/\/www.jacquescortes.fr\/blog\/2015\/12\/api-throttling-et-rate-limiting\/attachment\/429\/\" rel=\"attachment wp-att-155\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-155\" src=\"http:\/\/www.jacquescortes.fr\/blog\/wp-content\/uploads\/2015\/12\/429-300x240.jpg\" alt=\"HTTP 429 Too Many Requests\" width=\"493\" height=\"394\" srcset=\"http:\/\/www.jacquescortes.fr\/blog\/wp-content\/uploads\/2015\/12\/429-300x240.jpg 300w, http:\/\/www.jacquescortes.fr\/blog\/wp-content\/uploads\/2015\/12\/429.jpg 750w\" sizes=\"auto, (max-width: 493px) 100vw, 493px\" \/><\/a><\/p>\n<p>Cette erreur est pr\u00e9vue dans la\u00a0<a href=\"http:\/\/tools.ietf.org\/html\/rfc6585#page-3\">RFC 6585<\/a> <em>Additional HTTP Status Codes<\/em>.<\/p>\n<p>Petit extrait :<\/p>\n<blockquote><p>The 429 status code indicates that the user has sent too many requests in a given amount of time (\u00ab\u00a0rate limiting\u00a0\u00bb).<\/p>\n<p>The response representations SHOULD include details explaining the condition, and MAY include a Retry-After header indicating how long to wait before making a new request&#8230;<\/p>\n<p>Note that this specification does not define how the origin server identifies the user, nor how it counts requests.\u00a0For example, an origin server that is limiting request rates can do so based upon counts of requests on a per-resource basis, across the entire server, or even among a set of servers.\u00a0Likewise, it might identify the user by its authentication credentials, or a stateful cookie.<\/p>\n<p>Responses with the 429 status code MUST NOT be stored by a cache&#8230;<code><br \/>\n<\/code><\/p><\/blockquote>\n<p>Il y a diff\u00e9rentes fa\u00e7ons d&rsquo;impl\u00e9menter une\u00a0limitation.<br \/>\nLe plus simple est le param\u00e9trage du load balancer s&rsquo;il dispose de cette fonctionnalit\u00e9.<br \/>\nPar exemple pour <strong>HAProxy<\/strong> :\u00a0<a href=\"https:\/\/blog.codecentric.de\/en\/2014\/12\/haproxy-http-header-rate-limiting\/\" target=\"_blank\">https:\/\/blog.codecentric.de\/en\/201n4\/12\/haproxy-http-header-rate-limiting\/<br \/>\n<\/a><\/p>\n<p>On peut aussi le faire au niveau des serveurs HTTP Apache frontaux avec un module. Il en existe des tout faits, mais on peut aussi en d\u00e9velopper un custom sur mesure qui \u00e0 l&rsquo;aide d&rsquo;un serveur memcached (ou Redis&#8230;) va centraliser pour l&rsquo;ensemble des serveurs Apache les donn\u00e9es d&rsquo;usage par utilisateur, IP ou tout autre identifiant qui peut \u00eatre g\u00e9r\u00e9 par cookie par exemple.<\/p>\n<p>L&rsquo;int\u00e9r\u00eat d&rsquo;un module sur mesure est de permettre de g\u00e9rer l&rsquo;ensemble des r\u00e8gles de limitation qui peuvent exister.<br \/>\nPar exemple :<\/p>\n<ul>\n<li>Limitation globale bas\u00e9e sur le temps : 10000 requ\u00eates par seconde<\/li>\n<li>Limitation pour un service en particulier : 100 appel du POST \/ressource\/client par seconde<\/li>\n<li>Limitation pour une cat\u00e9gorie ou une liste d&rsquo;utilisateurs : limitations diff\u00e9rentes pour les utilisateurs non authentifi\u00e9s<\/li>\n<li>Combinaison des 3<\/li>\n<li>Limitation par seconde \/ minute \/ heure \/ jour \/ semaine \/ mois \/ ann\u00e9e : 1 requ\u00eate par seconde<\/li>\n<li>Combinaison : maximum 1 requ\u00eate par seconde et 10000 par mois<\/li>\n<li>Limitation bas\u00e9e sur le volume : 10Mo en upload ou en download par heure<\/li>\n<li>Limitation en nombre de r\u00e9ponse : 200 r\u00e9sultats max par requ\u00eate et 5000 r\u00e9sultats par jour<\/li>\n<\/ul>\n<p>Certaines limitations servent plus \u00e0 limiter l&rsquo;usage pour \u00e9viter les abus qu&rsquo;\u00e0 prot\u00e9ger les serveurs de la surcharge.<br \/>\nCa peut aussi permettre de mettre en place une facturation par pallier.<\/p>\n<h2>C\u00f4t\u00e9 client<\/h2>\n<p>Du c\u00f4t\u00e9 du client, par exemple dans une application mobile qui appelle des services REST, il faut g\u00e9rer le code HTTP 429 comme une demande d&rsquo;attendre avant de retenter la requ\u00eate.<br \/>\nLe code HTTP 429 peut \u00eatre accompagn\u00e9 par le header Retry-After indiquant le temps d&rsquo;attente sugg\u00e9r\u00e9.<br \/>\nL&rsquo;application doit \u00e9galement g\u00e9rer un nombre de tentatives maximum afin de rendre la main ou bien afficher un message d&rsquo;erreur \u00e0 l&rsquo;utilisateur ou bien passer en mode d\u00e9grad\u00e9 ou offline \/ asynchrone.<\/p>\n<p>&nbsp;<\/p>\n<h1>Rate limiting<\/h1>\n<p>Le rate limiting, c&rsquo;est un peu dans l&rsquo;autre sens, l&rsquo;auto-limitation de l&rsquo;usage d&rsquo;une ressource ou bien d&rsquo;une bande passante.<br \/>\nPar exemple, pour un batch devant tourner en pleine journ\u00e9e, on va pouvoir limiter son rythme de requ\u00eatage \u00e0 une API pour laisser la priorit\u00e9 aux vrais utilisateurs.<\/p>\n<p>En Java, la librairie Google Guava offre la classe RateLimiter pour impl\u00e9menter une limite par seconde :\u00a0<a href=\"http:\/\/docs.guava-libraries.googlecode.com\/git\/javadoc\/com\/google\/common\/util\/concurrent\/RateLimiter.html\" target=\"_blank\" class=\"broken_link\">http:\/\/docs.guava-libraries.googlecode.com\/git\/javadoc\/com\/google\/common\/util\/concurrent\/RateLimiter.html<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nous allons aujourd&rsquo;hui aborder\u00a02 concepts : l&rsquo;API throttling et le rate limiting. Le premier sert \u00e0 prot\u00e9ger d&rsquo;un trop grand nombre de requ\u00eates simultan\u00e9es sur une API REST par exemple, ou tout serveur HTTP et m\u00eame cluster de serveurs HTTP (au niveau du load balancer). Le deuxi\u00e8me sert \u00e0 s&rsquo;auto-limiter en se fixant un nombre [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":155,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[],"series":[],"class_list":{"0":"post-154","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-api","8":"czr-hentry"},"_links":{"self":[{"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/posts\/154","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/comments?post=154"}],"version-history":[{"count":9,"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/posts\/154\/revisions"}],"predecessor-version":[{"id":185,"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/posts\/154\/revisions\/185"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/media\/155"}],"wp:attachment":[{"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/media?parent=154"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/categories?post=154"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/tags?post=154"},{"taxonomy":"series","embeddable":true,"href":"http:\/\/www.jacquescortes.fr\/blog\/wp-json\/wp\/v2\/series?post=154"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}