
⏰ 🔥 Un proxy TCP pour simuler des conditions réseau et système afin de tester le chaos et la résilience
Toxiproxy est un framework pour simuler des conditions réseau. Il est conçu spécifiquement pour les environnements de test, d'intégration continue (CI) et de développement, prenant en charge l'altération déterministe des connexions, mais aussi le chaos aléatoire et la personnalisation. Toxiproxy est l'outil dont vous avez besoin pour prouver par des tests que votre application n'a pas de points de défaillance uniques. Nous l'utilisons avec succès dans tous les environnements de développement et de test chez Shopify depuis octobre 2014. Voir notre [article de blog][blog] sur la résilience pour plus d'informations.
L'utilisation de Toxiproxy se compose de deux parties : un proxy TCP écrit en Go (ce que contient ce dépôt) et un client qui communique avec le proxy via HTTP. Vous configurez votre application pour que toutes les connexions de test passent par Toxiproxy et pouvez ensuite manipuler leur état via HTTP. Voir Utilisation ci-dessous pour savoir comment configurer votre projet.
Par exemple, pour ajouter 1000ms de latence à la réponse de MySQL depuis le client Ruby :```ruby Toxiproxy[:mysql_master].downstream(:latency, latency: 1000).apply do Shop.first # this takes at least 1s end
Pour faire tomber toutes les instances Redis:```ruby
Toxiproxy[/redis/].down do
Shop.first # this will throw an exception
end
While the examples in this README are currently in Ruby, there's nothing stopping you from creating a client in any other language (see Clients).
Les solutions existantes que nous avons trouvées ne fournissaient pas le type d'API dynamique dont nous avions besoin pour
les tests d'intégration et unitaires. Les outils Linux comme nc et autres ne sont pas
multi-plateformes et nécessitent les droits root, ce qui les rend problématiques dans les tests,
le développement et les environnements d'intégration continue.
Prenons un exemple avec une application Rails. Notez que Toxiproxy n'est en aucun cas lié à Ruby, ce n'était que notre premier cas d'usage. Vous pouvez voir l'exemple complet sur sirupsen/toxiproxy-rails-example. Pour commencer immédiatement, rendez-vous à la section Utilisation.
Pour notre blog populaire, pour une raison ou une autre, nous stockons les tags de nos articles dans
Redis et les articles eux-mêmes dans MySQL. Nous pourrions avoir une classe Post qui
inclut des méthodes pour manipuler les tags dans un Redis set :```ruby
class Post < ActiveRecord::Base
def tags TagRedis.smembers(tag_key) end
def add_tag(tag) TagRedis.sadd(tag_key, tag) end
def remove_tag(tag) TagRedis.srem(tag_key, tag) end
def tag_key "post:tags:#{self.id}" end end
Nous avons décidé qu'il est acceptable de lever une erreur lors de l'écriture dans le magasin de données de tags
(ajout/suppression). Cependant, si le magasin de données de tags est indisponible, nous devrions
pouvoir voir le post sans tags. Nous pourrions simplement intercepter l'erreur
`Redis::CannotConnectError` autour de l'appel Redis `SMEMBERS` dans la méthode
`tags`. Utilisons Toxiproxy pour tester cela.
Comme nous avons déjà installé Toxiproxy et qu'il tourne sur notre machine, nous pouvons
passer à l'étape 2. C'est là que nous devons nous assurer que Toxiproxy a un mappage pour
les tags Redis. Dans `config/boot.rb` (avant toute connexion) nous ajoutons:```ruby
require 'toxiproxy'
Toxiproxy.populate([
{
name: "toxiproxy_test_redis_tags",
listen: "127.0.0.1:22222",
upstream: "127.0.0.1:6379"
}
])
Ensuite, dans config/environments/test.rb, nous définissons TagRedis comme un client Redis
qui se connecte à Redis via Toxiproxy en ajoutant cette ligne :```ruby
TagRedis = Redis.new(port: 22222)
Tous les appels dans l'environnement de test passent désormais par Toxiproxy. Cela signifie que nous pouvons
ajouter un test unitaire où nous simulons une panne :```ruby
test "should return empty array when tag redis is down when listing tags" do
@post.add_tag "mammals"
# Take down all Redises in Toxiproxy
Toxiproxy[/redis/].down do
assert_equal [], @post.tags
end
end
Le test échoue avec Redis::CannotConnectError. Parfait ! Toxiproxy a arrêté
Redis avec succès pendant la durée de la fermeture. Corrigeons la méthode tags
pour qu'elle soit résiliente :```ruby
def tags
TagRedis.smembers(tag_key)
rescue Redis::CannotConnectError
[]
end
Les tests passent ! Nous avons désormais un test unitaire qui prouve que la récupération des tags lorsque Redis est indisponible renvoie un tableau vide, au lieu de lever une exception. Pour une couverture complète, vous devriez également écrire un test d'intégration qui couvre la récupération de la page entière de l'article de blog lorsque Redis est indisponible.
L'application d'exemple complète se trouve à
[sirupsen/toxiproxy-rails-example](https://github.com/sirupsen/toxiproxy-rails-example).
## Utilisation
La configuration d'un projet pour utiliser Toxiproxy comprend trois étapes :
1. Installer Toxiproxy
2. Peupler Toxiproxy
3. Utiliser Toxiproxy
### 1. Installer Toxiproxy
**Linux**
Consultez [`Releases`](https://github.com/Shopify/toxiproxy/releases) pour les derniers binaires et paquets système pour votre architecture.