Quantcast
Channel: Blog Ippon - Ippon Technologies
Viewing all 938 articles
Browse latest View live

Une gestion des Authorizations sur mesure avec Spring

$
0
0
Une gestion des Authorizations sur mesure avec Spring

Quand on parle de gestion des authorizations on pense souvent RBAC (Role-Based Access Control). Cette stratégie est tout à fait viable pour différencier les utilisateurs des membres du staff (avec des droits plus élevés). Cependant, on en atteint rapidement les limites lorsque l'on souhaite restreindre les actions des utilisateurs à certaines ressources (pour éviter que tout le monde puisse modifier les données de tout le monde par exemple).

L'idée de cet article est de vous présenter un moyen de gérer ce type d'authorizations dans une application Spring Boot tout en gardant quelque chose qui soit simplement maintenable et utilisable.

Bien qu'il contienne des exemples de code, le but de cet article n'est pas de fournir une solution toute faite puisque cette gestion doit être adaptée à vos besoins. Pour cette raison l'implémentation fournie n'est pas utilisable directement (puisque je ne donne pas toutes les implémentations, les dépendances ou les tests).

Stratégie globale

Autant que faire se peut la vérification des authorizations doit se faire en dehors des traitements métier ; dans du code dédié. Spring Security propose depuis très longtemps une décoration des méthodes avec l'annotation @PreAuthorize : c'est ce que nous allons utiliser ici.

Vous pouvez aussi utiliser très simplement @Secured si votre besoin est de simplement vérifier les rôles et groupes de l'utilisateur ou les annotations de la JSR250 mais ce ne sera pas le sujet de cet article.
A plusieurs reprises je vais utiliser le terme application service : ce sont des services qui ne sont chargés que de l'orchestration des opérations. Il ne font pas de traitements métier.

Pour cet article nous allons donc utiliser @PreAuthorize dans une application

  • où les utilisateurs peuvent faire certaines actions (en fonction de leur rôles) sur des groupes d'objets. Les règles métier à appliquer pour savoir qui a accès à quels objets changent pour chaque type d'objets,
  • où on ne manipule pas de types primitifs (ou de String) en entrée des méthodes des applications services mais uniquement des types dédiés (par exemple on n’aura pas un String avec le login de la personne mais un objet Username),
  • où la sécurisation est faite en entrée des applications services.

Si votre projet n'a pas ces pré-requis l'article est quand même tout à fait applicable, je devais simplement faire des choix :).

Comment gérer qui peut faire quoi ?

Il est très courant de vérifier la possibilité de faire une action en se basant directement sur les rôles de l'utilisateur connecté. Je n'aime pas cette stratégie !

Dans ma compréhension un rôle doit donner accès à une liste d'actions possibles, je vais donc préférer associer les rôles à des actions et vérifier la possibilité de faire une action. De cette manière il sera bien plus simple de comprendre le contenu des @PreAuthorize mais il sera aussi plus simple de créer de nouveaux rôles pouvant faire des sous-ensembles d'actions.

En combinant la possibilité de faire une action avec les accès à une ressource nous allons pouvoir couvrir une part importante des besoins de vérification d'accès de notre application.

Choix d'une implémentation par type d'objet

Nous devons maintenant trouver un moyen de fournir une implémentation par type d'objet sur lequel l'accès doit être validé. Commençons par définir une interface :

import org.springframework.security.core.Authentication;

@FunctionalInterface
public interface CanChecker<T> {
  /**
  * Checks if the authenticated user can access the item.
  *
  * @param authentication
  *          authenticated user information
  * @param action
  *          action to check
  * @param item
  *          element to check action possibility on to
  * @return true is the user can do the action on the resource, false otherwise
  */
  boolean can(Authentication authentication, String action, T item);
}

Nous retrouvons bien nos notions : est-ce que l'utilisateur connecté peut faire une action sur un objet.

Nous pouvons maintenant écrire une class pour sélectionner l'implémentation correspondant à un objet donné et faire la vérification d'accès :

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

@Service
class CanEvaluator {
  private static final Logger logger = LoggerFactory.getLogger(CanEvaluator.class);
  private final ObjectChecker defaultEvaluator;
  private final Map<Class<?>, CanChecker<?>> evaluators;

  public CanEvaluator(List<CanChecker<?>> checkers) {
    evaluators = checkers.stream().collect(Collectors.toMap(this::getCheckerResourceClass, checker -> checker));
    logger.info("Authorized types: {}",
        evaluators.keySet().stream().map(Class::getName).collect(Collectors.joining(", ")));
    defaultEvaluator = (ObjectChecker) evaluators.get(Object.class);
    // Here you should ensure that you have a default evaluator :)
  }

  private Class<?> getCheckerResourceClass(CanChecker<?> checker) {
    Class<?> checkerClass = findCheckerClass(checker);
    return (Class<?>) ((ParameterizedType) streamParameterizedTypes(checkerClass)
        .filter(type -> ((ParameterizedType) type).getRawType().equals(CanChecker.class))
        .findFirst()
        .get()).getActualTypeArguments()[0];
  }

  private Class<?> findCheckerClass(CanChecker<?> checker) {
    Class<?> checkerClass = checker.getClass();
    while (Arrays.stream(checkerClass.getInterfaces()).noneMatch(interf -> CanChecker.class.equals(interf))) {
      checkerClass = checkerClass.getSuperclass();
    }
    return checkerClass;
  }

  private Stream<Type> streamParameterizedTypes(Class<?> checkerClass) {
    return Arrays.stream(checkerClass.getGenericInterfaces()).filter(type -> type instanceof ParameterizedType);
  }

  public boolean can(Authentication authentication, String action, Object item) {
    return evaluators.getOrDefault(item.getClass(), defaultEvaluator).canOnObject(authentication, action, item);
  }
}

Pour pouvoir faire cette implémentation j'ai dû ajouter une méthode dans l'interface CanChecker :

@SuppressWarnings("unchecked")
default boolean canOnObject(Authentication authentication, String action, Object item) {
  return can(authentication, action, (T) item);
}

Ce n'est pas très élégant mais, de cette manière, vos implémentations seront directement appelées avec des objets du type qu'elles gèrent.

Il nous manque aussi l'implémentation par défaut, j'ai choisi de bloquer les actions par défaut :

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
 
@Service
class ObjectChecker implements CanChecker<Object> {
  private static final Logger logger = LoggerFactory.getLogger(ObjectChecker.class);
 
  @Override
  public boolean can(Authentication authentication, String action, Object item) {
    logger.error("Error checking rights, falled back to default handler for action {} on class {}", action, getItemClass(item));
 
    return false;
  }
 
  private String getItemClass(Object item) {
    if (item == null) {
      return "unknown";
    }
 
    return item.getClass().getName();
  }
}

Maintenant que nous avons ce mécanisme de résolution d'un CanChecker pour un type d'objet nous pouvons utiliser cela depuis les @PreAuthorize.

Branchement à Spring

La première chose dont nous allons avoir besoin est de redéfinir notre SecurityExpressionRoot :

import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.core.Authentication;
 
class MyMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
  private final CanEvaluator evaluator;
 
  private Object filterObject;
  private Object returnObject;
  private Object target;
 
  public MyMethodSecurityExpressionRoot(Authentication authentication, CanEvaluator evaluator) {
    super(authentication);
    this.evaluator = evaluator;
  }
 
  @Override
  public void setFilterObject(Object filterObject) {
    this.filterObject = filterObject;
  }
 
  @Override
  public Object getFilterObject() {
    return filterObject;
  }
 
  @Override
  public void setReturnObject(Object returnObject) {
    this.returnObject = returnObject;
  }
 
  @Override
  public Object getReturnObject() {
    return returnObject;
  }
 
  void setThis(Object target) {
    this.target = target;
  }
 
  @Override
  public Object getThis() {
    return target;
  }
 
  public boolean can(String action, Object item) {
    return evaluator.can(getAuthentication(), action, item);
  }
}

Le but ici est d'invoquer la méthode can lorsque l'on utilisera @PreAuthorize("can('action', #item)"). Vous pouvez donc changer la signature comme vous le souhaitez pour correspondre à vos besoins. Vous pouvez par exemple ajouter une clé pour le type de ressource et sélectionner votre CanChecker (ou équivalent) non pas en fonction du type mais en fonction de la clé.

Nous devons maintenant utiliser ce nouveau SecurityExpressionRoot, pour cela il nous faut un MethodSecurityExpressionHandler :

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.core.Authentication;
 
class MyMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
  private final CanEvaluator evaluator;
 
  MyMethodSecurityExpressionHandler(CanEvaluator evaluator) {
    this.evaluator = evaluator;
  }
 
  @Override
  protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
    MyMethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(authentication, evaluator);
 
    root.setThis(invocation.getThis());
    root.setPermissionEvaluator(getPermissionEvaluator());
    root.setTrustResolver(getTrustResolver());
    root.setRoleHierarchy(getRoleHierarchy());
    root.setDefaultRolePrefix(getDefaultRolePrefix());
 
    return root;
  }
}

Et enfin nous devons configurer l'utilisation de ce handler :

import org.springframework.context.annotation.Lazy;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
 
@EnableGlobalMethodSecurity(prePostEnabled = true)
class MySecurityConfiguration extends GlobalMethodSecurityConfiguration {
  private final CanEvaluator evaluator;
 
  // All beans here needs to be Lazy otherwise it'll break AOP (cache, transactions, etc...)
  public MySecurityConfiguration(@Lazy CanEvaluator evaluator) {
    this.evaluator = evaluator;
  }
 
  @Override
  protected MethodSecurityExpressionHandler createExpressionHandler() {
    return new MyMethodSecurityExpressionHandler(evaluator);
  }
}

Même si c'est dit en commentaire je préfère le redire ici : injectez impérativement tous les beans de cette classe de configuration en @Lazy sinon vous allez perdre vos transactions, caches, etc !

Vous avez maintenant la possibilité d'utiliser votre nouvelle expression dans les @PreAuthorize :

@PreAuthorize("can('read', #stuff)")
public Optional<Stuff> get(StuffId stuff) {
  //...
}

Et c'est votre implémentation de CanChecker<StuffId> qui sera appelée pour savoir si votre utilisateur peut faire l'action read.

Et le filtrage des données en retour ?

La stratégie que nous avons vue permet de vérifier qu'un utilisateur peut accéder à une ressource mais elle ne permet pas un filtrage des données en retour. Même si on peut faire des choses avec @PostAuthorize je préfère traiter ce second besoin directement dans le code métier en filtrant les données lors de leur récupération.

S'adapter à votre besoin

L'exemple donné ici ne correspond très certainement pas directement à votre besoin : pas le bon verbe (can), pas les bons paramètres, ... Je pense cependant que la stratégie de choisir une implémentation en fonction du besoin métier s'applique dans la majorité des cas.

C'est maintenant à vous de trouver comment :

  • Associer des actions à des rôles (est-ce qu'une Map en dur suffit ?) ;
  • Faire simplement les implémentations des CanChecker des différents types (pensez aux délégations) ;
  • Améliorer CanEvaluator pour gérer l'héritage, les collections et les tableaux d'objets traités.

Un dernier point : selon votre besoin il est possible de brancher cette mécanique sur l'expression native Spring hasAuthority en définissant votre propre permissionEvaluator dans votre MethodSecurityExpressionHandler :

@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
  MyMethodSecurityExpressionHandler handler = new MyMethodSecurityExpressionHandler(evaluator);
  handler.setPermissionEvaluator(new MyPermissionEvaluator(evaluator));
  return handler;
}

De cette manière vous pourrez utiliser @PreAuthorize("hasPermission(#item, 'read')") et @PreAuthorize("hasPermission(#item, 'resource', 'read')"), c'est à vous de voir !


Rétrospective : Voici venir les élections

$
0
0
Rétrospective : Voici venir les élections

À mesure qu’une équipe avance dans son utilisation de Scrum, il arrive souvent qu’elle veuille varier le format de ses rétrospectives. Certaines restent très cadrées, d’autres plus ludiques mais toutes ont pour but l’introspection et l’amélioration des pratiques.

Le format que je vous propose ici est à mettre dans la famille des ludiques. La rétrospective se déroule sous forme de jeu de rôle où les membres de l’équipe vont incarner plusieurs profils. Ce qui nous donne un d’où déroulé/plan de rétrospective très « narratif ». Telle quelle, elle n’est pas adaptée à des petites équipes. Idéalement il faut être 6 personnes ou plus.

Matériel :

  • Post it
  • Feuilles A3 ou plus
  • Feutres, beaucoup de feutres
  • [Carte de vote et gommettes]

Place au plan !

L’équipe est une démocratie, et  comme dans toutes les démocraties, il y a régulièrement des élections où les  différents partis comptent bien faire élire leurs représentants et leurs idées.

Rétrospective : Voici venir les élections

Température de l’équipe : Sondage des électeurs

Tout d’abord, les instituts de sondage procèdent à une première étude des électeurs (tous les membres de l’équipe) pour connaître leur sujet de préoccupation à quelque temps des élections.

Chacun doit donc s’exprimer sur une (et une seule) idée/sentiment/remarque qui est particulièrement importante pour elle/lui.

[Cette prise de température va permettre de voir l’état d’esprit général et individuel de l’équipe, mais sans doute également les thèmes forts de la campagne]

Collecte d’idées : Qu’en pensent les échantillons représentatifs ?

Les instituts de sondage poussent ensuite plus loin leurs investigations pour avoir plus de matière.

Chacun doit alors répondre individuellement, sans limite d’idées (mais 1 par post-it) à ces deux questions :

  • Qu’ai-je particulièrement apprécié dans le mandat/sprint qui se termine ?
  • Qu’est ce qui m’a manqué, frustré qui pourrait être amélioré dans le mandat/sprint qui se termine ?

Chacun présente ses idées, sans qu’il y ait de débat, puis le groupe les rassemble par catégories. Elles représentent des thèmes importants à tenir compte lors des élections.

Générer des débats :

Préparation de la campagne

Désormais les participants ne sont plus de simples électeurs, mais des militants engagés de leur parti. Les participants à la rétrospective doivent donc se mélanger et former plusieurs partis/groupes. [D’au moins 3 membre chacun.]

Pour remporter les élections, les partis doivent réfléchir aux idées qu’ils souhaitent mettre en avant pour les élections.

Tout d’abord, ils vont réfléchir à leurs propositions d’améliorations, de changements ou même de réforme pour le pays et ainsi préparer les professions de foi , écrites sur papier, de leur campagne. [Cette étape est optionnelle mais permet d’avoir un brouillon de support pour le brainstorming généré par l’activité.]

Des pavés verbeux n’étant que rarement à même de capter l’attention des indécis, les partis tablent sur des affiches de campagne, à prévoir sur papier A3, pour rassembler visuellement leurs idées. [Que ce soit sous forme picturale, ou simplement du texte organisé de façon visuelle, faire cette affiche permettra de synthétiser les idées pour aller à l’essentiel, structurer la pensée et apporter une touche ludique]

Exemples d'affiches sur différents projets :

Rétrospective : Voici venir les élections

Tout est prêt, un représentant de chaque parti va donc pouvoir présenter l’affiche et les propositions qu’elle contient.

Les élections

Chaque électeur s’étant vu remettre une carte d’électeur pourra apposer son vote sur les différentes propositions. 1 vote (gommette) par idée, et non pas pour le parti dans sa globalité. Il n’est pas possible pour un même électeur de voter plusieurs fois pour la même idée. Le nombre de gommettes à donner par personne est à votre propre appréciation, en fonction du nombre de sujets soulevés, du temps, des participants, etc.

Rétrospective : Voici venir les élections

Décider des actions : Mise en place des décrets

Les électeurs se sont prononcés. Il est désormais possible pour la démocratie de s’améliorer en suivant les pistes plébiscitées par les électeurs. Les citoyens vont pouvoir sélectionner les thèmes les plus représentatifs et les retravailler pour en tirer des actions, propositions concrètes à mettre en place.

Il faudra ensuite choisir lesquelles intégrer au prochain sprint.

Rétrospective : Voici venir les élections

Voilà, l’exercice est terminé et après un discours d’investiture et d’auto-congratulation, charge à chaque sondeur, militant, candidat, électeur de retourner à son sprint et d’améliorer la vie de ses concitoyens !

J’espère que vous saurez embarquer votre équipe sur ce format, n’hésitez pas à poser des questions en commentaires ou sur par mail à skimsesiz@ippon.fr

Réplication des données : enjeux et approches

$
0
0
Réplication des données : enjeux et approches

Single Master, Multi Master, Masterless … derrière ces concepts se cachent des approches différentes pour la réplication des données dans un système distribué, souvent dans le cadre d’une base de données. Les compromis, avantages et limites de ces approches peuvent ne pas être évidents à comprendre et à synthétiser de prime abord. Cependant, les connaître est essentiel pour orienter le choix d’une solution technique selon le besoin auquel on cherche à répondre.

Souhaitant en apprendre davantage, je me suis tourné vers le livre de Martin Kleppmann, Designing Data-Intensive Applications , que je recommande à ceux qui veulent apprendre ou se remettre en tête les concepts du Data Engineering.

Le but de cet article est de synthétiser les principales idées et considérations lorsque l’on choisit une approche par rapport à une autre, afin de mieux orienter nos choix concernant les différentes bases de données disponibles à l’heure actuelle. L’article n’ayant pas une visée exhaustive, je n’aborderai pas les problématiques du partitionnement et du rebalancement.

Réplication des données : enjeux et approches

Réplication des données : enjeux

La réplication des données est un concept plutôt explicite. Dans le cadre d’une base de données, cela se traduit par l’évolution d’une architecture avec une seule instance à une architecture où plusieurs instances (appelées replicas) gardent chacune une copie de ces données et synchronisent les changements entre elles.

On souhaitera notamment procéder à cette évolution dans des problématiques de mise à l’échelle et d’infrastructures fault-tolerant (signifiant qu’une instance puisse devenir indisponible sans que les autres instances soient impactées, permettant de continuer les opérations courantes). Cela permet aussi d’améliorer la durabilité des données.

Cependant, ce changement d’architecture entraîne une complexité supplémentaire, principalement pour la réplication des changements. Il n’est initialement pas compliqué de copier une base de données vers une autre instance, mais lorsque de nouvelles opérations ont lieu sur l’un des noeuds (j’utiliserai désormais le mot noeud à la place du mot instance), il est nécessaire de le répliquer sur les autres pour que l’ensemble ait un état cohérent.

Dès lors, certaines problématiques (non-exhaustives) se posent :

  • Faut-il répercuter les modifications de manière synchrone ou asynchrone ?
  • Comment gérer les conflits d’écriture si deux opérations différentes ont lieu sur la même donnée sur des noeuds différents, et ce en même temps ?
  • Comment gérer les limites inhérentes des systèmes distribués, notamment les latences réseau pour la réplication des données (certains noeuds peuvent recevoir les données avant les autres).
  • Comment gérer l’échec d’un noeud : re-routage des requêtes, mise à jour lors de sa réintégration etc.

Les deux modes de synchronisation des données ne sont en réalité pas mutuellement exclusifs car une base de données (ex: DynamoDB) peut choisir d’utiliser les deux (semi-synchronous). En effet, chaque mode vient avec ses avantages et inconvénients :

  • Le mode synchrone permet de s’assurer que les données d’un noeud sont bien à jour avec celles d’un autre noeud. Cependant, ce mode de synchronisation est bloquant : si le noeud de réception des données n’est pas disponible, le noeud d’envoi va bloquer toutes les écritures en attendant la disponibilité de l’autre noeud (ce qui peut causer une paralysie en cascade du système).
  • A l’inverse, le mode asynchrone n’est pas bloquant. Cependant, nous n’avons pas de garantie que le noeud de réception aura déjà mis ses données à jour lorsqu’on fait une requête de lecture dessus. La synchronisation asynchrone émet aussi la possibilité d’une perte de données si un noeud cherchant à répliquer ses nouvelles données connaît un échec (avec données irrécupérables) avant que la synchronisation ait eu lieu.

Pour couper la poire en deux, DynamoDB choisit de répliquer d’abord une nouvelle donnée de manière synchrone sur un noeud, puis de manière asynchrone sur les autres.

La considération de la cohérence des données à un instant donné se pose alors : si certains noeuds obtiennent les données de manière asynchrone afin de ne pas bloquer le système, il se peut que des requêtes de lecture sur ces noeuds ne renvoient pas les dernières données disponibles (on voit ici la relation directe avec le théorème CAP). Cela peut aussi entraîner une violation de causalité, due à des différences de vitesse de réplication, par exemple l’arrivée d’une mise à jour d’une valeur sur un noeud avant que l'insertion initiale de cette valeur arrive sur le dit noeud (B arrive avant A). Ces problèmes de latence sont dénommés replicas lags et, si ils ne sont pas pris en compte lors de la conception d’une application, peuvent sérieusement entraver l’expérience de l’utilisateur et notre compréhension du système.

Il est donc courant d’entendre parler des termes eventual consistency (cohérence à terme) et strong consistency (cohérence forte). Les implémentations pour arriver à chacune de ces garanties divergent (je ne rentrerai pas dans les détails), mais on souhaite pouvoir au moins assurer les suivantes :

  • Monotonic read : éviter de voir un état antérieur à l’état que je viens de voir sur des requêtes successives (je fais une requête sur un noeud à jour puis une autre requête sur un noeud en retard).
  • Read-after-write consistency (aussi appelé read your own write) : une fois qu’une écriture est réalisée, éviter que, en tant que client, j’aille faire une requête à un noeud où la réplication n’a pas encore eu lieu, voyant alors mes données fraîchement insérées disparaître !

Ces problématiques en tête, il nous reste maintenant à aborder le coeur du problème : les approches implémentées par différentes bases de données pour gérer les changements et les potentiels conflits d’écriture ou de cohérence des données.

Réplication des données : approches

Il existe trois approches (ou algorithmes) principales utilisées par les bases de données qui supportent la réplication des données. Les concepteurs de ces systèmes choisiront l’approche qui est la plus efficiente pour les cas d’utilisation destinés à leur base de données.

Single Master

Implémentée notamment par : PostgreSQL, DynamoDB, MongoDB, Kafka (même si Kafka n’est pas une base de donnée pure)

Réplication des données : enjeux et approches

Cette approche fonctionne de la manière suivante : nous avons N noeuds. Un seul noeud est considéré comme le noeud maître, c’est à dire qu’il est le seul noeud à accepter des requêtes de modification des données (insertion, mise à jour, etc.). Les N-1 noeuds sont des noeuds en lecture seule (read replicas).

L’avantage de cette approche est d’éviter les conflits d’écriture. En effet, comme les modifications passent toutes par le même noeud, nous ne pouvons pas avoir de modifications concurrentes sur des noeuds différents, entraînant un problème détectable seulement plus tard lorsque la synchronisation asynchrone s’est effectuée. Ainsi, ce type d’approche est généralement recommandé pour les applications où la cohérence des données est importante. Comme l’approche parfaite n’existe pas, il y a un compromis : le seul noeud en écriture est le point d’échec principal de l’infrastructure (single point of failure). S’il tombe, nous ne pourrons plus accepter de modifications des données tant qu’un autre noeud n’aura pris sa place (le mécanisme d’élection, que je détaillerai juste après) !

Lorsqu’une nouvelle donnée est insérée ou modifiée via le noeud maître, celui-ci transmet les modifications aux noeuds en lecture seule. En effet, dans cette approche, on peut considérer que la synchronisation des données se fait par une différence entre l’état du noeud maître et l’état du noeud en lecture seule. Pour évaluer cet état, les bases de données qui implémentent cette approche utilisent ce qu’on appelle un log de réplication (replication log). Un log de réplication peut prendre plusieurs formes :

  • statement-based replication : on copie la requête aux followers, une approche jugée dangereuse si la requête n’est pas déterministe (avec les mêmes entrées, à un instant et état donné, la requête produit toujours le même résultat).
  • write-ahead log shipping : un log des modifications effectuées sur la base de données, très bas niveau (modifications de bytes) et couplé au moteur de base de données utilisé.
  • logical (row-based) log replication : un log découplé du moteur utilisé, utilisé spécifiquement pour la réplication, ici on spécifie directement les valeurs à insérer ou identifier, le quoi.

Par exemple, PostgreSQL, qui implémente l’approche de Single Master, permet de configurer la réplication : physique (WAL) ou logique.

Ce log de réplication est aussi utilisé dans le cas où un noeud en lecture seule tombe. Lorsqu’il revient en ligne, il aura certainement pris du retard sur le noeud maître. Il faut donc implémenter un mécanisme permettant à ce noeud de mettre à jour ses données pour refléter l’état actuel du noeud maître. Ce mécanisme est communément dénommé catch-up recovery. Le noeud en lecture seule va faire une demande du log de réplication au noeud maître, et par le calcul d’une différence, mettre à jour ses données.

Les noeuds en lecture seule peuvent aussi changer de type de synchronisation, principalement dans une approche semi-synchrone. Si le noeud en synchronisation synchrone tombe, un noeud auparavant asynchrone prendra sa place (en devenant synchrone), au risque de bloquer le système.

Cependant, la tâche n’est pas aussi aisée dans le cas de l’échec du noeud maître. Premièrement, il faut choisir le nouvel élu, celui qui deviendra le prochain noeud maître. Deuxièmement, c’est un titre convoité … il faut donc que les noeuds en lecture seule se mettent d’accord entre eux ! Mais sur la base de quels critères ? C’est toute une problématique : le mécanisme de failover. Généralement, c’est le noeud en lecture seule qui a les données les plus récentes qui sera choisi. Cela peut être décidé par vote, par une approche dite de consensus (Raft, Paxos, etc.).

Malheureusement, il existe des cas où l’ancien noeud maître, lorsqu’il retourne à la vie, n’accepte pas d’être relégué au rang de simple noeud en lecture seule. Il se considère toujours comme noeud maître ! On a donc un problème : deux noeuds maîtres dans une approche où un seul noeud maître devrait exister. Ce problème s’appelle le split brain. C’est un problème car le mécanisme de failover doit s’assurer que les requêtes de modification des données sont redirigées vers le nouveau maître ! A cause de ce problème, certains praticiens préfèrent ne pas automatiser le processus d’élection d’un nouveau maître, et le faire manuellement à la place. Quelques approches, comme STONITH (via Pacemaker/Heartbeat), permettent de limiter ces effets secondaires.

Multi master

Réplication des données : enjeux et approches

Implémenté notamment par : CouchDB, Redis

Dans cette approche, en contraste de l’approche Single-Leader, nous avons la possibilité d’avoir plusieurs maîtres. On va généralement utiliser cette approche dans une architecture hautement disponible (high availability) : un maître et quelques followers dans plusieurs zones de disponibilités / régions. Les noeuds maîtres acceptent les opérations de modifications, et se les propagent entre eux. L’avantage de cette approche est de ne plus avoir de point d’échec unique pour les écritures : si un noeud maître tombe, les requêtes sont redirigées vers les autres. On peut aussi bénéficier d’une meilleure latence si l’on place différents noeuds maîtres à différents emplacements, plus proches de nos utilisateurs.

Ici, le challenge principal n’est plus dans le mécanisme de failover pour l’élection d’un nouveau maître, mais pour la résolution des conflits d’écriture. Ces derniers sont particulièrement difficiles à corriger (ils ne sont détectés que plus tard à cause de la synchronisation asynchrone), on cherche donc généralement à les prévenir. Cependant, aucun système en Multi Master ne peut réellement garantir qu’il est capable de prévenir ce genre de conflits. Il ne faut donc pas utiliser de base de données implémentant cette approche si la véracité des données est critique. En cas de conflit d’écriture, il existe diverses méthodes permettant d’arriver à un état convergent, afin de résoudre les conflits (un ID unique pour chaque transaction où le plus grand sera choisi en priorité, etc.) mais la plupart entraînent potentiellement une perte de données.

Il faut aussi penser aux différents “chemins” possibles pour la synchronisation des données entre maîtres, la topologie. Si nous n’avons que deux noeuds maître, la topologie est simple, mais cela se complique si il y a plusieurs noeuds maître.

Réplication des données : enjeux et approches

A mes yeux, cette approche a davantage de sens dans des applications souhaitant être collaboratives et fonctionnant même hors-ligne. En effet, poussée à son extrême, cette approche considère que chaque appareil doit héberger un noeud maître en local (un mini-datacenter en périphérie) permettant de continuer à apporter des modifications aux données en local, pour qu’elles soient enfin synchronisées avec les autres noeuds lorsque la connexion revient. CouchDB correspond totalement à ce cas d’utilisation. Globalement, tout type d’architecture où l’on souhaite avoir un état local qui peut être synchronisé avec d’autres (notamment un cache, ce qui explique pourquoi Redis implémente aussi cette approche).

Pour éviter les conflits dans ce type d’application collaborative, il existe plusieurs approches intéressantes, que je nomme brièvement :

Masterless

Réplication des données : enjeux et approches

Implémenté notamment par : Cassandra

L’approche Masterless, c’est la démocratie participative apportée aux bases de données. Ici, plus de hiérarchie : tous les noeuds sont au même niveau, et se concertent entre eux pour la prise de décisions ! Il n’y a plus de concept de réplication de logs (les instructions transmises).

Dans cette approche, chaque requête (qu’elle soit de lecture ou d’écriture) est envoyée à plusieurs noeuds en “même temps” (entre guillemets car les réseaux sont capricieux, certains noeuds recevront les données avant les autres ; je parle donc ici du moment de l’envoi). Comme nous sommes en démocratie, pour qu’une requête soit acceptée, une majorité de noeuds doivent se mettre d’accord. Ce mécanisme de consensus léger s’appelle le quorum. Par exemple, si je veux lire une valeur, je vais envoyer la requête à 3 noeuds. Si le premier noeud a une valeur de “a”, mais les deux autres noeuds ont une valeur de “b”, c’est la valeur “b” qui sera choisie. Elle nous sera renvoyée, et la valeur “a” du premier noeud sera remplacée par “b “(mécanisme de read-repair, si la majorité ne pense pas comme moi, c’est elle qui a raison !). Ce principe peut être implémenté différemment : par exemple dans le cas de Cassandra, c’est le noeud possédant une donnée avec la timestamp la plus récente qui renverra la valeur. On sera ici davantage dans une approche de consultation.

Quelques règles sont à garder en tête pour que le quorum fonctionne bien. Prenons n le nombre de noeuds, w le nombre de noeuds qui doivent confirmer chaque requête d’écriture (write) et r le nombre de noeuds qui doivent confirmer chaque requête de lecture (read).

  • On prendra généralement un nombre impair pour n. Pour r et w : w = r = (n + 1) / 2
  • w + r > n : Si j’interroge 3 noeuds pour écrire, 3 noeuds pour lire, et que j’ai 5 noeuds en tout, je devrais avoir une valeur à jour car il y a superposition.
  • Si w < n, je peux tolérer la perte de n - w noeuds et continuer à supporter les écritures.
  • Si r < n, je peux tolérer la perte de n - r noeuds et continuer à supporter les lectures.

L’approche Masterless confère donc nombre d’avantages : résiliente (pas de noeud avec un rôle unique), durabilité des données (envoyées à plusieurs noeuds), performance, mise à l’échelle. On l’utilise ainsi dans les cas où on souhaite supporter des requêtes intensives et une forte résilience du système, au prix de données pas toujours cohérentes (récupération de données anciennes, appelées stale values). En effet, il faut parfois un certain temps avant que des données rarement accédées soient mises à jour par le processus de read-repair. C’est pour cela que certaines bases de données déclenchent un processus en arrière plan (un processus d’anti-entropie) pour régler les différences d’état entre les noeuds.

De plus, cette approche n’évite pas réellement le problème des écritures simultanées. Tous les noeuds n’auront pas le même délai d’écriture, du coup il se peut que des requêtes initiées par un autre client arrivent avant. Il faut donc trouver un mécanisme permettant de prioriser certaines requêtes au détriment d’autres. Cassandra implémente l’approche LWW (Last Write Wins), ce qui signifie que la requête avec la timestamp la plus récente a précédence sur les autres. Cependant, cette approche est limitée : un gros problème des systèmes distribuées est celui de la synchronisation des horloges. Si un noeud a une horloge avec un décalage temporel (drift) plus avancé que les autres, toutes ses requêtes vont supplanter celles des autres noeuds.

J’ai mentionné au début que cette approche n’utilise plus de log de réplication. Cela peut être problématique dans la mesure où le monitoring sera plus compliqué car nous n’avons pas d’historique ordonné des modifications apportées à la base de données.

Enfin, cette approche ne permet pas la gestion des transactions ACID. Une écriture partielle sera ainsi acceptée comme telle (pas d’atomicité).

Gardons donc en tête que la cohérence des données ne peut donc pas être garantie par cette approche, comme pour la précédente.

Synthèse

Single Master Multi Master Masterless
Exemples d’implémentation PostgreSQL, DynamoDB, MongoDB, Kafka CouchDB, Redis Cassandra
Cas d’utilisation Applications où la véracité des données est critique. Cache applicatif

Collaboratif / Hors ligne

Partie locale -> sync partie globale
Mise à l’échelle et requêtes intensives.
Synchronisation des changements Log de réplication Log de réplication Read-repair, processus d’anti-entropie
Résolution de conflits Pas de problème de données conflictuelles car les écritures ne peuvent que passer à travers un seul master. Mécanismes de résolution des conflits divers (on cherche surtout à les éviter). Quorum (vote à la majorité).
Gestion d’échecs d’un noeud Mécanisme de catch-up recovery pour les replicas, failover pour le noeud master. Comme pour le single master Transparent car tous les noeuds sont au même niveau, les mécanismes de read-repair et d’anti-entropie permettront une consistance éventuelle.
Avantages Plus simple à mettre en oeuvre et maintenir.

Cohérence des données.

Utilisé depuis longtemps, écosystème mature.

Pas de point unique pour l’écriture, donc plus résilient.

Si nous avons des utilisateurs dans différentes régions géographiques, cette approche permet de réduire la latence grâce à la possibilité de mettre un master dans chaque datacenter, à des endroits différents.
Pas de failover, fault-tolerant (tous les noeuds sont égaux).

Mise à l’échelle.

Moins de chance de perte de données car chaque requête (écriture, lecture, etc.) est envoyée à plusieurs noeuds en même temps.
Désavantages Un seul noeud pour l’écriture, ce qui en fait le maillon faible de l’architecture.

Les latences d’écriture peuvent être plus élevées pour les utilisateurs qui sont éloignés géographiquement du noeud master.
Conflits d’écriture.

Comme le modèle collaboratif est l’un des cas d’utilisation phare des bases de données multi-master, on ne peut pas utiliser des mécanismes de lock pour les problèmes de concurrence. Cela empêcherait par exemple l'édition simultanée d’un document. Il faut donc mettre en place des mécanismes de résolution des conflits (operational transformation…).
Monitoring des opérations et de leur ordre plus compliqué (pas de log de réplication).

La consistance éventuelle peut prendre du temps, surtout si on fait une requête sur des données rarement utilisées (le quorum read doit faire plusieurs passes pour s’uniformiser).

Permet les écritures partielles.

Ceph - Technologie de stockage Haute Disponibilité - En action

$
0
0

Contexte

Ceph - Technologie de stockage Haute Disponibilité - En action

Notre cluster de stockage Ceph contient 32 disques SATA (4To) et 8 disques SSD (500Go) pour la partie Rados Block Device. Ce stockage en mode bloc est la base du cloud privé chez Ippon Technologies.

L’augmentation de sa capacité a été faite au fil des années en conservant les anciens disques et en y intégrant des nouveaux. Afin d’anticiper les problèmes sur les moins récents (ajoutés au cluster il y a plus de 5 ans) nous avons procédé à leur remplacement.

Cela a impliqué le changement de :

  • 12 disques SATA

Noeuds de stockage, chaque disque SATA exécute un Object Storage Daemon (OSD) intégré au cluster. Les OSDs sont des services communiquant entre eux et qui sont en charge du stockage distribué. Dans un cluster Ceph en production, sur un disque SATA ne s’exécute qu’un unique OSD (pour éviter les conflits).

  • 3 disques SSD

Noeuds de journal où les lectures/écritures sont intenses. Dans notre infrastructure chaque SSD est responsable d’un groupe de 4 OSDs.

Le schéma suivant illustre la composition d’un de nos serveurs dédiés à Ceph, et les liens que les différentes entités entretiennent entre elles en son sein.

Ceph - Technologie de stockage Haute Disponibilité - En action
Lien entre les OSDs et disques SATA/SSD au sein d'un de nos serveurs physiques

L'opération a été effectuée sur 3 serveurs de ce type. Pour ne pas impacter l’utilisation du cluster par les clients, les opérations ont été découpées en plusieurs parties. Pour chaque serveur la procédure a été la même :  

  1. Sortie des OSDs du cluster : Ralentissement potentiel
  2. Remplacement physique des disques en datacenter : Aucun impact
  3. Intégration des nouveaux OSDs dans le cluster : Ralentissement potentiel

Note

Le peu d’informations précises disponibles sur internet et la volonté d’un retour d’expérience sur ce type d’opération sensible ont motivé l’écriture de cet article. Étant un article assez technique, une relative expérience sur Ceph rendra sa lecture plus confortable ; mais les notions clés seront expliquées le long de l’article. Hang in there ! 💪

Actions réalisées

Ceph - Technologie de stockage Haute Disponibilité - En action
Schéma des actions menées lors de l'opération en production

Chaque déplacement en data-center correspondait au remplacement physique de nos disques. Nous avons recensé quelques remarques quant-aux trois principales étapes du remplacement de nos disques, notamment un imprévu qui a changé le rythme de l’intégralité de l’opération.

ceph-01

Il y a eu environ 20To de données transférées lors de cette première intervention, contre 10 attendus. Un double mouvement de données a été repéré et nous a contraint d’attribuer deux fois plus de temps que prévu à l’opération totale. Nous avons commencé à chercher une manière de nous en affranchir.

ceph-02

Une solution pour éviter le double rebalancement des données a été étudiée sur notre cluster de test. Aucun ralentissement client noté pour une nouvelle fois 20To de données déplacées.

ceph-03

Moins de temps a été accordé à ce dernier serveur car nous avions d’autres projets importants en parallèle et pas de limite de temps critique à respecter. Le double mouvement de données est désormais évité après avoir mis en place une nouvelle procédure, testée et validée sur notre cluster de développement.

Une explication détaillée est disponible en fin d’article pour les plus curieux.

Procédure

Pour remplacer les disques de chaque serveur (ceph-0x), la procédure a été la suivante :

  • Connexion en ssh sur le serveur cible (doté des 4 SATA liés à 1 unique SSD de journal à remplacer) afin de pouvoir commencer les manipulations.
  • Récupération des identifiants des OSDs liés aux disques et partitions que l’on souhaite remplacer. (e.g. on souhaite sortir le disque sdc du serveur ceph-01 et on identifie que c’est l’osd.7 qui s’exécute dessus). Une fois la liste des identifiants établie, nous pouvons lancer nos commandes.
  • Sortie des OSDs du cluster par l'exécution des commandes suivantes :
ceph osd out XX 
    # Marquage de l’OSD comme non disponible au cluster
    # 1er mouvement de données, ~10To rebalancés
stop ceph-osd id=XX
    # arrêt de l'exécution de l’OSD sur le serveur
ceph osd crush remove osd.XX 
    # Sortie logique de l’OSD du cluster
    # 2nd mouvement de données (non prévu), ~10To rebalancés
ceph auth del osd.{osd-num} 
    # suppression des clés d’authentification de l’OSD au cluster
ceph osd rm {osd-num} 
    # suppression définitive de l’OSD du cluster

où XX est l’identifiant de l’OSD en question.

Cette suite de commandes a donc été lancée 4 fois par serveur, une fois par OSD. Quelques commandes utiles d’optimisation sont détaillées en fin d’article.

  • Une fois les 4 OSDs sortis du cluster, déplacement en data-center et face à nos racks, identification des disques physiques à sortir grâce à leur led (ledctl).
  • Sortie successive des disques durs du serveur puis insertion des nouveaux.
  • Une fois les 4 disques et le SSD remplacés, nous procédons à un test d’écriture sur les disques de fichiers lourds comme d’une multitude de fichiers légers (dd -if= … ) afin de nous assurer du bon fonctionnement de nos nouveaux disques.
  • Création puis ajout d’un nouvel OSD dans le cluster.
  • Utilisation de l’outil de déploiement ceph-deploy pour créer et ajouter les nouveaux OSDs au cluster :

ceph-deploy --overwrite-conf osd create ceph-0X:sdY:/dev/sdZ

où sdY représente l’emplacement du disque de stockage (SATA) réservé à l’OSD ; et sdZ l’emplacement de son journal associé (SSD). Sur un même server ceph-0X, les 4 OSDs partageront le même sdZ.

  • Pour le premier ajout dans le cluster, nous avons pour habitude de rester au datacenter pour s'assurer que tout se passe bien au premier rebalancement des données et être prêt à intervenir en cas de besoin.
  • Ajout par la suite des autres OSDs au cluster en suivant la même procédure, de manière distante.

Remarque : Il ne présente pas de soucis d’enlever le SSD journal à chaud, une fois que l’on s’est assuré que plus aucun OSD n’écrit dessus. C’est d’ailleurs son unique fonction sur le serveur.

La procédure engendre de lourds mouvements de données, et garder un oeil sur notre cluster lors de ce genre d’opération sensible est essentiel. Constamment, l’état de notre cluster est monitoré et nous permet d’être réactif aux métriques importantes : c’est ce que nous allons voir dans la prochaine section.

Monitoring du cluster lors de l’opération

Nous utilisons plusieurs dashboards Grafana pour surveiller l’état de notre cluster, en y étant d’autant plus attentif lors de cette opération de remplacement.

Exemple de dashboard Grafana

Ceph - Technologie de stockage Haute Disponibilité - En action
Dashboard général du cluster

Analyse des Placement Groups

L’analyse des Placement Groups (PGs) est une composante essentielle à l’ajout / suppression d’OSDs de manière successive. Basiquement, les PGs sont les paniers, groupes logiques où sont placées les données du cluster. Chaque OSD est en charge d’un certain nombre de ces PGs.

Lorsqu’un OSD est ajouté à notre cluster, il va devenir responsable d’un certain nombre de PGs. Ceux-ci étant stockés sur les autres OSDs, un transfert de données va s’opérer afin de remplir le nouvel OSD et d’alléger les autres.

Ceph - Technologie de stockage Haute Disponibilité - En action
Analyse des Placement Groups encore à déplacer pendant l’opération

L’analyse des PGs et la fin de leur migration étaient nos indicateurs principaux avant de continuer sur la prochaine étape de l’opération (nouvel ajout/suppression d’un nouvel OSD).

Utilisation des disques du cluster

L’utilisation des disques est une métrique importante dans notre cas, car il est témoin direct de la charge de notre cluster. Une importante écriture de la part d’un client, un transfert d’information intense ou encore une vérification de la cohérence des données au sein du cluster seront tous retranscrits en terme d’entrées et sorties (d’utilisation) de nos disques.

On voit ci-dessous que l’ajout d’un OSD à 8h42 ce matin-là a engendré une montée en charge des différents disques de notre cluster (chacun représenté par une ligne de couleur). Les OSDs rentrent dans un premier temps dans une phase de peering, puis s’occupent du rééquilibrage des PGs par un processus de backfilling (transfert progressif des données entre les OSDs). Au début de cette phase, l’utilisation des disques atteint quasiment 100%.

Ceph - Technologie de stockage Haute Disponibilité - En action
Occupation de nos disques en termes d’IO lors de l’ajout d’un nouvel OSD dans le cluster

Nous savons que la charge sur notre cluster à travers ces opérations est très lourde : les équipes étaient prévenues et nous n’entamions pas d’autres manipulations qui auraient pu avoir des conséquences sur les performances auprès de nos clients. Pour plus d’informations quant aux PGs et au backfilling, vous pouvez vous référer à cet article. Encore une fois pour les curieux, des informations sur leur optimisation seront données en fin d’article.

Gestion de l’espace disque

Notre cluster va constamment chercher à garder le bon nombre de réplicats de ses objets défini dans sa configuration (la crushmap). Si l’on prend finalement l’exemple de la suppression d’un OSD, le cluster va donc recréer des PGs sur les OSDs restants en respectant la politique de placement définie dans la crushmap.

Cela consiste au transfert des PGs de l’OSD à supprimer vers les autres OSDs du cluster.

Ceph - Technologie de stockage Haute Disponibilité - En action
Migration des données d’un disque se préparant à être sorti du cluster

Pour cette raison, les opérations ont été divisées par serveur et étalées dans le temps : l’idée n’est pas de surcharger les OSDs restants du cluster en enlevant tous les disques d’un coup, mais bien de diluer les conséquences de ces ajouts et suppressions autant que possible.


Remarques post-opération

Éviter le double mouvement des données

Comme énoncé précédemment dans l’article, nous avons été gênés par un double mouvement de données non attendu lors de la sortie des OSDs du cluster en suivant la procédure officielle. Au lieu de déplacer une fois 10To de données, 20To étaient déplacés pour chaque OSD. En comptant que l’on ait 12 disques (donc OSDs) à remplacer, cela nous ramène à un mouvement données de 240To contre 120To planifiés. Au lieu de durer 2 semaines, l’opération en durera le double. Pour y pallier, nous avons pensé à une autre manière de faire :

Dans un premier temps, nous avons remarqué que pour chaque ceph osd out XX mais également ceph osd crush remove osd.XX de la procédure, nous assistions à un rebalancement des données entre nos OSDs. Ceci était prévu que lorsque l’on marquait notre OSD out, mais pas une seconde fois lorsqu’on le supprimait de la crushmap. Afin de nous réduire à un seul mouvement de données, nous avons légèrement modifié la procédure.

Chaque OSD est doté d’un poids dans le cluster, un pourcentage en fonction de sa capacité de stockage en général. On peut le définir dans notre crushmap pour chacun d'entre eux.
Avant même de lancer la première commande (ceph osd out XX), nous avons réduit le poids de notre OSD dans le cluster à 0 :

ceph osd crush reweight osd.XX 0.

Réduire son poids à 0 revient en soi à le rendre responsable de 0% de la taille du cluster : donc qu'il faille le vider de toutes ses données. Nous avons testé cette procédure sur notre cluster de développement, afin d’éviter quelconque effet de bord non prévu en production.

Ceci a été concluant : ni le ceph osd out XX ni le ceph osd crush remove osd.XX n'engendraient alors plus de mouvement de données. Une fois la nouvelle procédure validée, nous l’avons donc mise en place sur l’environnement de production.

Elle sera également utilisée à l’avenir, ayant pour autre avantage que la valeur du poids de l’OSD puisse être graduellement réduite, afin d’éviter de gros rebalancements dans le cluster. La nouvelle procédure s’articule alors comme suit :

ceph osd crush reweight osd.XX 0.
    # Passage du poids de l’OSD à 0 (progressivement ou non).
    # Mouvement de données, ~10To rebalancés.
ceph osd out XX
    # Marquage de l’OSD comme non disponible au cluster.
    # Pas de mouvement de données.
stop ceph-osd id=XX
    # arrêt de l'exécution de l’Object Storage Daemon.
ceph osd crush remove osd.XX
    # Sortie logique de l’OSD du cluster.
    # Pas de mouvement de données.
ceph auth del osd.{osd-num}
    # Suppression des clés d’authentification au cluster
ceph osd rm {osd-num}
    # Suppression définitive de l’OSD du cluster.

Nous sommes confiants sur le fait que ce double mouvement de données, engendré bien qu’en suivant la documentation et les recommandations officielles, soit fixé sur les versions supérieures de Ceph.

Optimiser le backfill pour un transfert de données plus rapide

La configuration de l‘osd_max_backfill correspond au nombre de PGs maximum rebalancé à la fois par un OSD. Un backfill à 1 (par défaut) autorisera un transfert de données plus lent mais aura pour avantage de ne pas surcharger le cluster.

La commande ceph tell osd.XX injectargs '--osd_max_backfills Y' a été très utile pour justement contrôler le processus de mouvement de données en fonction de la charge du cluster.

Par bonne pratique, le backfill était mis à 1 au préalable d’un nouvel ajout ou suppression d’OSD dans le cluster. Une fois l’utilisation de disques plus calme (à la fin du peering entre les OSDs notamment), le backfill était ensuite monté à 2 pour accélérer l’opération.

Un backfill plus grand encore engendrait une occupation trop importante des ressources du cluster et n’a donc pas été mis en place.

Faire attention lorsqu’on a des serveurs à capacité hétérogène

Avec du recul, nous aurions sûrement dû prendre moins de temps lors de l’opération sur notre dernier serveur Ceph, ceph-03. En effet, il s’agit de notre plus petit noeud (avec le moins d’OSD et de capacité de charge) : si ceph-01 ou ceph-02 était tombé pendant l’opération sur ceph-03, la charge aurait été très lourde à gérer (car plus d’⅓ du cluster aurait été down).

Ceci aurait pu causer de sérieux ralentissements chez nos clients. Le fait d’avoir une procédure plus optimisée a néanmoins équilibré le temps d’opération sur ce dernier disque.


Conclusion

Un article assez technique,  si vous l’avez suivi jusqu’au bout sans jamais avoir entendu parler de Ceph, honnêtement bien joué ! Le changement d’un tiers d’une architecture de stockage distribué en production nécessite des connaissances précises et c’est ce que cet article essaie d'amener : poser la pierre sur laquelle nous n'avons pas pu nous reposer pour effectuer cette opération.

Ceph est une technologie bluffante (et ce déjà sous Jewel). Lorsque bien configurée et maîtrisée, elle est incroyablement résiliente et permet la mise en place d’un cloud privé à très hautes performances (nous sommes plus rapide en écriture sur notre cluster qu’en local sur SSD).

Avec ces nouveaux disques en production, nous voilà rassurés et prêts à attaquer la suite !

Koalas, quand Spark déclare sa flamme à Pandas !

$
0
0
Koalas, quand Spark déclare sa flamme à Pandas !

Je vais vous parler d’un nouveau projet open source de Databricks portant le doux nom de Koalas.

Avant même de parler du projet en lui-même, nous allons voyager ensemble dans la jungle de la Data. Je vous propose une petite excursion dans la zone des Pandas, l’outil Python de manipulation et d’analyse de la donnée, de passer par la maison Apache Spark, framework de calcul distribué, et enfin de vous présenter les Koalas, librairie implémentant les API Pandas sur Spark.

Pandas

Koalas, quand Spark déclare sa flamme à Pandas !
source : https://pandas.pydata.org/

Quelques lignes sur Pandas sont peut-être utiles alors je vais vous en parler ici.

Pandas est le premier pensionnaire de notre jungle, c’est une librairie open source Python de manipulation et d’analyse de données à plusieurs dimensions. Elle propose en particulier des structures de données et des opérations de manipulation de tableaux numériques et de séries temporelles. C’est une librairie très simple à utiliser et très simple à tester. Elle est soutenue par une communauté gigantesque et dispose d’un écosystème d’API pour la manipulation de la donnée tout aussi gigantesque. “Ce panda est géant !”

Pandas est parfaitement intégré aux librairies communes de visualisation de la donnée et de Machine Learning. Elle est devenue un standard pour tous les workloads de Machine Learning.

Le revers de la médaille est que cette librairie est conçue pour des lots de données qui tiennent entièrement en mémoire donc exit le Big Data à moins d’avoir des super-serveurs !

Spark/PySpark

Koalas, quand Spark déclare sa flamme à Pandas !
source : https://spark.apache.org/

Un petit mot sur Spark pour ne pas perdre tout le monde dans l’histoire : Spark est un outil permettant de traiter de larges volumes de données de manière distribuée.

Spark est devenu un standard dans les calculs à large échelle, il optimise les requêtes via Catalyst et optimise l’utilisation mémoire et CPU de ses workloads via Tungsten. Inutile de faire de la redite, vous trouverez tout ce que vous cherchez sur le site officiel de Spark si vous voulez aller plus loin !

Le lien avec Pandas ?
Les 2 outils permettent sensiblement la même chose : manipuler des dataframes. L’implémentation est différente : Pandas est mono-serveur quand Spark est distribué.
Autre point commun : Python. En effet, Spark propose une API en Python (PySpark) pour effectuer les transformations qui est devenu, au fil des années, très populaire ! Mais il y a un véritable fossé entre les APIs qu’offre la librairie Pandas et le  DSL PySpark ce qui rend difficile la migration entre Pandas et PySpark ou encore, comme dit dans l’introduction, l’accompagnement des Data Scientists à utiliser Spark.

Pourquoi m’y suis-je intéressé ?

Lorsque nous sommes Data Scientist ou que nous travaillons avec des Data Scientists, nous avons forcément entendu parler ou manipulé des dataframes Pandas. Via n’importe quel MOOC spécialisé ou au travers de ses études dans le domaine, nous sommes formés  à l’utilisation des dataframes Pandas.

Travaillant sur une plateforme dont le moteur principal de calcul est Spark, je rencontre une flopée de Data Scientists qui ne connaissent pas ou ne maîtrisent pas le framework.

Un dataframe Spark n’a rien en commun avec un dataframe Pandas. Lorsqu’un Data Scientist arrive en possession d’un Spark dataframe, sa première action est un “toPandas()” qui a le malheur de remonter toute la donnée, préalablement distribuée par Spark sur tous ses executors, au niveau d’un seul noeud (driver). Il effectue ensuite ses transformations et travaille sur ses modèles de machine learning préférés. Au niveau de Spark, cela se traduit par un gâchis de ressources et des grosses pertes en performance et rendement menant bien souvent à un crash du job. L’action suivante pour le Data Scientist, lassé d’attendre le filtrage sous-optimal de son dataframe Pandas, est une réduction de la quantité de données en entrée pour pouvoir travailler plus rapidement (via un take(1000) sur le dataframe Spark par exemple). Et là, il se retrouve à travailler sur un sous-ensemble de données non représentatif des données d’entrée construisant ainsi des modèles moins performants.

Nous, Data Engineer, avons alors passé énormément de temps à sensibiliser les Data Scientists à utiliser la puissance de Spark. Le problème est que le Domain Specific Language (DSL) Spark ne peut pas lutter avec la simplicité d’utilisation de Pandas.
Pour illustrer cela, voici un exemple du value_counts:

Koalas, quand Spark déclare sa flamme à Pandas !

Databricks est alors arrivé avec le projet Koalas, potentielle solution à nos problèmes !

Koalas

Koalas, quand Spark déclare sa flamme à Pandas !
source : https://github.com/databricks/koalas

Voici le dernier venu de la jungle (composée de Pandas, d’étincelles et de koalas … Ce n’est pas banal !).

Koalas est une librairie open source développée par Databricks released en mars 2019 (en version 0.0.5). Elle implémente les API Pandas pour Apache Spark. Elle unifie les API Pandas et Spark mais Pandas first (si une même API existe sur Pandas et Spark, Koalas exposera la transformation que fait originellement Pandas plutôt que Spark) afin de rendre efficace Pandas dans la jungle du Big Data.

Koalas maintient la compatibilité avec Spark et Pandas via la classe DataFrame (pouvant prendre en paramètre un dataframe Pandas ou Spark) et les méthodes to_pandas et to_spark permettant de transformer le dataframe Koalas en dataframe Pandas ou Spark.

Performances

Comme nous pouvions nous y attendre, les performances vis-à-vis de Pandas sont excellentes. Logique me direz-vous, puisqu’elle profite de la puissance offerte par Spark.

L’énorme avantage est, bien entendu, de pouvoir utiliser Spark sans avoir à apprendre une nouvelle API. Ils peuvent profiter pleinement des automatismes acquis en formation en apprenant à utiliser Pandas.

Comme pour Spark, les évaluations sur Koalas sont lazy. C’est à dire que les opérations sur les données ne sont lancées que sur certaines commandes. La donnée n’est chargée en mémoire que lorsqu’on en a réellement besoin. Les gros avantages à cela sont :

  • L’augmentation de la vitesse d’exécution de notre algorithme puisque nous ne chargeons pas en mémoire tous les états intermédiaires de nos données (seulement quand nous en avons besoin) ;
  • L’optimisation de nos algorithmes. Koalas profite des optimisations offertes par Tungsten et Catalyst ;
  • La réduction de la complexité des opérations. Les deux principales complexités dans les opérations sont spatiales et temporelles. L’évaluation lazy de Koalas permet de réduire les deux vu que CHAQUE opération n’est pas exécutée (sauf si elle est déclenchée) et la donnée n’est chargée en mémoire que lorsque nous en avons besoin.

Il faudra en tenir compte quand nous travaillons avec Koalas.

Facilité d’utilisation

Du point de vue de l’utilisation du package, vous trouverez ici un article évoquant les similitudes entre Pandas et Koalas. ‘import databricks.koalas as kd’ et le tour est joué. A terme (une fois toutes les API Pandas portées dans Koalas), si le Data Scientist a fait des tests avec Pandas dans son Jupyter notebook en local, il n’aura plus qu’à modifier son ‘import pandas as pd’ en ‘import databricks.koalas as pd’ et aucune autre modifications sur son code ne sera nécessaire.
Koalas est “Community driven”. Les avantages de l’open source !

Support / Communauté

Comme tout projet open source, il existe un github avec gestion de tickets et un forum pour la communauté. Databricks a mis à disposition pour la communauté un guide pour contribuer au projet. A ce jour, nous comptons presque 40 contributeurs, plus de 800 commits qui ont participé à 29 releases.

Les fonctions Pandas communes ont été implémentées dans Koalas.
Cela représente :

  • 60% des API Dataframe/Series
  • 60% des API DataframeGroupBy/SeriesGroupBy
  • 15% des API Index/MultiIndex
  • les fonction spécifiques to_datatime, get_dummies, …
  • 80% des fonctions relatives à la représentation visuelle (plot)

Il reste encore du travail mais la communauté est active !

Limitations / Préoccupations

Support des librairies Python

Certaines librairies Python faisant partie de l'écosystème d’un Data Scientist ne sont pas supportées. Il faudra alors passer par Pandas pour :

  • les librairies spécifiques de machine learning (scikit-learn, keras, …). Pour contourner ce problème, nous pourrons créer les modèles de Machine Learning et utiliser MLflow pour load() et predict() ;
  • les librairies de visualisation. Uniquement matplotlib est supportée. Dès que le Data Scientist voudra utiliser sa librairie de visualisation préférée, il faudra passer en Pandas.

Ou est la méthode apply ?

Quand on travaille avec Pandas, on a été, au moins une fois, frustré de la lenteur de la commande apply() qui applique une User Defined Function (UDF) à toutes les lignes ou colonnes de mon dataframe. Vu que Pandas est monon-serveur, on peut s’y attendre ! Koalas, à ce jour, n’implémente toujours pas cette API de la classe Dataframe. Pourtant Spark est taillé pour ça. Ne désespérons pas, un ticket existe et la communauté active !

Performances : Koalas vs PySpark

Il existe forcément un overhead entre Koalas et Spark. Pour une opération unique, les performances seront égales mais lorsque nous allons coder un algorithme complet (enchaînant les opérations) en utilisant Koalas, nous pourrions presque toujours trouver un code Spark plus optimal.

Ordre

Une des grosses différences entre Spark et Pandas est le fait que Spark ne maintient pas l’ordre des lignes dans un dataframe. Cela demandera alors de forcer des orderBy pour retrouver un traitement identique à Pandas.

Et le calcul distribué dans tout ça ?

Une des grosses limitations que j’y vois également est l’apprentissage lié au calcul distribué. En effet, abstraire l’utilisation de Spark masque l’aspect distribution du calcul et la problématique de performance qui en est liée. Un exemple simple est le shuffle. Quand nous utilisons Pandas sur une machine unique, joindre des dataframes ou les ordonner n’est jamais un problème. A partir du moment où nous utilisons Spark et nous faisons donc du calcul distribué sur plusieurs machines, ces opérations nécessitent de faire transiter les données entre les workers (shuffle) ce qui représente un coût très important. L’expérience dans le framework sera toujours nécessaire pour écrire du code performant !
Nous pourrons ajouter à cela, la difficulté dans la lecture des plans d’exécution, les problèmes de data skew etc.

Conclusion

C’est certainement une des évolutions que j’attendais pour faire le lien entre les ingénieurs Data et les Data Scientists. Le projet est très prometteur et très suivi par la communauté, il semble que je n’étais pas le seul à l’attendre !

Nous pointerons du doigt certaines limitations qui pourraient rebuter certains utilisateurs assidus de Pandas.

Attention, par contre, Spark semble à la portée de tout utilisateur de Python ou Pandas via Koalas, mais ce n’est pas si simple ! Koalas n’apprendra pas aux utilisateurs de Pandas à utiliser Spark mais c’est un grand pas vers l’unification de ces deux mondes que sont la Data Science et le Data Engineering en ne parlant que d’un seul framework de calcul commun. Mon intérêt à cette technologie ne s’arrête pas là, je ne manquerai pas de vous tenir informés de toutes les nouveautés sur ce sujet.

Apprendre le TDD

$
0
0
Apprendre le TDD

Le Test Driven Development est certainement la méthode de design de code la plus efficace connue actuellement ! Cependant, malgré son incroyable efficience, elle est souvent très mal comprise (voir prise pour une méthode de test).

Cette incompréhension vient certainement de la grande difficulté de son apprentissage, le TDD étant certainement une des plus belles illustration de la Loi de Bushnell : "Easy to learn, hard to master".

Il existe de très nombreuses manières d'apprendre le TDD, je vais simplement donner ici les astuces que j'aurais aimé avoir quand j'ai commencé mon propre apprentissage.

La théorie

Commençons par le commencement : Le TDD c'est quoi ? Déjà une méthode de design (même si je l'ai déjà dit) mais c'est surtout une manière d'organiser son travail qui se découpe dans un cycle très court en trois phases :

Apprendre le TDD

On commence par RED. Dans cette phase, on va écrire un test qui ne passe pas (s’il ne compile pas, il ne passe pas). À ce moment, on ne se concentre que sur la logique des APIs (exposition des methods, organisation des classes) que l'on veut appeler : est-ce que si j'appelle cet Objet de cette manière cela traduit bien l'intention métier du traitement que je veux faire ?

Vient ensuite la phase GREEN, ici on va écrire le code le plus direct pour faire passer notre test (sans casser un test précédent).

On termine le cycle avec REFACTOR où on va retravailler notre code pour :

  • Avoir du code plus élégant ;
  • Mieux expliciter les traitements qui sont faits ;
  • Apporter une meilleure réponse au métier.

On répète ce cycle toutes les quelques secondes voire minutes. Il n'est absolument pas question ici de cycle sur plusieurs jours. On fait plusieurs centaines de cycles de TDD dans une journée !

Ce cycle très simple à décrire peut cependant être très perturbant quand on s'y essaie pour la première fois. Une des erreurs les plus courantes est de vouloir penser à la manière de faire l'implémentation quand on est dans la phase RED. Il est aussi courant de vouloir faire tous les tests d'une class avant de se lancer dans l'implémentation : ce faisant notre implémentation ne sera alors pas dirigée par les tests !

Quand on commence le TDD, les journées sont tout bonnement épuisantes tant cette manière de travailler peut sembler peu naturelle. Au début, on fait peu de choses pendant la phase de REFACTOR alors que cette phase est au moins aussi importante que les deux autres, aussi je pense qu'il faut y prêter une attention particulière dans les premiers temps (penser à refactorer le code mais aussi les tests par exemple).

Cependant, une fois maîtrisé, le TDD permet d'obtenir très rapidement du code de très bonne qualité avec des efforts réduits. Je n'ai pas de statistiques précises mais, de mon expérience, il est tout bonnement impossible pour un développeur ne pratiquant pas le TDD de s'approcher de la vélocité d'un développeur travaillant en TDD !

Bien, ce court rappel étant fait (le but de l'article n'étant pas de présenter ou de convaincre de l'utilité de la méthode), voyons maintenant comment l'apprendre.

Gagner du temps dans son apprentissage

Même s'il est tout à fait possible d'apprendre seul le TDD, il sera beaucoup plus facile de bénéficier de l'expérience de nos pairs qui ont déjà fait cet apprentissage.

Un excellent moyen est de trouver une personne pouvant vous accompagner dans votre quotidien. Si cette personne n'existe pas dans votre entreprise, vous pouvez peut-être faire intervenir un prestataire ?

Vous pouvez peut-être aussi participer aux meetups des crafters de votre ville (si vous habitez à proximité d'une grande ville il y a surement un groupe).

Vous pouvez aussi lire des livres sur le sujet (Test Driven Development: By Example ou Working Effectively with Legacy Code) ou participer à des conférences.

Dans tous les cas et comme pour tous les apprentissages, pensez à remettre régulièrement en question les enseignements que vous allez recevoir sur ce sujet. Encore une fois, le TDD est malheureusement très mal compris et beaucoup penseront bien faire en parlant uniquement de test first.

Commencer par des exercices simples

Quand j'ai commencé le TDD, je l'ai fait sur la base de code sur laquelle je travaillais à ce moment-là (une application Struts avec des méthodes atteignant facilement les milliers de lignes). Avec le recul, je pense que j'aurais adoré connaître l'existence des code katas pour m'essayer doucement à cette nouvelle approche.

La métaphore des code katas vient des arts martiaux, on les pratiques dans des Coding Dojo et, comme pour les kata dans les arts martiaux, ils sont fait pour être répétés plusieurs fois jusqu'à la maîtrise d’une technique donnée.

Les katas permettent donc de s'entraîner à différentes techniques, pour le TDD je vous conseille (dans cet ordre) :

Et si vous voulez vous entraîner de manière plus spécifique aux techniques de refactoring :

Je ne peux que trop vous conseiller de faire ces katas puis de vous entraîner à les refaire régulièrement. Trivia mis à part, tous les katas de cette liste sont faisables en moins de 10 minutes donc n'hésitez pas à utiliser des petits moments morts de la journée (retour de déjeuner, avant une réunion, etc) pour en faire rapidement un.

Quand vous serez suffisamment à l'aise en TDD sur des petits exercices, vous pourrez commencer à inclure cette technique dans votre quotidien !

Au quotidien

Une question qui m'est souvent posée est : "Je veux faire du TDD mais je suis sur un code legacy pas vraiment testable, comment je fais pour commencer ?". Dans ce genre de cas je répond : "Ne commence pas sur ce code !".

En fait, réussir à tester ce type de code demande un peu d'expérience en TDD et, pour commencer, je vous conseille plutôt d'appliquer la technique sur du nouveau code que vous allez faire. Créez des classes très simples qui répondront à un besoin précis et faites-les en TDD.

Lorsque vous allez commencer le TDD, vous serez en phase d'apprentissage, et, scoop : ON NE VA PAS VITE QUAND ON APPREND ! Aussi frustrant que cela puisse être, vous allez perdre en vélocité pendant votre apprentissage. Il faut être prêt à l'accepter.

De mon côté, ayant appris le TDD seul et dans un contexte difficile, j'ai certainement fait le plus mauvais choix possible : j'ai fait des heures (beaucoup - trop - d'heures)  pour pallier à cette perte de vélocité. Je ne conseille vraiment pas cette approche, je pense qu'il est beaucoup plus efficace de transitionner progressivement vers le TDD et de rattrapper le temps à apprendre sur le temps où l’on travaille "comme avant". Enfin, en fait je n'en sais rien. C'est à vous de trouver comment faire. Sachez cependant que vous allez perdre en vélocité pendant un certain temps (Allant, je pense, d'un mois en étant très bien accompagné à… beaucoup plus).

Pendant cette phase de votre apprentissage, il faudra non seulement s'approprier la technique mais aussi tous les outils et patterns permettant de tester efficacement du code. Aussi, je pense que le temps nécessaire peut grandement changer en fonction des technologies que vous utilisez. Sur des technologies peu matures, vous devrez certainement vous fabriquer vos propres outils !

Cependant, si vous vous accrochez, vous allez atteindre le point d'équilibre : ce moment où votre vélocité sera la même en faisant du TDD que sans faire de tests.

Le point d'équilibre

Bien sûr, il ne s'agit pas réellement d'un point dans le temps, personne n'a de métrique suffisamment précise de sa vélocité pour pouvoir dire "c'est arrivé le 4 Mai 2012 à 13h37, je me rappelle très bien c'était un vendredi !".

Il s'agit plus ici d'un ressenti général, d'un moment où l’on fait encore du code sans TDD "par habitude" mais à chaque fois, on se dit qu'on a quand même perdu du temps… C'est à partir de ce moment que le TDD devient une évidence dès que l'on fait du code.

A partir de là, les choses s'accélèrent (en tout cas c'est le ressenti que j'en ai eu). On commence à apprendre BEAUCOUP plus vite, tout devient plus facile de jour en jour. Très rapidement, les points techniques qui nous semblaient être la principale difficulté dans la réalisation d'une application (connexion à la persistance, échanges avec d'autres services, …) ne deviennent qu'un détail que l'on ne prend maintenant que vaguement en compte dans nos chiffrages !

Pour moi, c'est à partir de ce point que le travail précédent a commencé à payer. Je ne sais pas dire précisément mais il m'a fallu quelques mois pour en arriver à ce point. Ces mois ont été compliqués pour moi car je n'étais pas sûr de mon choix. Je n'avais aucun mentor, aucun collègue travaillant de cette manière et qui aurait pu me conforter sur les gains de cette méthode de travail.

Aujourd'hui, je suis très content d'avoir investi du temps et de l'énergie dans l'apprentissage du TDD puisque c'est, sans conteste, un des skills qui me facilite le plus le quotidien.

Vers la qualité et la vélocité

Plus on avance dans la maîtrise de TDD, plus on avance dans la maîtrise globale des techniques de notre industrie, aussi je ne peux que trop vous conseiller d'essayer :

  • No estimates: vraiment, le gain de temps et d'énergie est phénoménal ;
  • Le Domain Driven Design: c'est une grosse marche avec un ticket d'entrée très cher mais ça en vaut, là aussi, largement la peine.

De mon côté, je suis certainement au début d'un chemin dont je ne connais pas encore l'existence. Tout ce que je sais, c'est que j'ai hâte de découvrir toutes ces techniques et approches qui rendront mon quotidien encore plus amusant !

La technique du Pac-Man appliquée

$
0
0
La technique du Pac-Man appliquée

Ah, Pac-Man ; un jeu mythique ; un gestionnaire de paquets pratique mais aussi une super technique !

Si vous avez déjà participé à une conférence, vous savez certainement qu'on apprend au moins autant entre les talks que pendant (c'est d'ailleurs cette observation qui a créé les unconferences).

Pendant ces pauses, si on regarde les discussions depuis un point en hauteur, les groupes ressemblent normalement à ça :

La technique du Pac-Man appliquée

De petits groupes de personnes qui se connaissent et se rassemblent pour parler de divers sujets ! C'est précisément dans cette situation qu'il est conseillé d'appliquer la technique du Pac-Man et de changer la disposition du groupe pour celle là :

La technique du Pac-Man appliquée

En laissant une ouverture dans le groupe, une nouvelle personne pourra rejoindre la conversion beaucoup plus simplement. Lorsqu'une nouvelle personne se joint à la discussion, il faut ouvrir de nouveau le Pac-Man !

Simple non ? Mais est-ce que ça marche réellement ? Lors de DDD Europe 2020, Mathias a lancé la Main conference en expliquant ce principe et en demandant aux participants de l'appliquer s‘ils le souhaitaient. La conférence étant internationale, il a aussi demandé à tout le monde de parler anglais, y compris avec les personnes avec lesquelles on aurait normalement parlé dans une autre langue.

En utilisant cette technique pendant les jours qui ont suivi, nous avons pu parler à plusieurs dizaines de personnes que l'on ne connaissait pas ! Nous avons eu des échanges passionnants avec des professionnels de multiples nationalités et travaillant dans des contextes très différents.

Dans cette conférence, ce qui a fonctionné pour notre petit groupe de Français était de "s'inviter" dans les groupes qui semblaient ouverts en demandant s’ils étaient en train de pratiquer cette technique (et en proposant de partir si les personnes ne souhaitaient pas échanger avec nous). D'autres ont choisi de rentrer silencieusement dans les groupes mais, dans tous les cas, nous avons pu valider le fonctionnement de cette approche.

De ce que nous avons vu, cela fonctionne bien jusqu'à des groupes de 5 / 6 personnes. Après, les groupes ont tendance à se refermer mais ce n'est pas forcément un mal : il est compliqué de parler avec autant de personnes dans un hall bruyant (j'y ai d'ailleurs laissé ma voix…).

Cette simple technique a rendu notre conférence encore meilleure. Aussi, je ne peux qu'inviter les organisateurs d'événements à proposer son application ! Je pense qu'il existe peu d'approches aussi efficaces permettant les échanges entre les participants d'un événement. De plus, celle-là ne coûte rien !

Apache Knox, l’API gateway d’Hadoop

$
0
0

Introduction

Apache Knox, l’API gateway d’Hadoop

Dans le cadre d’une mission, j’ai eu l'opportunité d'étudier la solution d’Apache Knox et d’analyser sa réponse à certains use cases, dont son utilisation dans une architecture On-premises composée de clusters Hadoop.

Le but de cet article est de faire un petit tour sur cette technologie pour présenter brièvement et simplement : son concept, son fonctionnement, ses cas d’utilisation et la pérennité de cet outil Apache peu connu.

Le concept

Apache Knox est l’API Gateway de la fondation Apache. Créé en 2013, il vise à répondre à des besoins de sécurité des clusters Hadoop.

Une API (Application Programming Interface) Gateway est une application qui permet d’avoir accès à un groupe de services via une entrée unique.

Concrètement, dans le cas de Knox, elle permet aux applications extérieures et aux clusters d’avoir accès aux différents frameworks de Hadoop (Hive, Map Reduce, HDFS, etc.) et de les utiliser via un seul canal.

Tout cela peut se résumer avec le schéma suivant :

Apache Knox, l’API gateway d’Hadoop

Sur cette illustration, nous avons à gauche : des utilisateurs qui peuvent être des applications (comme Tableau Software), des personnes qui font des requêtes directes (via Beeline par exemple), des jobs, etc. Ils souhaitent interroger un framework Hadoop via une requête HTTP.

L’initiateur de la requête va dans un premier temps envoyer la requête à Knox qui va interroger le service d’autorisation et/ou d’authentification (tel que Kerberos, Shiro, LDAP, etc.) afin de savoir si cet utilisateur a le droit de contacter le service concerné. Ensuite, Knox va aller interroger un service Hadoop, et retourner la réponse à l’utilisateur.

Cela permet donc de :

  • Protéger les informations du cluster de l'extérieur car on ne s’y connecte plus directement mais via Knox,
  • Diminuer le nombre de services avec lesquels le client doit interagir car désormais il communiquera uniquement avec Knox,
  • Simplifier le mécanisme d’authentification en n’en utilisant qu’un seul basé sur du HTTP, dans le cas où les clusters sont déjà sécurisés.

En terme de sécurité, Knox fonctionne avec les différentes couches d’autorisation et d’authentification des clusters Hadoop. Il est donc utilisable avec Apache Ranger, Kerberos , le protocole LDAP, ... et s'intègre bien avec les principaux IMS (Identity Management Solutions) du marché .

Fonctionnement

Je vais maintenant vous montrer comment Knox s’utilise de manière concrète en nous connectant à Hive.

Pour cela, le graphique suivant complète le précédent en vous montrant ce qu’il se passe dans Knox lors de l’envoi de la requête par un utilisateur :

Apache Knox, l’API gateway d’Hadoop

Pour appuyer cette illustration et mieux comprendre la suite, voici quelques définitions :

  • Topology : C’est l’endroit où l’on va retrouver l’ensemble des services. Il peut y avoir plusieurs topologies dans le cas où l’on souhaite que les services appelés varient en fonction des utilisateurs ou autres paramètres.

  • Service : Une topologie contient plusieurs services. Chaque service contient au minimum un rôle et une URL.

  • Rôle : Le rôle est contenu dans le service, il indique quel framework on appelle. Dans notre exemple, nous appelons Hive, mais cela aurait pu être WebHDFS, WebHCat, Oozie, HBase, Yarn, Kafka et j’en passe.

Dans un premier temps, l’utilisateur va envoyer un message HTTP en direction de Knox (par défaut https://localhost:8443/…). Le message contiendra :

  • la topologie avec laquelle il souhaite interagir (ici la topologie “default” configurée dans le fichier default.xml),
  • le rôle, qui sera l’application avec laquelle il souhaite communiquer (ici Hive),
  • un user et un mot de passe si besoin,
  • la requête (par exemple “show tables”).

Dans le fichier default.xml du dossier Topologies, il va directement aller voir quel service a pour rôle “Hive” et ainsi contrôler le user et le mot de passe.

Si tout est bon en terme d’autorisations, Knox va envoyer la requête à l’URL indiquée, qui est l’URL de Hive. La requête est transmise à Hive, qui y répondra. Knox renverra alors la réponse de Hive aux utilisateurs.

En résumé, Knox va véritablement agir comme un Proxy qui permet au client de communiquer avec les serveurs Hadoop via un seul point d’accès.

Attention, en aucun cas Knox ne suffira comme seule couche de sécurité  :

  • Dans notre cas, l’URL de Hive reste toujours active donc, sauf paramétrage particulier, nous pouvons toujours passer par cette URL pour d’autres services.
  • En aucun cas Knox ne permet de remplacer Kerberos, ou les autres couches de sécurité citées à la fin de la première partie : les services sont complémentaires.

Les cas d’utilisations

Maintenant que nous comprenons le fonctionnement de base de l’outil, il est temps de parler de ses cas d’utilisations.

Knox est fait pour être utilisé dans un environnement avec des clusters Hadoop.

Il permettra de répondre à ces besoins :

  • Étendre/simplifier les accès aux clusters sans perdre en sécurité,
  • Simplifier les configurations de sécurité des clusters.

Il peut être utilisé dans un EMR AWS (clusters Hadoop dans le cloud d’AWS) comme le montre cet article.  

Knox est donc utilisable comme API Gateway pour des clusters Hadoop dans un environnement On-premises mais aussi Cloud, qu’il soit public ou privé, ce qui étend considérablement ses possibilités. D’autant plus que les API Gateway potentiellement proposées par ces services, comme AWS API Gateway ou Cloud Endpoint, ne permettront pas forcément de proxifier des clusters Hadoop comme le fait Knox.

Il peut aussi répondre à des cas d'utilisations plus particuliers  :

  • authentification (en LDAP, SSO, SAML, etc.),
  • autorisation (il dispose de son propre ACL),
  • configuration de Kerberos (en l'encapsulant, évitant ainsi des configurations côté client).

De plus, certaines distributions comme Cloudera (et Hortonworks pour ceux qui sont sur une ancienne version) proposent de l’installer directement via leur UI (User Interface). En revanche, même si l’installation via l’UI est parfois possible pour les Data platforms, je vous conseille de faire bien attention à la version qui est utilisée.

Personnellement, j’ai commencé avec la version 0.12 de Knox, qui était la version de base dans mon SI. Je me suis ensuite décidé à passer sur la v1.3 qui est beaucoup plus stable, avec une bonne documentation et contient plus de fonctionnalités (comme l’intégration de Kafka et d’Elasticsearch par exemple !)

Pérennité

Avant d’envisager toute mise en prod de ce genre d’application, il faut être sûr de sa pérennité. D’autant plus que Knox reste assez peu connu. J’ai donc fait cette analyse en allant sur le repository GIT de l’application, son Jira et en consultant Google Trend

À l’heure où j’écris cet article, sur leur Github, il y a 42 contributeurs. Certes cela peut sembler peu, mais le repo est  très actif avec des commits quasi quotidiens.

Le nombre de commits est potentiellement lié au nombre de tickets Jira ouvert ( 227 tickets ouvert pour 80 environ tickets de types bug), ce qui peut nous faire émettre quelques réserves vis-à-vis de la stabilité de l’application.

Il faut également souligner que beaucoup des commiteurs sont de Cloudera et anciennement d’Hortonworks.

Il y a une plus forte activité depuis la version 1.3 parue en juillet 2019, ce qui rassure sur la pérennité du projet, d’autant plus qu’on remarque que le nombre de recherches sur Apache Knox est stable par rapport à 2016.

Le point noir par rapport à la durabilité de Knox est que l’on manque de visibilité sur les entreprises qui l’utilisent, bien qu’il ait été porté par Hortonworks et aujourd’hui Cloudera.

En bref, à la vue des informations citées précédemment, je pense que cette application sera maintenue et mise à jour, tant que les Data platforms comme Cloudera existeront.

Conclusion

Je vous ai ainsi présenté le fonctionnement de Knox d’un point de vue simplifié et généraliste, afin de vous faire connaître cette application et ses possibilités.

Je pense que ce framework d’Apache a totalement sa place sur les gros SI, avec des clusters Hadoop en On-premises ou Cloud, et c’est normal car il a été développé pour ça ! Cela permet faciliter les différents accès aux clusters et dans certains cas cela peut même simplifier l'implémentation de protocoles.

Pour mener à bien cette étude, je me suis appuyé sur la documentation et sur cet article assez complet, que je vous conseille de consulter si vous voulez aller plus loin sur Apache Knox.


Un EventStorming avec Alberto Brandolini

$
0
0
Un EventStorming avec Alberto Brandolini

Nous animons des EventsStorming chez nos clients depuis quelques temps déjà et, à DDD Europe 2020, nous (Anthony et Colin) avons pu participer à un atelier de 2h avec Alberto Brandolini (créateur de l'atelier).

Le but était de modéliser un Domain que nous avons tous découvert pendant la session : un expert du domain était présent et il a présenté pour la première fois à tout le monde (Alberto compris) le métier qui devait être modélisé.

Comment nous animions cet atelier avant de le faire avec Alberto

Pour cet atelier nous avons habituellement ces pré-requis :

  • Un sujet à traiter, cela peut être un système complet ou un point particulier ;
  • Au moins 2h de réelle disponibilité pour tous les participants ;
  • Un facilitateur qui assurera le bon déroulement de l’atelier et la participation bienveillante de tout le monde ;
  • Une petite dizaine de participants travaillant sur le domain avec des experts du domain et des développeurs. Cet atelier fonctionne éminemment mieux si tous les participants sont dans la même pièce ;
  • Un mur virtuellement infini ;
  • Une salle dont on enlève les chaises : les participants doivent rester debout ;
  • Un rouleau de papier et du scotch pour recouvrir et protéger votre mur ;
  • Des posts-its de différentes couleurs, à minima : orange, bleu, jaune, rose fluo et rose clair (selon le déroulement et le but recherché vous pouvez avoir besoin d’autres couleurs) ;
  • Des stylos / feutres fins pour tous les participants.

Une fois ces éléments rassemblés, le mur protégé et le tuto sur le décollage de post-its fait, on distribue des posts-its oranges à tous les participants. Sur ces posts-its on va chercher à identifier les événements, ils sont :

  • Au passé : ce sont des choses qui se sont passées ;
  • Simple : pas de description complexe ;
  • Partagés : tous les participants doivent être d’accord sur les termes ;
  • Compréhensible par tous : pas de termes techniques ici, on note les événements métier.

À ce moment les experts du Domain vont commencer à nous raconter l'histoire du traitement que l'on cherche à modéliser. Tout le monde peut couper à tout moment pour demander ou apporter des précisions mais surtout pour noter les événements qui sont en train d’être mis en lumière.

Pendant 20 minutes chacun va donc proposer et noter des événements que l’on va placer au mur sur des post-its orange dans l’ordre chronologique (de gauche à droite).

Un EventStorming avec Alberto Brandolini
Des premiers événements (après 20 minutes)

Les photos sont tirées d’une vidéo live que nous avons faite d’un EventStorming. Cela explique la piètre qualité et les mauvais cadrages (pour trouver les rares moments où personne n’est devant les post-its)...

Une fois ces 20 minutes passées prenez 5 minutes de pause pour expliquer l’utilité des post-its roses : noter les questions en suspens. L’idée n’est pas de chercher une réponse si on ne peut l’avoir tout de suite (manque d’information, manque de connaissance, …) mais simplement de noter que ce point est en suspens.

Dans certains cas vous aurez eu besoin de présenter les post-its roses avant cette pause. Ne laissez pas les gens chercher des solutions s'il est évident qu’elles ne peuvent pas apparaître en session !

Profitez aussi de ces 5 minutes pour prendre un peu de recul, recentrer tout le monde et fusionner les doublons si de petits groupes se sont naturellement formés.

Reprenez ensuite pour une nouvelle session de 20 minutes à trouver des événements (et des questions).

Un EventStorming avec Alberto Brandolini
Nos événements après 2 sessions de 20 minutes

À ce stade deux options :

  1. Il est évident qu’il vous manque des événements : vous pouvez repartir pour une session de découverte d'événements ;
  2. Les événements semblent être clairement trouvés : vous pouvez alors présenter trois nouvelles couleurs de post-it :
    1. Bleu : Ce sont les commandes, des actions qui permettent le déclenchement d’un événement. Ce sont des verbes à l’infinitif ;
    2. Jaune (pouvant être coupés en deux) : Ce sont les acteurs qui déclenchent les commandes ;
    3. Rose clair : Ce sont les systèmes externes qui déclenchent les événements (messages, temps, …) ;

Les déclencheurs doivent être positionnés à gauche des événements qu’ils déclenchent (si un événement en déclenche un autre on garde donc l’affichage temporel). Les acteurs sont ajoutés en bas à gauche des commandes :

Un EventStorming avec Alberto Brandolini
Positionnement des déclencheurs

Il est fréquent de vouloir mettre des commandes à la place des événements dans les premières boucles. La grande idée de cet atelier est justement de commencer par ce qui se passe réellement sur le système : il faut être très vigilant et ne pas faire apparaître les commandes trop tôt.

Si vous avez vos événements vous pouvez alors partir pour 20 minutes de découverte de déclencheurs de vos événements.

Un EventStorming avec Alberto Brandolini
Nos déclencheurs

Selon le but recherché par cet atelier vous pouvez vous arrêter là, vous avez déjà :

  • Une bien meilleure compréhension du métier pour toutes les personnes présentes ;
  • Un Ubiquitous Language ;
  • Un processus modélisé (et dont la timeline est clairement représentée) ;
  • Une vision des principales actions et événements qui doivent être codés.
Un EventStorming avec Alberto Brandolini

Vous pouvez cependant faire le choix d’aller plus loin dans cet atelier pour faire apparaître les Aggregates sur des posts-its jaunes. Pour cette étape vous allez devoir détruire la notion de temps pour regrouper vos déclencheurs et événements devant être manipulés ensemble.

Le but ici est de rechercher des transactions métier : ensembles d’éléments qui, pour le métier, ont une cohérence uniquement s'ils sont manipulés ensemble. Ces regroupements doivent être les plus petits possible (pour permettre une vérification des règles métier).

Lorsque ce point est compris vous pouvez rechercher ces Aggregates pendant une petite dizaine de minutes (cette étape est plus rapide que les précédentes).

Un EventStorming avec Alberto Brandolini
Quelques-uns de nos Aggregates (avec des posts-its verts…)

L’étape suivante est l’identification des Bounded Contexts : on va regrouper les Aggregates dans les plus petits ensembles possibles répondant à un métier donné. Pour cette étape on va déplacer de nouveaux les post-its pour pouvoir dessiner les Bounded Contexts au feutre sur le papier.

On va différencier deux types de Bounded Contexts :

  • On va tracer en pointillé ceux qui sont essentiels mais qui ne font pas directement la valeur ou la plus value de notre solution ;
  • On va tracer en trait plein celui qui, d’un commun accord, est le coeur de notre domain.
Un EventStorming avec Alberto Brandolini
Deux de nos Bounded Contexts

Tous les participants ont maintenant une bonne vision d’ensemble de beaucoup d’éléments de design que nous avons déjà évoqués (et même de certains qui n’ont pas encore été présentés).

Cet atelier peut être utilisé pour modéliser tout un système ou un sous ensemble de celui-ci, c’est à vous de voir. Dans tous les cas ne faites pas de session de plus de 2h, préférez plusieurs ateliers de 2h si le sujet est trop volumineux pour être traité en une fois.

Comme pour tous les ateliers prenez le temps de prendre un retour d’expérience de tous les participants.

Ce qui change dans la manière de faire d'Alberto

Lors de l’atelier que nous avons pu suivre avec Alberto, un expert métier (Brian) nous a présenté son besoin et pour nous montrer comment le modéliser, seul Alberto faisait l'analyse sous la forme d’un EventStorming.

La première chose qui frappe est l'animation de l'atelier : Alberto impose un rythme très soutenu, il est très dynamique et on sent clairement que c'est volontaire !

Avant de commencer l'atelier il nous explique la règle principale : au vu du nombre de personnes dans l'audience nous n'avons pas le droit d'intervenir oralement. Si nous avons une idée ou quelque chose qui ne nous convient pas nous devons prendre un post-it rose et simplement le placer sur le mur.

Le métier se situe dans le domaine bancaire et la première idée est de trouver le scénario le plus simple pour arriver au but de l’application à modéliser.

Pour trouver ce scénario minimal, Alberto a identifié plusieurs cas possibles :

  • Un échange entre particuliers ;
  • Un échange avec un vendeur ;
  • Des échanges differents selons les règles en vigueur dans d’autres pays.

Dans notre cas, l’idée est de représenter l’échange entre particuliers, c’est-à-dire tout ce qu’il se passe entre l’activation d’un compte et une somme monétaire reçue par une seconde personne.

Pour se faire, il a positionné le premier événement avec un post-it orange à gauche du support papier sur le mur pour indiquer le compte du particulier activé.

Immédiatement après, il s'est concentré sur le dernier événement pour représenter le but à atteindre, c’est-à-dire le paiement reçu par l’autre particulier. Il a pris du temps pour identifier ce point : savoir quelles sont les bornes de l'atelier est vraiment un point essentiel au bon déroulement.

Alberto prend sur lui l’ensemble des post-its dont il a besoin, il n’hésite pas à mettre des questions à l’aide des roses lorsqu’il veut indiquer un élément à creuser plus tard. En fait dès que quelque chose sort du scénario nominal qu'il à choisi d'étudier pour rendre un premier service il note un post-it rose (il y en a rapidement beaucoup).

Très vite, il sort les petits post-its jaune, ceux qui représentent les acteurs, non seulement pour les représenter mais aussi pour indiquer la satisfaction à l’aide d’un :) ainsi que la valeur business à l’aide d’un $.

Cette représentation que nous ne faisions pas dans notre atelier permet d’indiquer là où la solution a de la valeur pour l’entreprise et de la distinguer de celle qui a de la valeur pour l’utilisateur.

Contrairement à un atelier de découverte, Alberto positionne directement les vues via ses post-its verts, les commandes via les post-its bleus et les agrégats via les post-its larges jaunes sans représenter l'exhaustivité des autres événements avant.

Pour revenir sur la notion des vues, elles représentent les données visibles par un utilisateur mais aussi les données qui permettent de prendre des décisions en amont d’une commande. ou d’une policy (notion que nous allons aborder plus tard). Elles constituent ainsi ce qu’il appelle le Read model.

En discutant avec Alberto suite à l’atelier, nous pensons qu’il est plus pertinent de partir sur une approche plus classique, c’est-à-dire représenter d’abord les événements, plutôt que de tout représenter au fil de l’eau parce que ça nécessite d’avoir déjà pratiqué de nombreux EventStorming. Lui-même conseille, lors d’une découverte du métier, de ne pas aller trop loin pour représenter le métier.

En parallèle, durant l’atelier, il n’hésite pas à nous rappeler le but de l’atelier et suite à des remarques dans l'assistance, il introduit trois rôles :

  • The driller (celui qui va creuser le sujet) :
    • Les + : Il va aider à représenter l’exhaustivité du modèle ;
    • Les - : Il n’a pas de vision permettant d’aller vite à un résultat (qui est le but de l'atelier). Ce rôle peut ouvrir beaucoup d’embranchements n’apportant pas forcément beaucoup de valeur.
  • The pragmatic :
    • Les + : Il tranche rapidement et s'assure que l'atelier va vers sa cible ;
    • Les - : Il peut oublier de prendre en compte des détails importants pour le métier.
  • The empathic :
    • Les + : Il comprend les besoins des utilisateurs finaux et peut apporter des simplifications nécessaires notamment dans les vues (ou faire ajouter des vues). Il peut aussi insister sur un cas qui doit être creusé et non pas noter comme un point en suspens ;
    • Les - : Il peut ne pas avoir assez de recul pour être capable de s’arrêter sur un détail.

Pour Alberto, pour un EventStroming réussi, ces trois rôles doivent s'équilibrer : The pragmatic doit éviter que the driller consume tout le temps de l'atelier à creuser des détails de détails. The empathic doit quand à lui s'assurer que les besoins des utilisateurs sont au centre de l'analyse (et qu'on ne se concentre pas uniquement sur des problématiques techniques comme peut avoir tendance à le faire the pragmatic).

Un EventStorming avec Alberto Brandolini

Suite à cet aparté, Alberto reprend et introduit la notion de Policy (sur des post-it lilas), qui permet de représenter des décisions et ainsi mettre en lumière des règles métier.

Depuis son introduction à EventStorming, Alberto indique que cette notion apparaît lorsqu’une réaction commence par le mot "lorsque" ou "à chaque fois". Il donne ainsi deux exemples avec "whenever the exposure passes the given threshold, we need to notify the risk manager" et "whenever a user logs in from an new device, we send him an SMS warning".

En l’interrogeant à ce sujet pour savoir pourquoi Alberto introduit cette notion dans ses ateliers, il nous a expliqué que c’est suite à un retour de Greg Young qui lui a demandé explicitement de parler de cette notion qu’il n’introduisait pas ou rarement dans ses ateliers jusqu’à présent.

L’avantage de cette notion permet selon lui de détailler ce qui est changeant dans le métier de ce qui ne change pas ou peu. Avec le recul, il remarquait que les agrégats n’étaient pas assez complets et ne parlaient pas assez aux experts métiers alors que les policies semblent avoir plus de sens pour eux.

C’est sans doute l’outil des EventStorming que nous connaissions le moins ! Cet ajout change grandement la forme du l'atelier.

Avec ces notions voici l'ordre suivi pendant l'atelier :

Un EventStorming avec Alberto Brandolini

Après une grosse demi-heure de modélisation il s'est passé un événement important : nous avons atteint un point ou un changement de context semblait évident. Alberto a alors marqué clairement ce changement avec de l'adhésif jaune. Même si nous ne modélisons pas directement la solution dans cet atelier il est très possible que ces deux parties finissent par être dans des Bounded Contexts différents.

Après un peu plus d’une heure, Alberto a su représenter le domaine métier décrit par Brian dans une vision très simple.

Souvent il y a de la frustration avec les produits minimum viables (MVP) lorsqu’on travaille avec un client puisque, pour le réaliser, il faut parfois passer plusieurs mois. Faire cet atelier en se concentrant sur un cas d'utilisation aboutissant au rendu d'un premier service permet d'avoir une première version fonctionnelle en production.

Pendant le temps restant, Alberto a modélisé des scénarios laissés en suspens sur des post-it roses en cherchant toujours à avoir un utilisateur satisfait.

Pour terminer voici une partie de notre Domain final (avec Alberto répondant un point soulevé par l’audience qu’il pourra par la suite représenter sur le mur) :

Un EventStorming avec Alberto Brandolini

Ce qu'on va changer dans nos futurs EventStorming

Comme nous l'avons déjà dit nous allons probablement garder l'ordre que l'on utilise actuellement qui est plus simple pour des analystes qui ne sont pas Alberto.

Nous allons cependant nous essayer aux Policies et aux Read Models mais nous allons surtout changer le rythme "imposé" par le facilitateur tout en se concentrant beaucoup plus sur un seul cas d'utilisation (avec beaucoup plus de post-its roses).

Même si nous ne savons pas encore de quelle manière, il est certain que ces deux heures avec le créateur de l'atelier vont changer notre manière de l'utiliser. Peut-être écrirons-nous un article dans quelque temps expliquant tout ça.

De l'importance du format de la donnée : Théorie (Partie 1/2)

$
0
0
De l'importance du format de la donnée : Théorie (Partie 1/2)

Être Data Engineer c’est beaucoup de développement, mais ce n’est pas que ça ! Une partie du travail consiste à optimiser les traitements, aussi bien sur leur temps d’exécution que sur l’espace requis. Pour ce faire, on peut amener des améliorations sur le hardware, en scalant horizontalement ou verticalement les nœuds d’un cluster ainsi qu’en variant la taille des disques.

Le format des données utilisé est un facteur jouant sur l’espace requis mais aussi sur le temps d’exécution des traitements. Cet article a pour but d’expliquer les principaux formats utilisés actuellement dans l’écosystème Data et d’aider à la prise de décision lors du choix du format à utiliser.

De l'importance du format de la donnée : Théorie (Partie 1/2)

Ce Meme n'est pas une critique de l'Avro mais une critique du format qui n'est pas toujours correctement choisi. Avro est un super format !

Il est tout d’abord nécessaire de définir les notions qui vont être utilisées afin de partir sur une base commune. Il est indispensable de comprendre ces notion afin de pouvoir choisir le format le plus adapté à votre besoin, c’est la raison pour laquelle cet article sera entièrement consacré à la théorie et suivi d’un deuxième centré sur la pratique.

Les données d’exemple utilisées tout le long de cet article sont les suivantes (représentation tabulaire) :

De l'importance du format de la donnée : Théorie (Partie 1/2)

Stockage

Les formats de données existants aujourd’hui permettent de stocker celles-ci sous deux types différents : Row Storage et Columnar Storage.

Les Row storage stockent les données sur disque ligne par ligne. Le nième Nom sera toujours suivi du nième Prénom par exemple. Schématiquement les données seront séparées et stockées de la sorte :

De l'importance du format de la donnée : Théorie (Partie 1/2)

Quant aux Columnar storage (format colonne), elles stockent les données sur disque colonne par colonne. Le nième Nom sera toujours suivi du nième +1 Nom. Schématiquement les données seront séparées et stockées de la sorte :

De l'importance du format de la donnée : Théorie (Partie 1/2)

Si vous voulez creuser un peu plus ce thème, je vous conseille cette présentation.

Projection Pushdown

Le projection pushdown permet de ne scanner que les colonnes qui vont être utilisées dans le programme. Les formats de données colonne permettent de mettre en place le projection pushdown aisément.

Un exemple vaut mieux qu'un long discours : si on ne veut connaître que le Nom et le Prénom des individus de notre dataset d’entrée, le moteur de traitement saura qu’il n’est pas nécessaire d’aller lire les colonnes Age et Sexe. Par exemple, l’Optimizer de Spark (Catalyst) ne lira que les colonnes Nom et Prénom dans les fichiers d’origine lors de la requête suivante si le format de stockage sous-jacent le permet

scala> df.select(col("Nom"), col("Prenom")).show

Ainsi, grâce au projection pushdown, on a évité de lire inutilement 50% des données. C’est bien pensé quand même ...

Predicate Pushdown

Le predicate (ou filter) pushdown permet de filtrer des données en se basant sur les statistiques incluses dans les fichiers.

Par exemple, si on ne veut récupérer que les individus ayant 36 ans ou plus et admettons que le format de fichier utilisé inclut des statistiques sur l’Age. Le moteur de traitement saura qu’aucune donnée de notre dataset ne correspond à ce critère et ainsi retournera rapidement un résultat vide. En Spark Scala (évidemment) une commande utilisant ce predicate pushdown serait la suivante :

scala> df.filter($"Age"> 36).show

Les predicate/projection pushdown permettent d’économiser des I/O disque, du trafic réseau et donc du temps.

Compression

Compresser une donnée, c’est la représenter avec moins de bits que la donnée initiale. Il existe les compressions avec et sans perte.

La compression des données mériterait un article rien qu’à elle, c’est la raison pour laquelle ce sujet ne sera pas plus développé ici. En revanche, si vous avez un peu de temps, je vous conseille d’aller lire cet article (après la fin de celui-ci bien sûr !).

Il n’est pas rare que des données qui se suivent aient la même valeur dans certaines colonnes (e.g. Ville), la compression pour tous les formats colonne est donc souvent très efficace.

Lazy decompression

Prenons l’exemple suivant : on décide de lire des données selon une condition (même requête que le predicate pushdown, Age > 36) et notre format de stockage est orienté colonne. Il serait inefficace de décompresser toutes les colonnes pour rechercher seulement les lignes passant le filtre sur une seule colonne. C’est ici que la lazy decompression intervient. Comme on utilise un format colonne, on peut tout d’abord décompresser seulement la colonne correspondante (colonne sur laquelle le filtre est appliqué, ici Age) et repérer les lignes satisfaisant la condition pour enfin les décompresser.

Imbrication

Des données imbriquées (a.k.a. nested) ne sont pas représentées par une unique valeur mais par une autre structure de données (e.g. Liste, objet, Tuple, etc.). Certains formats ne supportent pas ce type de données, il est parfois donc nécessaire d’aplatir (a.k.a. flatten) les données imbriquées afin de pouvoir les convertir dans ces formats.

De l'importance du format de la donnée : Théorie (Partie 1/2)

Ci-dessus un exemple de donnée avant (Nested) et après (Flat) avoir été aplatie.

Compatibility

La problématique de la compatibilité entre deux versions de programmes n’est pas inhérente à la Data mais en fait entièrement partie.

Imaginons … une entreprise avec un SI assez simple : un programme A va écrire des données (data V1.0) sur un File System, que va ensuite lire un programme B. Elle décide de mettre à jour son SI et les nouvelles données transférées (data V2.0) auront un schéma différent que data V1.0. Les programmes A&B V2.0 sont donc pensés pour lire et écrire des données 2.0. Pour migrer son SI elle décide d’adopter une méthode Blue/Green. Des versions V1.0 et 2.0 des programmes et données vont donc cohabiter pendant quelques temps.

Si le programme B ne supporte pas l’évolution de schéma, il a de fortes chances de ne pas se terminer et lever des erreurs.

La Forward Compatibility tient dans le fait que le programme B en V1.0 puisse lire des données data V2.0, écrites donc par le programme A V2.0. Inversement, la Backward Compatibility est le fait que le programme B en V2.0 puisse lire des données data V1.0, écrites donc par le programme A V1.0. Ces deux types de compatibilité sont essentiels pour les programmes ayant besoin du schéma de la donnée.

Conclusion

Une fois avoir pris connaissance de toutes ces notions, on se rend compte qu’il est primordial de réfléchir au format à utiliser pour tous nos traitements. Nous en avons donc fini avec la théorie. Dans le prochain article de cette série, nous verrons les différentes implémentation de ces types de formats.

Dompter le domaine grâce aux moteurs de règles

$
0
0
Dompter le domaine grâce aux moteurs de règles

Dans la jungle du développement informatique, l’animal le plus féroce pourrait bien être votre domaine métier… Aujourd’hui, lorsque nous programmons, il est important de comprendre ce que nous sommes en train d’implémenter. Encore plus dans un contexte Agile où la discussion et le partage de la connaissance font partie intégrante dudit manifeste:

Business people and developers must work together daily throughout the project

Il est parfois compliqué pour un développeur et un Product Owner de se comprendre même si désormais il existe beaucoup d’outils et de façons pour échanger autour de ces sujets. C’est également le rôle du PO (je vous conseille cet article qui démystifie son rôle et ses préjugés) d’organiser son besoin et réussir à le faire comprendre aux développeurs. La mise en place de méthodologies comme le BDD (Behaviour Driven Development) permet justement d’avoir un meilleur partage de l’équipe dans l’écriture, la compréhension et la validation des comportements que devra respecter notre application, à travers l’écriture de scénarios fonctionnels (souvent écrits dans un langage dédié, généralement le Gherkin) qui mettront en lumière le besoin métier.

Dompter le domaine grâce aux moteurs de règles
ONE: Number 31, 1950, Jackson Pollock, MOMA, Museum of Modern Art, New York City

La fameuse Big Ball Of Mud (qui décrit l’architecture d’un logiciel sans architecture évidente) a tendance à arriver plus souvent qu’on ne le pense au sein d’un projet. En complément d’une conception aux petits oignons, il va cependant être utile pour votre domaine métier, qu’il soit maintenable et cohérent. Voyons ensemble les spécificités des moteurs de règles, leurs avantages et leurs inconvénients et bien sûr, une des manières de le tester.

Un moteur de règles : Késako ?

Un moteur de règles se base essentiellement sur un moteur d’inférence qui va être chargé de répondre aux conditions données sur les règles et les faits, afin de résoudre le cas en cours d’évaluation… Ou comme le dit si bien Martin Fowler, ici :

You can build a simple rules engine yourself. All you need is to create a bunch of objects with conditions and actions, store them in a collection, and run through them to evaluate the conditions and execute the actions.

Il va nous permettre de séparer les traitements et les données, qu’on appelle respectivement les règles et les faits. Les règles métier, en général, suivent une organisation semblable à un arbre de décision. Grâce à l’implémentation d’un moteur de règles, on va notamment pouvoir rendre modulable nos règles, et donc n’avoir aucun couplage fort entre les règles et le reste de notre application. A savoir, qu’un grand nombre de règles métier, bien évidemment, peut faire ralentir nos traitements…

Il existe principalement 2 types de moteurs d’inférence :

  • Le moteur par chaînage avant:
    • On part des faits et des règles et on en déduit une solution finale : le plus utilisé et le plus simple…
  • Le moteur par chaînage arrière
    • On part de la solution et on essaie de remonter jusqu’aux faits et aux règles : Utilisé principalement en IA et plus complexe à mettre en oeuvre...

En pratique

Nous allons mettre en place un moteur de règles simplifié qui va nous servir à la détection de forme (triangle ou quadrilatère). Commençons par nous créer un DSL pour écrire d’un côté les faits et les règles, par exemple :

Dompter le domaine grâce aux moteurs de règles

Imaginez 2 fichiers distincts contenant ces données qui sont donc séparées du reste de l’implémentation et compréhensibles par tout le monde. C’est un premier pas vers le partage de la connaissance et le couplage faible ! On est sur la bonne voie…

Ensuite, nous allons devoir valider les faits, c’est-à-dire calculer le nombre de côtés, connaître le nombre de côtés égaux, vérifier la présence d’angles droits… Ici, nous n’allons pas nous intéresser à ceci, je vous laisse libre dans le choix de l’implémentation 😊

Intéressons-nous, maintenant, au moteur de règles.

Pour lire notre DSL, il va bien sûr falloir utiliser un lexer (découpage de notre phrase en mots-clés reconnaissables) et un parser (hiérarchisation des mots-clés) … En général, on choisira d’utiliser les expressions régulières et un AST si on souhaite réaliser un moteur de règles poussé.

Côté Frameworks

En Java, il existe différents frameworks sur le marché comme Drools, qui intègre toute une suite d’outils autour du moteur de règles afin d’établir nos règles et les orchestrer grâce à une UI. D’autres frameworks comme OpenL Tablets sont de simples moteurs de règles n’intégrant que le strict minimum pour ne pas surcharger notre application.

La plupart des moteurs de règles (Java) respectent la JSR-94, définie comme étant la norme à suivre en matière de moteurs de règles (notamment dans le respect de l’API Rule Engine de javax.rules). Cette spécification répond aux besoins de la communauté en matière de réduction des coûts liés à l'intégration de la logique métier dans les applications et tente de donner un cap commun aux moteurs présents sur le marché.

Toutefois, il existe également de plus petits moteurs qui répondent tout à fait au besoin comme Easy-Rules mais qui ne suivent pas la JSR-94. Ces moteurs de règles peuvent donc différer en terme d’intégration et de performances : à utiliser avec précaution.

Les écritures de règles peuvent se faire dans un DSL normé (pas comme celles que j’ai définies au-dessus…) appelé MVEL. Il est généralement utilisé pour exposer les règles via une configuration (.xml, .yml, .drl...) ou par annotations.

Exemple simple de MVEL:

Dompter le domaine grâce aux moteurs de règles

Comment tester mon moteur de règles maintenant ?

Grâce à des outils comme Cucumber (Framework) et Gherkin (DSL), nous allons pouvoir définir conjointement avec le Product Owner, dans un langage commun (je rappelle que la clé du moteur de règles est de séparer les règles du code de l’application), le comportement de notre application, et ainsi tester nos différents cas possibles. Reprenons notre système de détection de polygones à 3 et 4 côtés.

Un exemple de tests écrits pour la détection des différents triangles suivant les faits et règles ci-dessus :

Dompter le domaine grâce aux moteurs de règles

De cette façon, grâce à la séparation ordonnée dans les règles et les faits, notre moteur de règles peut être testé dans sa globalité et dans un contexte fermé. Grâce à la mise en place des features Gherkin, ici, en anglais, nous avons pu organiser nos règles métiers de façon à pouvoir les faire évoluer simplement, et constituer également une documentation vivante !

Dompter le domaine grâce aux moteurs de règles

“Le BDD, qu’est ce que c’est?”, Arnauld Loyer, blog arolla.fr, 2012

L’implémentation de nos tests (dans le langage de notre choix) grâce aux différents Frameworks comme Cucumber (Java) ou SpecFlow (C#), vont nous permettre d’organiser notre test à la façon d’un scénario au format Given / When / Then, donc en Gherkin :

  • Given : un prérequis
  • When : une action
  • Then : un résultat

On peut également écrire les scénarios pour les quadrilatères:

Dompter le domaine grâce aux moteurs de règles

Conclusion

Nous n’avons pas abordé le cas des moteurs de règles sur de grands volumes de règles. Sur les cas ci-dessus, notre base de faits et de règles est plutôt minime et logique. En pratique, dans un contexte plus imposant, le nombre de cas devient vite exponentiel, et il est parfois complexe d’identifier chaque solution. Certains acteurs importants de l’IT comme IBM ou Red Hat, l’ont bien compris et ont créés des systèmes optimisés pour des traitements sur des centaines de milliers de règles… avec des outils de Big Data. Ces entreprises offrent généralement une prestation de conseil spécifique, comme par exemple lors de l’élaboration du projet (IBM) concernant les contrôles aux frontières des aéroports.

Quant aux tests, Il existe plusieurs papiers de recherche qui traitent de ce sujet, notamment ce papier de l’Université de Manchester qui propose une stratégie de tests sur de gros volumes à l’aide d’une base de données.

En début de projet, ou pendant une refactorisation, si vous pensez avoir (ou avez…) une quantité de règles de gestion importante (plus d’une dizaine), qu’elles évoluent au fil du temps, qu’elles font appel à des définitions métier complexes, je vous conseille d’utiliser un moteur de règles et d’y ajouter les tests d’acceptation comme vu précédemment. L’objectif est également d’ajouter ou développer la cohésion dans l’équipe et de faire une introduction au BDD. L’écriture commune des test cases est une étape importante dans la création de notre produit, elle vous fera gagner du temps et vous assurera un suivi de vos règles de gestion : So… try it 😎

Nos échanges avec les participants à DDD Europe

$
0
0
Nos échanges avec les participants à DDD Europe

Lors de DDD Europe 2020, avec Anthony, grâce à la technique du Pac-Man, nous avons pu échanger avec de nombreux professionnels intéressés par le DDD (puisque participants à la conférence) et nous avons posé en substance la même question à toutes ces personnes : "Quelle est la maturité d'utilisation du DDD que vous observez ?".

Cela va sans dire mais c'est toujours mieux en le disant : cet article ne reflète que les échanges que nous avons eus et nos avis ! Il ne s'agit absolument pas d'un état objectif du DDD !

Les réponses

Sans grande surprise, toutes les personnes avec qui nous avons pu échanger considéraient que le DDD était très loin d'être adopté ou connu. De leurs observations, la très grande majorité des applications sont basées sur des modèles anémiques et cela quelque soit le pays. Nous avons parlé avec des Français mais aussi des Belges, des Allemands, des Suisses, des Anglais, des Américains, des Italiens, des Portugais et bien sur des Néerlandais puisque la conférence était à Amsterdam : tout le monde partage ce constat !

Plus étonnant par contre au vu du lieu : les Speakers mis à part, la très grande majorité des personnes ne considéraient pas "faire du DDD" (quoique cela puisse vouloir dire). Si beaucoup étaient là pour découvrir, et dans une volonté d'adopter l'approche, certains considéraient aussi mal faire du DDD :

  • Parfois par manque d'implication des experts métier ;
  • Souvent à cause d'un mauvais découpage qui avait entraîné la création d'un monolithe distribué plutôt que de microservices !

Pour les personnes voulant adopter le DDD,  elles considéraient trop souvent le DDD comme une approche de design sur tableau blanc. De fait, les représentants de ces entreprises étaient trop souvent des personnes ne faisant pas de code au quotidien : Architectes d'entreprise ou Product Owners.

Notre réaction

Voyant que beaucoup de personnes imaginaient utiliser le DDD comme un simple outil d'analyse et de modélisation, notre discours à été systématiquement le même : nous avons parlé de nos convictions personnelles pour l'adoption du DDD !

Dans l'état actuel de notre compréhension et de réflexion, il n'est absolument pas pertinent de faire du DDD (là encore quoique cela puisse vouloir dire) sans maîtriser le Test Driven Development.

Le premier constat menant à cette réflexion est qu'il est primordial d'impliquer le développement dans la modélisation : "Hands-on Modelers" ! En se contentant de faire des analyses "hors code" on ne pourra pas capturer toutes les subtilités du Domain car seul le code demande de résoudre tous les détails. En réalité, la seule vraie représentation du Domain c'est le code, pas ce qui est sur le tableau !

Un autre constat menant à cette réflexion est que la capacité à faire du Refactoring (et plus précisément du Refactoring Toward Deeper Insight) est essentielle au DDD. On ne peut pas modéliser correctement notre Domain du premier coup. Certains implicites vont devenir explicites en avançant sur le projet. De fait, dès qu'une nouvelle compréhension apparaît, il est nécessaire de faire un Refactoring dans le code pour refléter cette nouvelle compréhension (et faire apparaître les nouvelles notions).

Un développeur travaillant en TDD fera une bonne centaine de Refactorings par jour aussi ce type d'opération est un non événement. Une pratique saine du TDD nous permet de changer parfois en profondeur une solution en étant guidé et avec un filet de sécurité assurant la non régression à chaque changement.

A l'inverse, s'il n'y a pas de pratique du TDD, sans cette habitude du Refactoring et sans filet de sécurité, les Refactorings nécessaires pour faire apparaître cette nouvelle compréhension ne seront tout simplement pas totalement faits. Plusieurs raisons à cela :

  • Sans habitude des pratiques, faire un Refactoring prend beaucoup de temps et d'énergie : deux ressources très limitées dans les journées d'un développeur ;
  • Sans filet de sécurité, on n'osera pas faire de Refactorings "violents", on ne fera que de toutes petites opérations de peur de casser un traitement.

Un autre point essentiel, pour nous, à la pratique du TDD comme pré-requis au DDD est en fait la puissance de design offerte par le TDD (oui, le TDD est une pratique de design par les tests, pas uniquement une pratique de tests). Aujourd'hui, nous n'avons pas expérimenté de meilleure technique que le TDD pour designer nos solutions !

Lorsque maîtrisé, le TDD permet de faire des designs élégants, pertinents et pragmatiques dans un temps extrêmement réduit ! Les solutions produites de cette manière répondront correctement aux problèmes posés sans chercher à répondre à des problèmes qui n'existent en fait pas (et qui n'existeront probablement jamais). Ce type de design est exactement celui que l'on cherche à produire avec le DDD, les deux approches sont complémentaires et doivent être utilisées conjointement !

Enfin, un dernier point qui, pour nous, justifie d'apprendre le TDD avant le DDD est l'utilisation d'une Clean Architecture (nous utilisons essentiellement Ports and Adapters). Lorsque l'on veut faire du TDD, il est naturel de faire apparaître cette Separation Of Concerns pour pouvoir tester chaque élément de notre solution d'une manière adaptée.

Ce type d'architectures étant essentiel pour la protection du Domain Model, et donc au DDD, nous considérons qu'il est très pertinent d'apprendre leurs utilisations et leur utilités par le TDD.

Malheureusement, apprendre le TDD demande du temps et de l'énergie donc nous avons humblement conseillé à nos différents interlocuteurs de commencer par le TDD avant de se lancer dans le développement d'un Domain Model.

Est-ce qu'on a bien fait ?

Les conversations que nous avons eues n'était absolument pas préparées et nos avis ont bien été présentés comme tels ! Nous n'avons absolument pas affirmé que c'était LA voie à suivre (ce qui aurait été stupide lors d'une conférence avec des speakers tels que Eric Evans, Kent Beck ou Alberto Brandolini).

Cependant, ces différents échanges ont permis la formalisation d'une réflexion qui était jusque-là une conviction personnelle que nous partagions sans vraiment le savoir.

Nous espérons avoir pu apporter une vision différente à certains participants mais, ce qui est certain, c'est que l'importance du TDD pour la pratique du DDD est maintenant bien plus claire pour nous !

De l'importance du format de la donnée : Pratique (Partie 2/2)

$
0
0
De l'importance du format de la donnée : Pratique (Partie 2/2)

Nous avons vu dans l’article précédent les principales notions liées aux formats de données. La théorie c’est bien, la pratique c’est encore mieux.

Voici donc une liste non-exhaustive des formats que l’on rencontre couramment dans les environnements Data.

CSV (Comma Separated Values)

Commençons doucement …

Sûrement un des formats les plus répandus. Il n’est pas propre au domaine de la Data et est utilisé par un large panel de métiers, notamment car il peut être facilement lu, que ce soit avec un éditeur de texte, des outils de reporting ou bien avec des tableurs tels que LibreOffice.

Ce format textuel est utilisé pour les données tabulaires et non imbriquées. Il embarque optionnellement le schéma dans la première ligne, appelée “header”, mais pas les types des valeurs. Chaque valeur est séparée par une virgule et chaque ligne est terminée par un retour charriot.

De l'importance du format de la donnée : Pratique (Partie 2/2)

On peut aussi trouver des formats CSV-like, où la virgule est remplacée par un autre caractère (Tabulation, Barre verticale, point virgule … ).

Ce format n’est pas utilisé pour les gros volumes de données car il n’offre pas de possibilité de compression, hors formats courants tels que zip. En revanche comme il s’agit d’un format lisible sans modification par l’Homme, il est souvent utilisé pour les petits datasets, l’exploration de données ou encore les tests.

Bon à savoir : Le type des données n’étant pas embarqué dans le format, une lecture de toutes les données avant de pouvoir inférer les types peut être nécessaire. Selon le framework utilisé, seules les n premières lignes sont utilisées pour inférer le type. Utiliser ce format est donc rarement une bonne idée en production.

JSON (JavaScript Object Notation)

Le bien-aimé JSON (/ʒizɔ̃/), souvent vu comme le XML 2.0, est un format de donnée textuel comme le CSV. Humainement lisible donc.

Comparé au CSV, il possède quelques avantages :

  • Le JSON permet de distinguer les chaînes de caractère des nombres, grâce à des guillemets. Néanmoins la distinction entre entiers et nombres flottants n’est pas aussi explicite et aucune méta-donnée sur la précision des nombres n’est donnée. Cette dernière caractéristique peut être problématique lors du traitement dans des langages tels que le JS (exemple).
  • Le schéma est embarqué dans la donnée et les structures imbriquées ainsi que des listes sont des types existants dans le JSON. Il est donc souvent utilisé pour les bases de données NoSQL de type document.

Bien que le JSON soit moins verbeux que le XML, sa taille est assez imposante comparée à celles des fichiers binaires. Pour palier ce problème, certains formats binaires (MessagePack, BSON, etc.) basés sur le JSON ont émergé du fabuleux monde de l’informatique. Par soucis de concision, je ne réécrirai pas mon exemple en JSON mais préfère vous rediriger vers le site officiel du JSON pour plus de précision sur la syntaxe.

Bon à savoir : Dans le domaine de la Data et notamment Hadoop le JSON est souvent représenté inline par défaut. C’est-à-dire que chaque donnée est écrite sur une ligne.

Parquet

Ça y est, on rentre dans la cour des grands … Apache Parquet est un format orienté colonne et très en vogue aujourd’hui. Son succès est en partie dû au fait qu’il a été créé pour faire partie de l’écosystème Hadoop. Il y est donc très bien intégré et vit notamment une belle histoire avec Apache Spark.

Ce format embarque avec lui le schéma des données et les types associés. Il existe deux types de données en Parquet, les primitifs et les logicals qui étendent ces derniers. L’association de ces deux types permet l’utilisation de ce format sans travail de conversion. La présence d’un schéma est aussi un avantage car il permet de créer des objets déjà typés lors de l’utilisation des fichiers. Ainsi, nous n’avons pas non plus besoin de lire toutes les données d’une colonne afin d’inférer un type.

Cependant, ce format est binaire et donc pas lisible par l’Homme. De plus, la structure d’un fichier Parquet n’est pas si simple mais peut être schématiquement représentée de la façon suivante :

De l'importance du format de la donnée : Pratique (Partie 2/2)

Représentation du format Parquet
  • Header : Il contient un Magic Number, 4 octets identifiant le fichier comme étant un fichier de type Parquet ‘PAR1’.
  • Row Group : C’est la représentation logique des données en lignes. Il est composé de column chunks, un par colonne du dataset.
    • Column Chunk : Il contient une partie des données pour une colonne particulière. Les lecteurs (readers) peuvent lire des statistiques de chaque colonne (min, max, num_nulls) et ainsi dans certains cas ne pas avoir besoin de lire certains Column Chunks.
      • Page : Les pages contiennent les données compressées (~1MB) et partagent des headers communs. Les mêmes statistiques y sont stockées, mais calculées avec une granularité plus fine (Page).
  • Footer : Il contient les metadata du fichier. Les lecteurs des Parquets lisent tout d’abord, ce fichier de metadata pour trouver les column chunks qui les intéressent. Il contient aussi la taille du fichier de metadata ainsi que le même Magic Number que le header.

Schématiquement, notre jeu de données pourrait être représenté de la sorte :

De l'importance du format de la donnée : Pratique (Partie 2/2)

Niveau compression, Snappy est l’algorithme par défaut avec du Parquet mais on peut aussi trouver du LZO, gzip et bien d’autres.

La force de ce format est son orientation colonne couplée aux statistiques associées. Il est donc très efficace lorsque des projections et predicate pushdowns sont utilisés. Son intégration avec de multiples outils (Spark, Hive, Flink, Athena, BigQuery, etc.) fait qu’il est aujourd’hui le format le plus utilisé quand on parle de traitements Big Data.

Bon à savoir : Sa structure singulière et son écriture binaire couplée à la compression rendent sa lecture directe très difficile. Pour explorer des données Parquet on peut utiliser un spark-shell qui nous permet aussi de les manipuler. Autrement, il existe l’utilitaire Parquet-tools un peu moins connu mais très pratique qui permet de visualiser les données ainsi que toutes les metadonnées associées au fichier. En bref, spark-shell + Parquet-tools = ❤️

ORC

Le grand rival du Parquet … Apache ORC (Optimized Row Columnar) est un format orienté colonne très utilisé et qui est intégré à l’écosystème Hadoop. Globalement, ORC dessert les mêmes cas d’utilisation que Parquet. Il est souvent utilisé avec Hive.

Les types de données supportés sont multiples (primitifs et composés), la liste de ceux-ci se trouve ici. Tout comme le Parquet, le schéma des données est embarqué dans les fichiers ORC.

Un fichier ORC a une structure presque similaire au Parquet et peut être représenté de la manière suivante :

De l'importance du format de la donnée : Pratique (Partie 2/2)

Représentation du format ORC
  • Header : Le header permet d’identifier le format du fichier, ici ce sera ‘ORC’
  • Stripe : C’est ici que la donnée y est contenue, ce sont des blocs de 250Mb par défaut.
    • Index data : Contient les index des lignes (row-level) de chaque colonne du stripe. Ce sont des métadatas.
      • Column : Contient les index row-level sur la colonne en question.
    • Row data : Contient les données de chaque colonne.
      • Column : Contient les données de la colonne en question.
    • Strip footer : Contient les informations sur l’encodage de la colonne.
  • Footer : Contient les files et strip level index.
  • Postscript : Contient les informations nécessaires à la lecture du fichier (meta-data) et n’est jamais compressé.

Les trois index mentionnés ci-dessus font référence à des statistiques calculés sur les données de chaque colonne mais à différents niveaux :

  • File-level : Sur tout le fichier
  • Strip-level : Sur chaque stripe
  • Row-level : Sur 10 000 lignes (row-group) dans une stripe et, la position de départ de chaque row-group.

Ces statistiques, plus complètes que celles offertes par le Parquet, contiennent min, max, sum, count, hasnull, bytesOnDisk et des bloom filters. ORC supporte aussi les opérations ACID (hello Hive).

Par défaut le format ORC est souvent compressé avec le ZLIB, mais d’autres algorithmes tels que le Snappy sont aussi envisageables.

Bon à savoir : L’aspect binaire du format ORC et sa structure alambiquée ne permettent pas une lecture humaine des données. Tout comme Parquet, des solutions existent pour explorer directement des données ORC, spark-shell ou orc-tools.

Parquet Vs ORC

Il y a les pro-“LE wifi” et les pro-“LA wifi” (on reste bienveillant, on ne juge pas), tout comme il y a les pro-Parquet et les pro-ORC. Vous avez pu le voir les formats ORC et Parquet sont assez similaires.

Mais dis-moi Jamy, les deux formats se ressemblent énormément, alors quelles sont les réelles différences ?

ORC a été développé par Facebook puis open-sourcé au sein de la fondation Apache (2013) et en partie maintenu par Hortonworks. Il en est de même pour Parquet, développé par Twitter puis de même donné à la fondation Apache (2013) et maintenu par Cloudera. Cette dernière distribution est la plus populaire et pousse naturellement l’utilisation de Parquet ce qui expliquerait le fait qu’ORC soit moins populaire. Les temps changent, et l’annonce de la fusion en 2018 de ces deux mastodontes va peut-être faire changer les choses.

On se pose donc forcément la question : Dois-je choisir le format Parquet ou ORC ? La question n’est pas triviale. Si vos cas d’utilisation finaux ne passent que par Hive, le format ORC est certainement à privilégier car son intégration y est souvent mise en avant. Sinon, il faut malheureusement prendre le temps de lire les différents benchmarks existants et de tester de manière empirique les performances (stockage et temps d’exécution) de vos transformations avec ces formats, couplés à différentes compressions.

Lors de la rédaction de cet article, le support de ces formats dans l’écosystème Big Data est le suivant :

De l'importance du format de la donnée : Pratique (Partie 2/2)

Bon à savoir : Spark est sûrement plus mature sur la manipulation de fichiers Parquet, supportés depuis Spark 1.0, que ORC, introduits eux en Spark 1.4.

RCFile

Pour la petite histoire … RCFile (Row Columnar File) peut être considéré comme le premier fichier format colonne de l’écosystème Big Data, un peu comme le MapReduce du Spark. Le premier papier introduisant RCFile a été publié en 2011. Tout comme ORC et Parquet les concepts de projection pushdown, compression, lazy evaluation y étaient possibles et il était aussi fait pour fonctionner avec MapReduce.

Toutefois, aucune metadata sur les données n’était présente. Et ainsi le predicate pushdown impossible. De plus les rowgroups étaient seulement de 4MB, les lectures séquentielles n’étaient donc pas optimales.

C’est pour ces raisons qu’ont été introduits ORC et Parquet.

Avro

Le troisième mastodonte de la data. Apache Avro, créé en 2009, est un format de sérialisation de données. Contrairement aux formats de données colonnes, son objectif est le transfert des données dans l’écosystème Hadoop (donc environnement distribué).

Un fichier Avro peut être schématiquement représenté de la sorte :

De l'importance du format de la donnée : Pratique (Partie 2/2)

Représentation du format Avro
  • Header : Les trois premiers bytes du header informent que le fichier est du type Avro et sont suivis de la version Avro du fichier, ici 1.

    • Sync Marker : Permet de vérifier que le fichier de données n’est pas corrompu, comme un checksum par exemple.
    • File Metadata : contient (roulement de tambour …) les metadonnées du fichier au format JSON. Elles sont composées du schéma de la donnée, du codec et de la compression. Pour notre exemple, le schéma serait le suivant :
{    
     "type": "record",
     "namespace": "fr.lesnuls",
     "name": "Informations",
     "fields": [
       { "name": "Nom", "type": "string" },
       { "name": "Prenom", "type": "string" },
       { "name": "Age", "type": "int" }
       { "name": "Sexe", "type": "string" }
     ]
}
  • Data Blocks : contiennent les données en soit, le plus souvent en binary mais le format peut aussi être du JSON (pour débugger par exemple).

La donnée Avro embarquant le schéma, l’utilisateur n’a pas besoin d’écrire les classes de sérialisation/désérialisation de la donnée lui-même. Ce qui est un avantage non-négligeable lorsque l’on veut un système robuste et flexible, schématiquement parlant. La backward compatibility et forward compatibility ne sont donc pas à implémenter par l’utilisateur.

Apache Avro implémente aussi le Remote Procedure Call (RPC) qui permet au producteur et consommateur de la donnée d’avoir exactement le même schéma. Ce qui facilite donc grandement la résolution de schéma niveau consommateur.

Souvent Apache Avro est la sérialisation recommandée lorsque l’on utilise Apache Kafka, qui inclut un schema registry (version confluent).

Récapitulatif

Voici un tableau récapitulatif des formats présentés dans cet article :

De l'importance du format de la donnée : Pratique (Partie 2/2)

Conclusion

Nous avons vu que les formats binaires offrent des capacités de compression et d’accès aux données en colonne que ne permettent pas les formats CSV ou JSON.

Ces 2 caractéristiques sont déterminantes pour accélérer les traitements de données car elles réduisent énormément le volume de données qui va être effectivement traité.

C’est donc devenu une bonne pratique que de passer sur un format évolué dès que la donnée est acquise. Cela réduit le volume de stockage et le temps de traitement, donc mécaniquement l’énergie consommée et aussi les coûts.

How to: Mob Programming

$
0
0
How to: Mob Programming

Lors de DDD Europe 2020 nous (Anthony et Colin) avons assisté au talk d'Elisabeth (Lisi) Hocke : A Story of Mob Programming, Testing and Everything.  Cette heure nous a permis d'y voir plus clair sur cette pratique formalisée par Woody Zuill et son équipe.

Ce rappel nous a donné envie de revenir sur cette manière de travailler souvent incomprise et sous-estimée !

Mob Programming: Késako ?

Une traduction pourrait être "programmation collective" : l'idée est que toute l'équipe va travailler en même temps à la résolution d'un même problème ! Pour ce faire on utilisera donc l'intelligence collective mais un seul clavier et une seule souris.

On va configurer la salle de cette manière :

How to: Mob Programming

Comme en pair-programming le Driver est responsable du clavier : il code dans la direction donnée par le Navigator. Seul le Navigator donne des directions au Driver mais le Mob donne son avis au Navigator qui doit alors les compiler pour en faire des directions claires.

Le Navigator ne doit pas dicter le code qui doit être écrit et le Driver ne doit pas prendre de décision seul, enfin, normalement...

Dans une session de Mob programming tout le monde change de rôle à intervalle régulier (on peut utiliser mobster pour gérer ce changement de manière fluide). Toute personne participant à la session sera donc, à un moment donné, Driver, Navigator et Mob.

En fonction du but de la session : apprentissage ou processus de travail, il faudra faire quelques adaptations à la session (mais ça nous allons le détailler plus tard dans cet article).

Les premières réactions

Quand on présente le Mob Programming pour la première fois la réaction la plus fréquente est certainement : "On n’a pas le temps !". En fait il est commun de penser que cette pratique fait perdre du temps à l'équipe.

C'est vrai, comment, en ayant moins de personnes qui codent, on pourrait faire la même quantité de code ? En fait on ne pourra pas mais, comme le dirait le père de Woody : "I'd rather work slowly on the right thing than quickly on the wrong thing" ("Je préfère travailler doucement sur ce qui doit être fait que rapidement sur des choses inutiles").

C'est bien là le secret de l'efficacité de cette pratique : on codera certainement moins, mais on le fera pour des choses plus utiles. Woody dit : "What do you mean by being productive? Focus on effectiveness instead!" ("Que veut dire être productif ? Concentrez-vous plutôt sur l'efficacité !").

Lors d'échanges avec des collègues pratiquant au quotidien l'un d'eux nous disait "C'est comme si on attaquait tous les problèmes au bazooka ! Quand on rencontre un problème la personne qui a l'information est forcément là donc on a tout de suite la réponse.".

Comme pour toute pratique, il est essentiel de la mettre en place pour se faire réellement un avis ! Les premières sessions peuvent être source de stress, vous aurez donc des premières réactions différentes, mais cette fois ce sera de la part des participants.

Un des rôle les plus impressionnant est sans doute celui du Driver. Faire du Live Coding est tout sauf aisé ! Pour faciliter le démarrage on pourrait être tenté de faire commencer les développeurs les plus expérimentés : c'est surement une erreur ! Les personnes passant après ne seront que plus gênées de "ne pas aller aussi vite" ou de "ne pas connaître aussi bien le langage". Faire commencer les personnes les moins expérimentées peut alors être une bonne idée car elles ressentiront moins le besoin de justifier les inévitables erreurs. De plus, en commençant, leur stress aura moins le temps de se construire pendant le passage des "anciens" de l'équipe.

Le rôle du Navigator peut aussi être source de stress : arriver à prendre en compte les avis de tout le monde tout en étant capable de prendre des décisions pour donner une direction claire au développement n'est pas toujours chose aisée. Pour les premières sessions, il est essentiel que le facilitateur protège le Navigator, par exemple en rappelant que chaque personne doit parler à tour de rôle.

Le rôle de Mob peut aussi être stressant, certaines personnes vont être "complexées" de ne pas être aussi à l'aise que d'autres avec les notions métier ou technique. Certains peuvent aussi se "fabriquer" du stress en comptant le temps restant avant leur passage et en paniquant par anticipation. Dans ce genre de cas, c'est au facilitateur de détecter ces comportements et de  rassurer les personnes (une simple blague du facilitateur expliquant que lui aussi est perdus peut très bien fonctionner). Il est aussi très important que le Mob participe et c'est au facilitateur de s'assurer de cela.

Dans tous les cas il est essentiel de travailler en bonne intelligence. Le but de la session doit clairement être affiché dès le départ et tous les participants doivent travailler à l'atteinte de ce but.

Les sessions ne fonctionnent bien que si tout le monde traite les autres avec considération et respect ! Il est aussi essentiel que chacun reste dans son rôle.

Le Mob Programming comme méthode d'apprentissage

Cette pratique peut être utilisée comme une technique d'enseignement et d'apprentissage. Si c'est le seul but des sessions, on n’utilisera pas de réels problèmes, mais des kata de code qui seront bien plus adaptés et réduiront le stress des participants.

Dans cette optique, il est fréquent que les formateurs ne participent pas au Mob au même titre que les personnes formées, mais qu'ils restent Facilitators.

Il est aussi possible que trop de personnes se présentent à la session, on pourra alors avoir cette configuration :

How to: Mob Programming

Dans cette configuration on peut laisser une place de Mob libre en permanence pour permettre aux personnes de l'Audience de rejoindre si elles le souhaitent. Si une personne de l'Audience prend une place de Mob, alors un Mob doit rejoindre l'audience.

Ce format étant particulièrement éprouvant, il est fortement conseillé de faire des sessions relativement courtes (2h). Il faut aussi bien préciser qu'il est tout à fait possible de partir pour mieux revenir si on le souhaite lorsqu'on est Mob ou Audience.

Dans une optique de formation, le formateur a un superpouvoir : il peut demander à être le prochain Navigator et ainsi remettre le groupe dans une direction plus appropriée.

Même si le dispositif semble relativement simple, il est redoutablement efficace en termes d'enseignement ! Il permet à chaque participant :

  • D'apprendre des manières de faire des autres ;
  • De coder sous contraintes (changement de matériel, live coding, …) ce qui est très formateur ;
  • D'apprendre à faire des revues et des retours ;
  • D'apprendre les techniques et outils qui sont en cours d'enseignement sous contrôle des formateurs.

Comme à la fin de chaque session de formation, pensez à faire une rapide rétrospective. Cela peut être quelque chose d'aussi simple qu'un Return On Time Invested, mais il est important de prendre les avis (et surtout d'essayer de comprendre les plus mauvais pour faire mieux la prochaine fois).

Le Mob Programming comme processus de travail

Lorsqu'on utilise le Mob Programming comme processus de travail dans une équipe, en plus des avantages que l'on y trouve en l'utilisant comme méthode d'apprentissage, on va :

  • S'assurer de travailler sur les tâches réellement importantes ;
  • Eliminer les changements de contextes ;
  • Limiter le Bus Factor en partageant instantanément les informations ;
  • Accueillir simplement de nouvelles personnes ;
  • "Attaquer les problèmes au bazooka !".

Enfin, ça, c'est quand tout se passe bien et pour ça, il semblerait que quelques astuces soient nécessaires ! Déjà sur le plan matériel : branchez un clavier "normal" (un AZERTY en France) et une souris pour que les inputs soient classiques.

Assurez vous aussi de trouver un écran permettant vraiment la lecture du code : une télé de 55" coûte moins qu'une journée de prestation, ce serait dommage de s'en priver. D'ailleurs, il est fortement recommandé de faire ces sessions dans le bureau de l'équipe, car il peut être compliqué de réserver des salles de réunions.

Pour commencer, il est préférable que quelqu'un assure la facilitation. Cette personne aura plusieurs rôles :

  • Expliquer le fonctionnement du Mob Programming en début de session ;
  • S'assurer que chacun respecte son rôle ;
  • S'assurer que les échanges se fassent en bonne intelligence ;
  • Animer une courte rétrospective finale.

Même s’il est tout à fait possible de travailler tout le temps en Mob, il est sans doute préférable de commencer par des sessions de 2h avec 10 mn d'introduction et 10 mn de rétrospective finale. Pour les premières sessions, il est recommandé de choisir des scopes très légers quitte à avoir de bonnes surprises !

Quand on veut utiliser le Mob Programming comme méthode de travail, il est courant de vouloir avoir toute l'équipe présente. En fait c'est comme ça que doivent se faire les sessions dans l'idéal (avec les développeurs, PO, etc). Malheureusement, il est souvent très compliqué d'avoir tout le monde pendant plusieurs heures !

Il est tout à fait possible d'être moins strict. En laissant les gens rejoindre et quitter la session de Mob comme ils veulent / peuvent, vous allez non seulement faciliter l'organisation, mais aussi rendre le déroulement moins éprouvant !

La dernière chose à laquelle il faut prêter une attention toute particulière est de laisser tout le monde s'exprimer. Au début, il peut être bon de laisser les personnes les plus juniors de l'équipe parler en premier : cela facilitera leurs interventions et permettra à tout le monde d'entendre leurs idées. Il est toujours plus compliqué pour un junior de donner son avis lorsqu'une personne senior vient de donner un avis tout à fait contraire au sien !

Quand ne faut-il pas faire du Mob Programming ?

Il est possible de faire du Mob pour beaucoup de choses (et pas forcément pour du développement). On peut par exemple penser à l'écriture de mails compliqués ou à la rédaction de documentation. Il existe cependant des cas ou le Mob n'est pas recommandé.

Si des tensions existent dans l'équipe, il est fort probable que les sessions de Mob ne fassent que les accentuer. Dans ce genre de cas, il est probablement préférable de régler les tensions avant de se lancer dans une pratique qui peut être stressante.

Faire du Mob peut aussi être une mauvaise idée si trop peu de personnes sont disponibles. Si seulement 2 personnes de l'équipe sont disponibles, c'est du pair-programming.

Il est aussi peu pertinent de faire une session de Mob pour la réalisation de tâches trop simples et maîtrisées par toute l'équipe. Attention cependant : des tâches simples pour certaines personnes peuvent être de vraies découvertes pour d'autres !

Un autre cas qui peut venir à l'esprit : lorsque la fonctionnalité ne doit pas être dévoilée et que seules quelques personnes ont le droit de travailler dessus. Même si ce genre de cas est plutôt rare, il faut penser à les prendre en compte et ne pas afficher la fonctionnalité à des personnes n'ayant pas les autorisations nécessaires.

Quoi qu'il en soit le Mob Programming est adapté dans la majorité des cas, pas d'excuses pour ne pas se lancer donc !

Et personnellement, qu'est-ce qu'on y gagne ?

Aux gains déjà conséquents pour l'équipe s'ajoutent les gains personnels, pour Lisi c'est :

  • L'écoute ("Listening"),
  • L'Empathie ("Empathy"),
  • Aider les autres à grandir ("Helping others grow"),
  • L'observation ("Observation"),
  • La collaboration synchrone ("Synchronous Collaboration"),
  • La communication ("Communication"),
  • Laisser de la place ("Making space").

Elle nous a expliqué avoir grandi au travers des sessions de Mob qu'elle a vécues avec son équipe. Avec ce talk inspirant elle nous a donné envie de mettre en place ces sessions de manière plus régulières et, peut être, en sortirons nous, nous aussi, grandis !

Matillion Data Loader : gadget ou réelle utilité ?

$
0
0
Matillion Data Loader : gadget ou réelle utilité ?

Matillion est un ELT qui, depuis 2015, s’est installé parmi les plus en vogue du moment. Forte de ses 5 années d’expérience et après avoir levé 35 millions de dollars, l’entreprise britannique (située à Manchester) a recueilli les demandes de ses clients et sondé les besoins changeants des acteurs du marché pour finalement annoncer la sortie fin 2019 de son nouvel outil : Matillion Data Loader. En effet, selon leurs recensements, de plus en plus de parties prenantes aux différents projets IT ne sont pas issus de formations IT, et le besoin de solutions no-code qui permettraient à ces acteurs de pouvoir apporter leur expertise malgré leur manque de connaissances techniques est grandissant. Ainsi, d’après un sondage de IDG Research et Matillion, 87% des entreprises ayant des équipes silotées (ou partiellement silotées) prévoient de centraliser le management de la BI et de l’analytics, ce qui ferait graviter autour du même sujet des personnes issues d’horizons bien différents (IT mais aussi marketing, finance, etc.). L’idée est que tout le monde puisse avoir un accès rapide à un modèle de données démocratisé.

PRÉSENTATION

Les acteurs du marché ont exprimé le besoin d’avoir un outil centré sur l’intégration facile, rapide et économique de données dans le cloud. Ce besoin s’exprime également dans un contexte où l’objectif est de casser les silos de données existants pour tout regrouper dans un unique élément : le data warehouse. Matillion Data Loader (MDL) est donc un outil de pipeline de données (Extract, Load) en SaaS, permettant essentiellement de copier des données depuis des sources dites classiques (bases de données relationnelles notamment) vers des data warehouses dans le cloud. Voici la liste des différentes sources et cibles disponibles :

Matillion Data Loader : gadget ou réelle utilité ?
Fig 1 : A gauche les sources, à droite les cibles

On trouve à l’heure actuelle dans la documentation 13 composants différents permettant de connecter sa/ses source(s) à un des 3 data warehouses présentés. On retrouve ainsi dans les cibles les 3 plus gros acteurs du marché du virtual data warehouse en ce moment : Redshift d’AWS, BigQuery de GCP et Snowflake (qu’il soit basé sur AWS ou Azure). De plus, MDL est en cours d’intégration de 4 nouvelles sources de données :

  • Facebook AdAccounts ;
  • Facebook AdInsights ;
  • Facebook Content Insights ;
  • HubSpot.

On imagine que d’autres encore sont à venir, mais Matillion n’a pas encore dévoilé de noms à ce propos. Par ailleurs, un plus grand nombre de sources sont disponibles dans la version ELT de Matillion.

Côté facturation, c’est très simple : l’outil est totalement gratuit. De base, l’entreprise comptait offrir le service gratuitement dans la limite de 250 millions de lignes transférées par mois, mais depuis peu cette limite a disparu et l'entièreté du service est gratuit. Il n’y a pas de possibilité d’abonnement Premium (ou équivalent) qui permettrait d’avoir accès à un support personnalisé, à plus de fonctionnalités ou à de meilleures performances. Pas de stratégie de format propriétaire utilisable seulement par l’ELT Matillion qui forcerait les utilisateurs de Data Loader à souscrire à l’ELT. Enfin, l’outil scale horizontalement automatiquement et il n’y a pas de limite sur le nombre maximal d’instances.

Une communauté (récente) et de la documentation sont accessibles ici. Le support semble assez actif et répond aux questions des utilisateurs dans la journée. On y retrouve également une FAQ et des bugs connus et en cours de traitement par Matillion.

A noter que MDL est optimisé pour (dans l’ordre) Google Chrome et Mozilla Firefox, mais fonctionne également avec HTML5 Canvas et WebSockets.

PLUS TECHNIQUEMENT

L’interface MDL est basée sur AWS Fargate dans un VPC AWS administré par Matillion. Les métadonnées des utilisateurs sont stockées dans un AWS Aurora sous-jacent. Ces métadonnées correspondent aux pipelines, aux planifications, aux identifiants et à des métriques concernant l’utilisation du produit. Pour l’instant il n’y a des serveurs disponibles qu’en Europe et aux USA. D’après Matillion, ils n’ont pas sur leur roadmap la volonté de s’étendre à d’autres continents comme l’Asie.

Le fonctionnement est le suivant :
MDL se connecte à la source en utilisant les credentials fournis. Ces credentials sont envoyés au service lorsqu'un pipeline est déclenché. Le service envoie les données à un runner isolé dans le VPC de Matillion. Le runner place ensuite les données dans une zone de staging (par exemple Amazon S3 si le data warehouse cible est Redshift), avant de les charger dans la table cible dans le datawarehouse cible.

Le fonctionnement peut être complété par le schéma suivant :

Matillion Data Loader : gadget ou réelle utilité ?
Fig 2 : schéma de fonctionnement de MDL (source)

De plus, le runner existe dans un container temporaire isolé au sein du VPC de Matillion qui ne reçoit que les metadata et les références nécessaires pour accéder à une source unique et à un data warehouse cible. Un seul container est utilisé pour chaque exécution du pipeline et est détruit une fois l'opération terminée. Les utilisateurs n’ont pas directement accès au runner. La communication entre le runner est les datawarehouses se fait via JDBC en SSL pour Snowflake et Redshift, et en TLS (HTTPS) pour BigQuery.

MDL ajoute des colonnes “flags” qui permettent de suivre le Change Data Capture de chaque ligne. Ces colonnes sont par défaut un _id de run _et une date de dernier update.

Concernant la sécurité, lorsque les données sont en transit entre la source et MDL, la responsabilité de la protection de celles-ci revient à la source elle-même. Lorsque les données sont dans la zone de staging, la protection des données est à la charge du user qui a le contrôle sur l’environnement du data warehouse cible (qui définit la zone de staging).

Une fois les données chargées depuis la zone de staging vers les tables cibles, les données sont supprimées de cette zone. C’est la même chose une fois les données arrivées dans le data warehouse : c’est le user qui est en charge de définir ses règles de protection de données. De plus, au sein de l’outil, on trouve une gestion des mots de passe avec un système de clef:valeur où la valeur est le mot de passe (encryption KMS, non visible en clair) et la clef est le nom associé au mot de passe. Cet ensemble clef:valeur est accessible à l’outil lorsqu’il est nécessaire de rentrer des identifiants, pour paramétrer un composant par exemple.

MISE EN PLACE D’UN PIPELINE

Mise en place de l’environnement

La création d’un compte se fait facilement. On peut s’enregistrer avec son compte Google, Microsoft ou alors avec une simple adresse mail. Il est ensuite nécessaire d’accorder certains droits aux users de services dédiés à Matillion Data Loader pour chaque type de data warehouse. Ces droits à octroyer sont visibles ici. De plus, j’ai dû whitelister les adresses IP de MDL pour que l’outil puisse se connecter à mon instance PostgreSQL (pour la région EU) :

52.214.186.180
52.49.22.171
52.31.2.16

Création d’un pipeline

L’entité de base de MDL est le pipeline, qui est décrit par une source, une cible et sa fréquence de run. Ces éléments sont à paramétrer lorsqu’on crée son pipeline :

Matillion Data Loader : gadget ou réelle utilité ?
Fig 3 : Etapes de création d’un pipeline
  1. D’abord, le choix du type de source (PostgreSQL ici) ;
  2. Ensuite, le choix du type de cible (Snowflake ici) et du nom du pipeline ;
  3. Enfin, le paramétrage de la connexion :
    • Credentials de connexion
    • Options de connexion
    • Sélection des tables à charger
    • Sélection des colonnes à charger
    • Définition de l’environnement de Staging (où sont temporairement stockées les données)
    • Définition de l’environnement de Landing (où les tables finales sont stockées)
    • Réglage de la fréquence de run et test de la connexion.

Une fois le pipeline créé et les premières 24h passées, voici un aperçu de ce qu’on peut voir :

Matillion Data Loader : gadget ou réelle utilité ?
Fig 4 : Monitoring d’un pipeline

On peut voir ici par exemple que 9001 lignes ont été chargées le 19/02 et 8000 le 20/02. Un total glissant sur plusieurs périodes est disponible en bas. Par ailleurs, on peut activer et désactiver un pipeline avec le bouton switch en haut à gauche.

Management du pipeline

En plus d’avoir accès aux informations du pipeline, il est également possible de redéfinir la fréquence de run et le nombre d’erreurs à partir duquel un mail de notification est envoyé à l’utilisateur :

Matillion Data Loader : gadget ou réelle utilité ?
Fig 5 : Paramétrage a posteriori d’un pipeline

Voilà, une fois le pipeline paramétré comme souhaité, il suffit de le laisser activé pour que la migration des données en source soit effectuée vers la/les cible(s).

QUELS SONT LES AVANTAGES DE MDL ?

Le premier avantage et non des moindres est que l’outil est disponible en SaaS, ce qui élimine de nombreuses contraintes d’installation et de maintenance. Ensuite, le pricing est plus qu’intéressant : c’est totalement gratuit. Vient ensuite un argument à double-tranchant : il faut passer par un wizard (une interface graphique qui guide l’utilisateur pas à pas) pour configurer ses connexions. Cela s’inscrit pleinement dans la volonté de Matillion d’élargir son spectre d’utilisateurs. En effet, l’UI est relativement intuitive et claire. Cependant, cela frustrera forcément les plus puristes d’entre nous puisqu’il n’est pas possible de coder en dur ses connexions : le passage par le wizard est obligatoire. Dans la version ETL de Matillion, c’est la même chose, même s’il est possible d’accéder au code SQL équivalent au composant que l’on est en train de configurer. De plus, les sources disponibles sont parmi les plus populaires du marché. On pourrait ajouter à ça des features de monitoring des jobs et un système d’alerte et notification, mais ces éléments restent assez basiques.

CONCLUSION

MDL est un EL (Extract, Load) performant mais basique, qui suffira lorsque le besoin est simplement de migrer des données de sources différentes vers un endroit unique. Cependant, dès que des transformations sont à envisager, il est nécessaire de passer à un ETL/ELT plus complet comme Matillion ETL. D’ailleurs, Matillion offre un service qui permet de passer de Matillion Data Loader à Matillion ETL en transférant le travail effectué de l’un à l’autre.

Par ailleurs, il existe également des solutions concurrentes, dont voici quelques exemples :

Toutes ces solutions proposent plus de sources différentes, souvent plus de cibles, mais toutes sont payantes. Je ne me suis pas penché sur les performances de chacune. En conclusion, MDL sera une bonne option si le use case est simple (pour un POC par exemple) et si la diversité de sources de l’entreprise est faible. Sa facilité d’utilisation, sa gratuité et son utilisation en SaaS restent des avantages indéniables qui font de MDL une solution idéale pour le chargement de données. Quand un projet s'élargit et que plus de connecteurs sont nécessaires, on pourra s'orienter vers Matillion ELT ou une autre solution de transformation. Matillion Data Loader reste un outil très jeune, qui sait s’il saura s’imposer comme leader dans l’intégration de données ?


Retours DDD Europe 2020 (Partie 1)

$
0
0
Retours DDD Europe 2020 (Partie 1)

Du 05 au 07 Février 2020 nous (Anthony et Colin avons eu la chance de passer 3 jours à DDD Europe. Autant spoiler tout de suite : c'était vraiment 3 très belles journées, on vous raconte !

Matinée Event Sourcing :

Il y a plusieurs formules pour participer à DDD Europe. Nous avions pris un combo avec une première journée dédiée à l'Event Sourcing. Nous commençons donc avec trois talks sur le sujet :

  • [Event Sourcing] Keynote par Udi Dahan ;
  • Mistakes Made Adopting Event Sourcing (and how we recovered) par Nat Pryce ;
  • Event Sourcing Done Right - Experiences from the Trenches par Dennis Doomen.

Dans notre perception, ces trois premiers talks étaient relativement similaires : d'abord une introduction à l'Event Sourcing puis une mise en garde de n'utiliser cette approche que si on en a réellement besoin.

Les 3 speakers ont bien insisté sur le fait que l'Event Sourcing augmente drastiquement les risques d'erreurs dans le développement. On ne parle pas ici du risque de faire des traitements faux mais bien des risques d'erreurs très coûteuses dans l'architecture logicielle. Ils ont aussi largement insisté sur la complexité accidentelle qu'ajoute cette approche.

Quelques temps avant cette conférence, Anthony avait eu la chance de participer à 3 jours d'ateliers avec Adam Dymitruk et Greg Young sur CQRS et l'Event Sourcing. À cette occasion nous avions pu échanger avec ces deux porteurs de la discipline. Pour leur part ils font systématiquement de l'Event Sourcing (quelle que soit la mission).

Retours DDD Europe 2020 (Partie 1)
De gauche à droite, Anthony, Greg et Adam

Avant d'échanger avec eux sur ce sujet nous étions persuadés que l'Event Sourcing n'était adapté que dans certains cas bien précis :

  • très importants volumes de données et de traitements,
  • CQRS avec beaucoup de projections et d'importants risques en cas de perte de la cohérence à terme,
  • fort besoin de traçabilité,
  • présence d'une équipe expérimentée pouvant comprendre ce type d'architectures.

De fait, nous étions étonnés du discours tenu et, pouvoir entendre des avis similaires au nôtre dans les talks de DDD Europe nous a conforté dans nos convictions. En fait, il est tout à fait normal pour ces deux fers de lance de l'approche de ne faire que ça. Pour les autres développeurs, par contre, il semble qu'il soit important de ne pas considérer tous les problèmes comme des clous, mêmes lorsqu'on a un superbe marteau !

De ces trois premiers talks, si nous ne devions en retenir qu'un, ce serait celui de Dennis Doomen qui semblait plus expérimenté sur cette approche et donnait des retours vraiment intéressants.

Functional Event Sourcing par Jérémie Chassaing

On commence l'après-midi avec un talk présenté sous forme de live coding, Jérémie Chassaing nous montre comment cloisonner un domaine métier (le fonctionnement d’une ampoule) de son infrastructure basée sur de l’Event Sourcing.

Aucun slide, un IDE, une en-tête en F# pour mettre quelques informations personnelles et Jérémie lance son live coding.

Jérémie, commence par représenter le Domain d’une ampoule avec les états "Allumé", "Éteint" et les actions "Allumer" et "Éteindre" à travers le système de typage du langage.

On voit tout de suite la pertinence du typage fort qui permet de rendre explicite chacun des états et chacune des actions.

Pour ajouter un peu de complexité au domaine métier de l’ampoule et justifier l’intérêt de l’Event Sourcing, il ajoute une règle métier qui casse l’ampoule au quatrième allumage, ce qui introduit l’état "Cassé".

Ainsi il devient facile de déduire les évènements associés "Ampoule allumée", "Ampoule éteinte" et "Ampoule cassée".

Il insiste sur le fait que sa représentation du domaine est immuable, c’est-à-dire que les valeurs correspondant à ses types ne peuvent pas changer (un peu comme si tous les fields de vos objets n’étaient accessibles qu’en lecture) et ses fonctions donneront toujours le même résultat si les mêmes paramètres sont passés en entrée (on appelle ça des fonctions pures).

Ensuite, Jérémie décide d’implémenter un event store en mémoire. Ayant séparé le métier de son infrastructure (le domaine de l’ampoule, du système de persistance des évènements en mémoire), il peut s’attaquer à une seconde implémentation en persistant dans un fichier. Suite à cette implémentation, Jérémie ajoute un dernier adaptateur pour la solution Event Store.

À travers tous ces exemples d’implémentation, Jérémie aura montré un domaine métier cloisonné de l’infrastructure. À aucun moment il n’aura eu besoin de retoucher ses règles métiers, seulement les adaptateurs vers son infrastructure et ainsi démontrer l’intérêt d’une architecture hexagonale.

Ce live coding est une très bonne introduction à l'architecture hexagonale et ses bénéfices puisqu’il permet, à travers une application concrète, de montrer les avantages de séparer les adaptateurs du Domain afin de ne pas retoucher le code métier. De plus l’immutabilité au sein du code métier est bien amenée et le typage fort utilisé rend le sujet explicite. Un très bon live coding qui regroupe plusieurs notions du DDD tout en restant très simple et sans volonté d’impressionner son public comme le rappelle Jérémie.

Dissecting Bounded Contexts par Nick Tune

On commence cette première journée de Main Conference par une keynote très bien menée par Nick Tune. Il commence par rappeler l'importance du langage avec des exemples bien choisis et plein d'humour :

  • "JavaScript is not related to Java",
  • "There is no Straw in Strawberries",
  • ou encore une image comme celle-là :
Retours DDD Europe 2020 (Partie 1)

C'est vrai que l'on peut légitimement se demander quels sont les points communs entre une "Fairy" et un "Ferry" alors qu'on entend clairement la même chose !

Il nous parle ensuite de l'importance des Bounded Contexts avec, là encore, un exemple plein d'humour concernant les tomates. En fait, dans le contexte de la science les tomates sont des fruits par contre, à cause d'une loi américaine, dans le contexte de la cuisine, les tomates sont des légumes.

Il revient ensuite sur les notions de Core Domain, Generic Domain et Supporting Subdomain pour proposer un différenciation qu'il détaille dans un article medium. Cette nouvelle vision apporte vraiment un plus et nous la verrons probablement intégrer les prochains ouvrages sur le DDD !

Il revient ensuite sur l'organisation des équipes (qui est intrinsèquement liée aux découpage des Bounded Contexts). Pour lui, nous n'avons pas encore trouvé d'organisation d'équipe répondant vraiment à toutes les contraintes de notre marché.

Pour expliquer cela il commence par présenter les interactions entre l'équipe et les clients de cette manière :

Retours DDD Europe 2020 (Partie 1)

Avec ce cycle en tête, il est essentiel que les différentes équipes travaillant à la réalisation d'une solution (et donc travaillant sur des Bounded Contexts ayant beaucoup d'interactions) puissent partager efficacement leurs compétences et décisions.

Dans une organisation avec des équipes figées il y aura forcément de la perte d'information (même avec des canaux de communication privilégiés). À l'inverse, on ne peut pas faire changer les équipes de contexts trop régulièrement au risque de perdre en vélocité.

Nick propose alors une organisation dans laquelle une personne change régulièrement d'équipe mais ou on garde ce qu'il appel un team lead (que nous avons compris comme étant un tech-lead). On obtient alors une organisation comme celle-ci :

Retours DDD Europe 2020 (Partie 1)

Cette seconde journée pour nous (mais la première pour beaucoup) commence donc très très fort avec un talk inspirant et fort bien mené, vivement la suite !

Blink Modelling par Alberto Brandolini

On enchaîne par un atelier d’EventStorming animé par Alberto Brandolini : créateur de la méthode. Le but de l'atelier est de représenter le domaine métier d’une banque décrit par Brian, un visiteur de l’évènement.

Nous avons eu tellement de retours à faire sur cet atelier que nous les avons détaillés dans un article dédié.

Combatting the Near Enemies of Domain Driven Design - at Scale! par Andrew Harmel-Law et Gayathri Thiyagarajan

Cette journée valait déjà à elle seule le déplacement et le billet, nous étions comblés et n'attendions même plus rien de spécial à ce moment-là. Puis, arrive ce talk, Gayathri, Andrew et les "Near Enemies" : une notion du bouddhisme.

Un "Near Enemy" est souvent bien plus dangereux qu'un "Far Enemy" du fait qu'il est bien plus difficile à détecter ! Pour prendre un exemple éloigné de l'informatique : le déni est un "Far Enemy" de l'acceptation, par contre, la passivité et la résignation sont eux des "Near Enemies" (de l'acceptation).

L'idée ici était de présenter les "Near Enemies" du DDD qu'ils ont dû combattre dans un contexte où ils sont tous les deux intervenus mais aussi les solutions pour combattre chacun d'entre eux.

Voici quelques-uns des conseils que nous avons retenus de cette conférence :

  • Il faut s'assurer que tous les livrables de Design sont faits en prenant en compte les personnes auxquelles ils sont destinés ;
  • Il ne faut pas faire des abstractions trop tôt, en tout cas, pas avant d'être certain d'avoir bien compris les subtilités du Domain ;
  • Il ne faut pas partager le code entre plusieurs équipes à moins que cela ne soit absolument nécessaire. Pour être honnête nous avons déjà expérimenté bien trop souvent les problèmes posés par des Shared Kernels trop imposants, donc nous connaissons bien celui-là, mais on voulait quand même le remettre ici :) ;
  • Hands on modelers est VRAIMENT un point important du DDD. Si la personne qui fait des schémas sur les tableaux ne participe pas à la réalisation du code alors ses modèles seront probablement inutiles. Toute personne participant au projet qui peut coder DOIT coder, pour les personnes qui ne peuvent pas coder elle doivent pairer avec des personnes qui peuvent coder ;
  • Le modèle du Domain doit être fait par l'équipe, pas par une personne externe ;
  • Pensez aux relations entre les membres des équipes lorsque vous découpez vos Bounded Contexts.

Si vous voulez voir le talk (en attendant la publication des vidéos de DDD Europe) ils l'ont donné au Virtual Domain-Driven Design et il est donc disponible sur YouTube.

A Story of Mob Programming, Testing and Everything par Elisabeth Hocke

En parallèle des lightning talks, pour terminer ce deuxième jour, Elisabeth (Lisi) Hocke, une testeuse, revient sur son expérience du MOB programming.

Elle replace son contexte en abordant le Pair Programming très présent dans son équipe et s’en sert de levier pour aborder la notion de Mob Programming mise en place au sein de son équipe.

"All the brilliant people working on the same thing, at the same time, in the same space, and on the same computer."

Elle rappelle les rôles : le driver (celui qui code), le navigator (celui qui instruit) qui sont déjà présents dans le Pair Programming, auquel s’ajoute le rôle du Mob (l’assistance).

Notre but ici n'est pas de détailler le fonctionnement du Mob Programming. En fait ce talk nous a donné envie de faire un article dédié.

Elle soulève ainsi l’importance de l’apprentissage de tous les participants en insistant sur l’importance de la bienveillance, la considération et le respect :

Treat each other with kindness, consideration and respect

Elle décrit son tout premier mob avec une matinée bien remplie :

  • 9h45 Setup
  • 10h Introduction
  • 10h10 Mobbing
  • 11h15 Retrospective
  • 12h10 Closing
  • 12h15 Lunch :)

En se basant sur ses expériences tirées du monde réel, elle nous expose quelques points d’attention sur le mob :

  • La disponibilité de la salle ;
  • Les setups différents sur les machines ;
  • Le périmètre d’une story ;
  • Les personnes à distance ;
  • Le côté trop formel de l’atelier.

Et pour répondre à ces points, son équipe a mis en place les solutions suivantes :

  • Utiliser son bureau ;
  • Être plus flexible ;
  • Adapter les rotations en fonction des compétences et connaissances de chacun ;
  • Tout le monde contribue ;
  • Le Mob en tant que navigator ;
  • Autoriser des Mobs partiels (avec certains participants absents).

Avec toutes ces évolutions, elle revient sur les apports du Mob en terme d’évolution personnelle ; sur ce qu’enseigne la méthode ; sur la force des contributions de chacuns.

Elle insiste sur les apports du Mob en termes :

  • d’écoute,
  • de communication,
  • de collaboration synchronisée,
  • d’empathie,
  • d’observation,
  • de capacité à laisser tout le monde s'exprimer,
  • d’aide à faire grandir les autres,
  • des autres façons de faire que la sienne.

Ensuite, elle aborde une phase de doute vis-à-vis de la méthode puisqu’en Mob, il n’y a tout de même qu’une seule personne qui code à la fois, comment peut-on rester productif alors que sans, tout le monde code en parallèle. À ce moment, elle cite une phrase de Woody Zuill qui prend tout son sens :

"I’d rather work slowly on the right thing than quickly on the wrong thing"

Ainsi elle rappelle que tous les avantages du Pair Programming, tels que le partage des compétences et des connaissances … sont multipliés et améliorés avec le Mob. Elle parlera de bonne méthode pour des onboarding, d’absence de changement de contextes, de l’instantanéité du partage d’information …

Elle nous parle ensuite des impacts de la non pratique du Mob qui a pour conséquences de :

  • moins partager,
  • moins apprendre,
  • perdre de l’information,
  • plus retravailler l’existant,
  • selon elle, d’être moins fun.

Elle indique qu’il ne faut pas faire du Mob lorsque le problème à traiter est confidentiel, administratif ou trop simpliste mais qu’il est intéressant d’en faire pour tout le reste.

Elle insiste sur l’idée de faire des pauses lorsque les sessions sont trop intenses.

Pour terminer, elle indique que pour faire du Mob, il est important de rendre l’atelier facile et d’y aller progressivement en commençant par le préparer avec un but clair. Ensuite il est important de le mettre en place rapidement, de désigner un Navigator et un facilitateur. Puis de commencer par une petite contribution timeboxée à une ou deux heures au début afin de terminer l’atelier dans un bon état d’esprit.

Avec son support très simple à suivre et son aisance à l’oral, Lisi a su nous faire passer de nombreuses informations sur son retour d’expérience. C’est sans doute un des talks les plus marquants que nous avons pu voir dans toute la sélection du DDD Europe. On sentait qu’elle avait envie de partager tout ce qu’elle a vécu durant ses ateliers de Mob Programming ainsi que les enseignements qu’elle en a tiré professionnellement, mais également, personnellement.

Fin de journée

Ainsi se termine cette première journée de la Main Conference. Si la première journée dédiée à l'Event Sourcing était intéressante, pour nous, la première journée de la conférence principale a été bien au dessus.

Nous avons choisi de ne parler que des talks qui nous ont marqués mais on ne pouvait pas terminer sans dire qu'on a eu la chance de se retrouver à la table d'Alberto Brandolini pour le dîner. Nous avons ainsi pu poser différentes questions que nous avions suite à l'atelier fait dans la matinée !

Nous avons terminé cette journée éprouvante très tôt car le Main Event était pour le lendemain avec une journée commençant sur les chapeaux de roues mais ça, ce sera pour un autre article :)

Retours DDD Europe 2020 (Partie 2)

$
0
0
Retours DDD Europe 2020 (Partie 2)

On y est, notre dernier jour en tant que spectateurs d'une conférence d’ores et déjà incroyable ! Pour être tout à fait honnête, ce qui a fini de motiver notre participation est encore à venir puisque c'est la keynote de cette journée.

En échangeant avec les participants de DDD Europe 2020, nous (Anthony et Colin) savons que nous ne sommes pas les seuls à attendre avec impatience le passage sur la grande scène de Monsieur Kent Beck ! Pour rappel, le Monsieur est notamment :

Ce que beaucoup considèrent déjà comme le Main Event va commencer ! Nous sommes cependant perplexes à la lecture du titre du talk : "Continued Learning: The Beauty of Maintenance".

Kent monte sur scène, il explique qu'il ne savait pas de quoi parler dans une conférence sur le DDD. Il a donc mis un titre très générique (et aucune description) pour sa présentation.

Son but était de parler avec les participants pendant les premiers jours et de décider des sujets qu'il allait aborder en fonction de ces discussions. Nous allons donc assister à une présentation sur mesure.

Pas de slides, un écran tactile et un speaker d'un niveau stratosphérique à l'humour décapant : le début de la fin de cette conférence s'annonce vraiment sous les meilleurs auspices.

Après une introduction expliquant, qu'à un an près, il aurait fait de la musique et non pas de l'informatique (car il a changé de spécialité chaque année à l'université en alternant musique et informatique), il commence la présentation du premier des 4 sujets qui seront abordés :

  1. Comment gérer son stress lorsqu'on fait une présentation ;
  2. Cohésion et couplage ;
  3. Le retour du Waterfall ;
  4. Une pensée pour la fin.

Comment gérer son stress lorsqu'on fait une présentation

Mr Beck décide de commencer par un sujet pas du tout technique. Il nous le présente comme venant d'une discussion qu'il a eue dans l'ascenseur le matin même :

- A guy: "Aren't you stressed for your talk?" ("N'êtes-vous pas stressé pour votre talk ?")
- Kent: "I wasn't, but, now that you ask me, I am!" ("Je ne l'étais pas, mais, maintenant que vous me le demandez, je le suis !")

Puis, il nous avoue immédiatement que, non, il n'a pas répondu ça même si ça pourrait être une réponse très marrante !

Il nous donne ensuite sa vraie réponse : en faisant référence à "A Soprano on Her Head", il nous explique comment il a appris à transformer le stress qu'il ressentait avant de monter sur scène :

"Quand vous êtes stressés, que vous avez peur, avant d'aller présenter quelque chose vous avez les mains moites, le coeur qui bat rapidement et du mal à respirer non ?

Bien, maintenant imaginez vous enfant, derrière la porte pour aller chercher les cadeaux de Noël. N'avez-vous pas les mains moites, le coeur qui bat rapidement et du mal à respirer ?

Etiez-vous stressé ? N'était-ce pas plutôt de l'excitation ?

Nous avons pris l'habitude d'associer ces sensations au stress, à la peur, des sentiments négatifs mais nous pouvons tout aussi bien les associer à de l'excitation !

Maintenant, quand on me demande si je suis stressé avant de monter sur scène je répond : "Non ! Je suis excité !""

Avec le recul, nous pouvons rapprocher ce premier sujet d'un bref échange que nous avons eu avec lui les jours précédents. Nous avions profité de quelques secondes de sa disponibilité pour le remercier de ce qu'il a fait pour notre profession. Sa réponse a été immédiate : il nous a conseillé d'enseigner, de partager les connaissances que nous avions acquises.

En commençant son intervention avec un moyen d'échanger plus simplement et en nous invitant à enseigner, il confirme l'importance qu'il accorde au partage.

Bien que ce premier sujet ait été présenté de main de maître, il s'avère que c'est un travail que nous avions déjà fait. Nous en sortons cependant avec une bien meilleure manière d'expliquer cette approche et nous sommes impatients d'attaquer les geeky stuff.

Cohésion et couplage

Pour ce sujet technique, Mr Beck a décidé de parler d'un sujet au combien commun dans notre profession : la cohésion et le couplage.

Son premier constat est qu'il pense que tout le monde ne partage pas la même définition de ces termes. Il rappelle donc la définition originelle du couplage définie dans Structured Design : Si A et B sont couplés, si on change A, on doit changer B.

Il explique ensuite qu'on voit parfois un couplage plus fort que ce qu'il n'est réellement. Par exemple, si un service renvoie A et B et que ce service est utilisé par un autre service qui est, lui-même, utilisé par un troisième service :

Retours DDD Europe 2020 (Partie 2)

Si, dans le service 1, on veut changer A pour C (un nouvel attribut), on ne peut pas faire le changement en une fois car cela obligerait à synchroniser les changements. Il est cependant tout à fait possible de faire ce changement en plusieurs étapes. Tout d'abord, ajouter C dans le service 1 :

Retours DDD Europe 2020 (Partie 2)

Puis consommer C dans le service 2 :

Retours DDD Europe 2020 (Partie 2)

On peut alors consommer C et supprimer A dans le service 3 :

Retours DDD Europe 2020 (Partie 2)

Puis supprimer A dans le service 1 :

Retours DDD Europe 2020 (Partie 2)

Puis dans le service 2 pour arriver au résultat voulu initialement :

Retours DDD Europe 2020 (Partie 2)

Il a échangé à de nombreuses reprises sur ce problème et cette approche et, selon lui, beaucoup de personnes ont du mal à accepter cette solution qui commence par empirer les choses. Il nous donne alors ce qu'il présente comme une leçon de vie : "Things always get worse before they get better!" ("Les choses empirent toujours avant de s'améliorer !").

Pour continuer sur le sujet du couplage, il nous donne une anecdote vécue pendant qu'il travaillait chez facebook : une mécanique de sauvegarde a été changée sur l'application A et la solution B est totalement tombée ! En fait, les deux applications étaient hébergées sur des serveurs distincts mais dans le même rack. Les nouvelles sauvegardes de A ont totalement saturées le switch, rendant B indisponible.

Le but de cet exemple tiré d'un cas réel était de mettre l'accent sur un fait essentiel : "The most expensive is the coupling you don't see" ("Le couplage le plus cher est le couplage que l'on ne voit pas"). En fait, le couplage que l'on peut voir sera relativement simple (et donc peu coûteux) à changer. A l'inverse, ce type de couplage tout à fait inattendu va coûter des fortunes en analyses et en reconception.

Ces rappels sur le couplage faits, il insiste sur l'importance du découplage : "Decoupling things reduces the cost of changing things over time because those changes then don't cascade and become big changes." ("Découpler les choses réduit le coût des changements dans le temps puisque les changements ne vont pas entraîner des modifications en cascade et devenir de gros changements.").

Une transition toute faite pour parler du coût d'une solution, il présente alors cette équation :  "Cost of a solution ≃ cost of change ≃ cost of Big change" en expliquant que le coût total d'une solution est, en fait, proche du coût des gros changements.

Pour affirmer cela, il se base sur le fait que l'on ne peut pas avoir de solution satisfaisante sans prise en main par les utilisateurs (ce n'est pas le papa d'XP pour rien :)). De fait, notre solution doit être en production et utilisable le plus rapidement possible. Il ne reste alors que des changements qui constitueraient 99% des coût d'un projet (il avoue avoir pris ce chiffre au hasard parce qu'il sonnait bien).

Découpler les choses devient alors essentiel pour éviter les gros changements : si on peut faire des changements sur des sous-ensembles sans affecter le reste de la solution, c'est tout de suite plus simple !

Ces explications sur le couplage faites, il est temps de passer à la cohésion avec ce schéma :

Retours DDD Europe 2020 (Partie 2)

L'élément E est cohésif quand les éléments qui le composent sont couplés. Ok, donc, la cohésion (qui est une chose que l'on recherche) a besoin de couplage (qui est quelque chose que l'on veut éviter) !

Ce n'est pas tout à fait ça : la cohésion est un remède au mauvais couplage. Il est compliqué de découpler en cherchant simplement à découpler mais il est beaucoup plus simple de le faire en ajoutant de la cohésion. En changeant simultanément des éléments qui doivent effectivement changer en même temps, on n’aura pas les problèmes que pose le couplage.

Kent donne alors un exemple qu'il a vu chez l’un de ses étudiants : cet étudiant devait faire un refactoring de deux lignes de code. Il a :

  • Extrait une méthode contenant ces deux lignes ;
  • Fait la modification ;
  • Remis les lignes de code dans la méthode originelle.

Mr Beck dit qu'il a commencé par le charrier en expliquant qu'il aurait tout aussi bien pu faire directement cette petite modification dans la première méthode. Puis, après réflexion, il dit s'être rendu compte que ce qui avait été fait était tout à fait logique : son étudiant a ajouté de la cohésion et supprimé du couplage (avec le reste du traitement) en créant cette méthode. Il savait alors que ces modifications n'affecteraient que cet élément cohésif.

Après cette explication sur l'importance de l'ajout de cohésion dans nos solutions, Kent propose un verbe pour cette action : "Cohesivating". Puis, après quelques secondes d'une salle pensive, il avoue espérer une application de la lois de Cunningham.

Cette loi explique que, si on veut une réponse à une question sur internet, le meilleur moyen n'est pas de poser la question mais de donner une mauvaise réponse, on verra alors rapidement apparaître plein de bonnes réponses.

Mr Beck dit qu'il connaissait d'abord cette loi sous le nom "the rule of Mcdonald's" : Si vous voulez aller au restaurant mais que personne n'a de bonne idée, suggérez Mcdonald's. Vous allez immédiatement avoir des dizaines de bien meilleures alternatives !

Voilà qui termine ce second sujet sur la cohésion et le couplage. Même si nous connaissons bien ces problématiques, nous trouvons ici beaucoup de nouvelles pistes de réflexions qui vont très certainement nous aider dans un avenir proche !

Le retour du Waterfall

Après les deux premiers sujets il ne reste que quelques minutes mais il tient quand même à parler encore de deux choses, la première étant le retour du Waterfall : "Waterfall is back, it's stopped apologizing, and it needs to be killed with fire !" ("Le waterfall est de retour, il ne s'excuse même plus et il doit être tué par le feu !").

Comme on peut s'y attendre de la part d'un des fondateurs de l'agilité, il ne croit pas au Waterfall et nous présente alors ce processus de fabrication de solutions informatiques :

Retours DDD Europe 2020 (Partie 2)

Les idées génèrent des comportements. Ces mêmes comportements génèrent de nouvelles idées dans une boucle vertueuse tant que les idées structurent les comportements (et non pas l'inverse).

Pour appuyer son point de vue sur les dysfonctionnements du Waterfall, il imite un partisan de cette approche : "I have a big spec, what do you have? A bunch of testcases? Pfff!" ("J'ai une grosse spécification, qu'est-ce que tu as ? Un paquet de tests ? Pfff !"). Venant d'un des plus importants contributeur à la popularisation du TDD, le message est vraiment fort !

Toujours pour appuyer le fait que le Waterfall ne peut pas fonctionner il dit : "People use the word <organically> as some kind of pejorative. This codebase grew <organically>. I mean what is the other option you have to grow something?" ("Les gens utilisent le mot <organique> comme quelque chose de péjoratif. Ce code grandit de manière <organique>. Je veux dire, quelles sont les autres manières de faire grandir quelque chose ?").

Cette nécessité de répondre aux changements pour faire grandir une solution est définitivement entérinée avec : "Software made by carbon life forms... may grow organically" ("Des logiciels faits par des organismes à base de carbone… peuvent grandir de manière organique").

Malgré les très nombreuses punchlines que comporte cette partie, on sent bien que cette question l'affecte profondément ! Il nous explique alors que la communauté DDD est bien placée pour lutter contre cette recrudescence de Waterfall puisque la capacité à répondre aux changements est un des grands apports du DDD.

Le DDD demande aussi l'implication des experts métier pendant tout le processus de fabrication d'une solution. Les personnes présentes dans la pièce sont naturellement conscientes des dysfonctionnements des approches ne prenant pas en compte les retours au fil de l'eau.

Le but de ce troisième sujet n'était probablement pas d'expliquer les dysfonctionnements du Waterfall (même si ça a été fait avec brio) mais plutôt de nous faire prendre conscience du rôle que nous avions à jouer dans l'endiguement de cette épidémie.

En ce qui nous concerne, on peut dire que le message est clairement passé ! Et oui, pour nos collègues, ça veut dire qu'on va être encore plus pénibles qu'actuellement avec la fausse agilité… Et on n’est même pas désolé !

Une pensée pour la fin

Son dernier sujet concerne les changements dans les solutions : "Carefully separate structural change from behavior change [...] Behavioural changes can be irreversible while structural ones not. Which is the best for you to start from?" ("Séparez avec attention les changements de comportements des changements de structures [...] Les changements de comportements peuvent être irréversibles alors que les changements structuraux ne le sont pas. Quel est le meilleur point de départ pour vous ?").

Il conclut alors avec une phrase qui a rapidement fait le tour du Web : "Make the Change Easy Then Make the Easy Changes" ("Rendez les changements simples puis faites les changements simples").

En fait, cette phrase a tellement marqué les esprits que les organisateurs ont fait imprimer des stickers dans la journée !

Retours DDD Europe 2020 (Partie 2)

Ainsi se conclut cette keynote drôle, inspirante et touchante. Nous en sortons avec plein de réflexions naissantes directement sur le contenu abordé ou sur la manière de présenter un sujet. Merci, Monsieur Kent Beck !

Retours DDD Europe 2020 (Partie 3)

$
0
0
Retours DDD Europe 2020 (Partie 3)

On (Anthony et Colin) continue notre dernier jour de conférences à DDD Europe 2020 et cet article conclura notre passage à Amsterdam !

Architect’s Survival Guide to Healthcare par Sonya Natanzon

Sonya Natanzon, architecte chez Genomic Health, une entreprise spécialisée dans la recherche génétique et notamment dans la détection du cancer, nous parle de son expérience au sein de son entreprise.

Elle commence un talk très touchant en mettant en avant l'importance du Domain médical qu'elle met en parallèle d'un Domain qui a très souvent été présenté pendant la conférence : celui de la banque.

Elle explique avoir pris pleinement conscience de l'importance de ce Domain mais aussi de sa complexité lorsqu'une leucémie à été diagnostiquée chez son mari. A ce moment, elle a découvert la complexité du langage médical qui n'est tout simplement pas compréhensible pour les non-initiés (contrairement au langage bancaire, par exemple).

Elle nous rappelle alors l'importance de l'Ubiquitous Language dans ce type de Domains complexes et peu maîtrisés par la majorité des équipes de développement.

Depuis ces événements, elle s'est spécialisée dans les applications à vocation médicale et nous propose donc un retour d'expérience d'utilisation du DDD dans ce type d'environnement techniquement très spécifique.

Les architectures dans lesquelles elle évolue sont basées sur des ERP, des CRM et pléthore d'autres solutions absolument pas construites pour répondre à un besoin spécifique. Elle insiste sur les problèmes de couplage entre les solutions "maison" et ces solutions du marché. En fait, le couplage est même tellement fort qu'elle travaille avec un Monolithe Distribué.

Même si nous savons que cet anti-pattern est très nocif, il y a eu une image très parlante pendant l'un des talk (mais nous avons oublié lequel...) : "Il vaut mieux un gros tas de m***e que de la m***e étalée de partout". De fait, quand elle évoque ce terme, nous imaginons aisément les difficultés qu'elle rencontre au quotidien.

Comme on pouvait s'y attendre, elle a rassemblé les choses pour, ensuite, faire des découpages autour du métier (et des patients) et non pas des contraintes techniques. Malheureusement, dans le Domain médical, certains outils ne peuvent êtres supprimés, les développeurs sont donc forcés de garder certains découpages techniques.

Une fois le découpage un peu plus logique, elle a appris à se préparer aux audits (qui sont monnaie courante dans le domaine médical) en anticipant les demandes des auditeurs qui veulent des documents que l'on aimerait beaucoup ne pas avoir à produire. En étant capable de générer facilement des BPMN et autres "documents d'architecture" très éloignés de la logique du DDD, elle a pu se faciliter le quotidien et largement diminuer ce problème.

En tant qu'adeptes de méthodes de travail itératives centrées sur la réponse aux besoins métier, nous avons eu, sur le coup, une réaction épidermique aux diagrammes illisibles qu'elle a présentés (et qu'elle présente lors des audits). Cependant, avec le recul, nous nous rendons compte que ces diagrammes font partie de son métier.

Certes, ils n'apportent aucune valeur dans les solutions mais, sans eux, les solutions ne peuvent pas être utilisées car elle ne reçoivent pas les agréments nécessaires. De fait, dans ce genre de cas, lorsqu'on ne peut pas changer les règles du jeu (comme dans le cas de la loi), il peut être intéressant de s'outiller pour répondre à moindre coût à ces contraintes souvent déconnectées de la réalité.

Au final, un talk intéressant qui nous rappelle que, dans certains cas, la solution pragmatique peut être de donner aux gens ce qu'ils demandent (même si on sait pertinemment que cela n'apportera rien à la solution). On a aussi confirmé, une fois de plus, qu'il vaut largement mieux avoir un Monolithe qu'un Monolithe Distribué qu'on appellerait micro-services.

Systems Thinking and the Art of Simplification par Lorraine Steyn

Un talk sur le Systems Thinking par Lorraine Steyn, un sujet qui nous est totalement inconnu, un talk avec beaucoup d'informations : on ne va pas lui faire honneur ici…

Après une brève présentation de quelques uns des principes du Systems Thinking  (Rasoir d'Ockham, Success to the Successful, Rule Beating, …) Lorraine nous donne une manière de modéliser un Système :

Retours DDD Europe 2020 (Partie 3)

Dans cette représentation, on place :

  • Au centre ce que l'on veut modéliser ;
  • A gauche les entrants, ce qui va aider à la réussite (Inflows) ;
  • En dessous les contradictions (Discrepancy), ce qui au final ne sert pas notre but ;
  • Tout en bas le but à atteindre ;
  • Et à droite les éléments sortants qui pourraient empêcher l'atteinte de l'objectif.

En suivant ce modèle nous essayons, en séance, de faire le modèle d'efficacité d'une équipe de développement. Nous arrivons à ce résultat :

Retours DDD Europe 2020 (Partie 3)

Puis, Lorraine présente le modèle auquel elle est arrivée lors de sessions précédentes :

Retours DDD Europe 2020 (Partie 3)

On retrouve sensiblement les mêmes choses ce qui s'explique simplement par le fait qu'elle a beaucoup guidé l'atelier :). Par exemple, les policies avaient été mises dans les Outflows (pas dans les Inflows) mais Lorraine, en tant que chef d'entreprise, a tenu à ce que les règles de l'entreprise soient une aide et non un frein.

Après d'autres conseils concernant des sujets aussi divers que la manière de gérer son énergie ou comment faire des schémas lisibles, elle conclura en disant :

"Systems always behave exactly as they are designed, just not always as they are intended."

"Be creative and courageous about systems redesign."

Au final, ce fut un talk qui nous a plus même si nous n'avons pas pu en tirer tous les enseignements. Nous en sortons avec des sujets intéressants à creuser ou simplement à laisser maturer.

Lightning talks

Nous avons hésité à aller voir les Lightning Talks puisque le talk de la veille sur cette plage horaire nous a beaucoup marqué. Pour être tout à fait honnêtes, si nous nous étions un minimum renseignés et si nous avions su qui était Aslam Khan (le speaker faisant l'autre talk), c'est probablement lui que nous serions allés voir !

Mais, en fait, on a vu 3 très bons talks pendant cette heure ! Malheureusement, nous n'avons pas les vrais titres des talks mais on va quand même vous en parler.

DDD Iceberg par Marco Consolaro

Le premier talk qui nous a marqué était présenté par Marco Consolaro et on en a retenu son Iceberg du DDD. Dans cette présentation il introduit les pré-requis suivants au DDD :

Marco explique ensuite comment il accompagne des équipes de différentes entreprises dans l'apprentissage de ces bases en utilisant beaucoup de Mob Programming. L'exemple d'utilisation de cette approche pour l'enseignement dans notre article dédié vient justement de ce Lightning Talk.

Nous avons été très réceptifs à ce talk et à ces pré-requis puisqu'on a reconnu ce qu'on pouvait dire au cours des échanges avec les participants pendant les jours précédents.

La rapidité des résultats qu'il obtient en basant son enseignement sur des sessions de Mob nous a bluffé et nous allons nous y essayer dès que l'occasion se présentera (en fait, elle s'est déjà présentée pour Anthony et les résultats sont bons).

En plus de la manière d'enseigner, nous retenons une liste de prérequis plus formalisée que celle que nous pouvions avoir en tête. Il est fort probable que l'on réfléchisse à notre propre iceberg du DDD dans un avenir proche.

Types Driven Development

Ce second talk est présenté par Arnaud Bailly. Il parle de TDD, mais le premier "T" est pour Types. Il nous explique que, pour s'essayer à Idris, il a voulu faire un modèle de Domain. Il s'est alors rendu compte qu'en utilisant correctement les types pour représenter son métier il était "forcé" de faire les choses de la bonne manière.

En fait, il est possible de s'y prendre mal, mais ce sera bien plus compliqué que de faire des choses logiques. Utiliser un typage fort guide non seulement notre implémentation mais aussi la réflexion métier que l'on peut avoir sur notre Domain. Ce guide vient du fait que les types vont naturellement empêcher les opérations et peuvent donc nous amener à rendre implicites certains explicites !

Au quotidien, nous travaillons en Java et en Typescript, des langages qui ne sont pas naturellement fortement typés, mais nous essayons d'introduire au maximum des types et de suivre ce paradigme depuis quelque temps déjà.

Avant ce talk, nous étions déjà convaincus de l'importance des types mais nous n'avions pas encore poussé la réflexion jusqu'à guider l'analyse du métier par les types. Un nouveau point à garder dans un coin de la tête, peut être ressortira-t-il un jour.

Liskov

Le dernier Lightning Talk qui nous a marqué était présenté par Pedro M. Santos et l'idée initiale était de parler du principe de Substitution de Liskov (le L de SOLID).

Pedro commence par un rappel du principe et du but des héritages : "Un carré n'est pas un rectangle avec des côtés égaux puisqu'un rectangle a, par définition, des cotés qui ne sont pas égaux".

En réexpliquant Liskov et la validation des préconditions, des invariants et des postconditions, il explique qu'on peut construire des solutions :

  • Robustes ;
  • Résilientes ;
  • Fiables.

Ce talk nous a ouvert les yeux sur l'importance de ce principe mais nous devons encore laisser tout ça mûrir pour pouvoir en faire un retour intéressant. Pour le moment, tout ce que l'on peut dire, c'est qu'on a bien aimé et qu'il peut être intéressant de réfléchir là-dessus :).

Elephants, Patterns, and Heuristics par Rebecca Wirfs-Brock et Christian Kohls

On termine cette journée incroyable par un talk au titre plus ou moins étrange de Rebecca Wirfs-Brock et Christian Kohls.

Bien entendu, le titre fait référence à la Anekantavada (mais si, les aveugles et l'éléphant !) et, même si il y avait certainement bien plus à en retenir, nous retiendrons surtout des enseignements liés à, justement, l'enseignement.

Ce talk parle du Design Pattern Observer et va s'amuser à regarder différentes représentations de ce même Pattern, en commençant par celle du GOF. Les speakers mettent très rapidement le doigt sur un point important : non seulement sa représentation n'est pas la même en fonction des versions de Wikipedia mais certaines représentations sont tout simplement fausses !

Bien entendu les versions identifiées fausses ont été corrigées par les speakers avant la conférence.

Le fait que les versions diffèrent est intéressant, cela s'explique simplement par une volonté de rendre l'explication plus claire pour les lecteurs. Malheureusement, dans le cas des Design Patterns il est très simple d'introduire des erreurs dans les représentations.

Pour ces deux experts, les erreurs seront évidentes et ils pourront simplement les corriger mais ce n'est pas le cas des personnes découvrant le sujet, celles-là même pour qui une représentation simplifiée a été faite !

En voulant simplifier la représentation d'un problème complexe pour en faciliter l'apprentissage, les auteurs enseignent en fait des choses fausses ! Ces mauvaises représentations entraîneront alors de mauvaises implémentations et, de fait, des promesses non tenues.

Rebecca et Christian soulèvent alors la question de l'adaptation de la représentation en fonction des interlocuteurs. Certes, il faut toujours garder une représentation juste mais, dans certains cas, cette représentation juste ne pourra tout simplement pas être comprise.

Du coup, est-ce qu'il vaut mieux, parfois, donner une représentation un peu fausse (mais tenant quand même les promesses initiales) pour permettre aux interlocuteurs de comprendre ? Est-ce toujours possible ?

Dans certains cas, le meilleur moyen n'est-il pas de donner les pistes permettant à chacun de faire ses propres découvertes ?

Et en dehors des talks ?

En plus de la qualité tout à fait impressionnante des talks auxquels nous avons assisté, ce qui nous a marqué, c'est le très grand état de fatigue dans lequel nous étions (et pourtant on a été très sages).

Assister à des talks incroyables, échanger avec les participants en utilisant la technique du pac-man et essayer de perdre le moins d'informations possible aura rapidement eu raison de notre endurance.

Au final, on aura passé 4 jours mémorables à Amsterdam parce que oui, on est quand même allé faire un peu de tourisme avec des centres d'intérêt parfois différents. Pendant que Colin prenait en photo les bâtiments

Retours DDD Europe 2020 (Partie 3)

Anthony, lui, s'intéressait plus aux fromages...

Retours DDD Europe 2020 (Partie 3)

Outillage du Scrum Master d'équipes distribuées (partie I)

$
0
0

Introduction

Outillage du Scrum Master d'équipes distribuées (partie I)

Et oui, effectivement les garçons : c’est l’an 2000 et il est parfois nécessaire dans un contexte projet complexe de répondre à des problématiques de travail à distance ou avec des équipes distribuées. Il est donc primordial de bien s’équiper pour faire face à :

  • La différence de fuseau horaire,
  • La différence de langue,
  • La vision,
  • La communication,
  • La collaboration,
  • Etc.

C’est encore plus vrai aujourd’hui, avec le COVID-19 qui nous force au travail en équipes ultra-distribuées. Je vous propose ce premier article pour partager les premières idées et solutions techniques à votre nouveau quotidien.

Un peu de contexte

Si le contexte vous passe au dessus,

Cela va faire bientôt dix mois maintenant que je travaille depuis Bordeaux sur un produit avec une équipe de développement basée principalement sur Lyon.

Le périmètre ayant beaucoup évolué, nous sommes passés d’un MVP de trois mois pour quatre personnes à :

  • 2 développeurs, Lyonnais ;
  • 2 DevOps/Cloud (intitulé de poste étrange, mais ce sont des développeurs spécialisés dans l'industrialisation logicielle et l’architecture pour le Cloud) ;
  • 1 développeur, Bordelais ;
  • 1 équipe Ippon support, plus globale pour le DevSecOps (DevOps avec une couche sécurité intégrée) ;
  • Le Product Owner, côté client Lyonnais : Oui oui, pour de vrai et qui est sur Lyon, mais qui doit voyager souvent ;
  • 1 architecte partie prenante, côté client Lyonnais ;
  • 1 équipe du client à Pékin pour la partie du code historique.

Et demain, probablement, ce produit va faire des petits dans un plus vaste projet, avec par exemple le marché américain.

Dans ce contexte, en tant que Scrum Master, je dois composer avec cette situation qui peut sonner dissonante sur la partition de l’Agile Manifesto. Dans un second article, je m’attarderai plus sur mon travail avec l’équipe, les problèmes que j’ai rencontrés, les pièges, les améliorations pour la prochaine fois.

Notre sujet pour ce premier article : les outils !

Je vais vous présenter ce que j’utilise dans mon quotidien depuis les tranchées, mais aussi des alternatives, réparties par thèmes.

Et comme c’est vous, j’irai chercher d’autres outils pour aller plus loin...


🚨 Attention 🚨

J’apporte un jugement qui n’engage que moi. Mon avis peut évoluer demain en raison de l’évolution des fonctionnalités, des tarifs ou toutes autres raisons et expérimentations.

Il ne faut pas oublier que le contexte dans lequel l’outil est utilisé peut influencer votre jugement :

  • personnalisation,
  • droits d’accès,
  • niveaux de l’offre,
  • accès à distance via VPN,
  • latences réseaux,
  • système d’exploitation utilisé : Windows, Mac OS, Linux,
  • navigateur web,
  • etc...

De plus, je ne connais clairement pas toutes les limitations des outils qui peuvent influencer le choix de telle ou telle solution (nombre de participants max, rétention des informations, stockage, prix, ...).

Les solutions

Les outils étant de plus en plus riches en fonctionnalités, certains peuvent se retrouver dans plusieurs thèmes. Pour plus de clarté, je vais détailler l’outil dans le thème qui me semble le mieux lui convenir.

Je tâcherai de montrer les avantages, mais aussi les limites.

Communication

Dans cette catégorie il y a deux mastodontes : Teams et Slack.

Slack, la référence

Slack est un outil de messagerie instantanée, vidéo conférence, espace privé pour des équipes ou communautés.

Il n’est probablement pas le précurseur dans le domaine, mais il est très vite devenu la référence. C’est une valeur sûre pour un grand nombre d’entreprises qui souhaitent une solution gratuite.

Outillage du Scrum Master d'équipes distribuées (partie I)

L'interface est claire, simple et personnalisable pour les fans des modes sombres. Il est aussi possible d'épingler des messages importants et de naviguer dans l’historique des conversations des différentes salles de conversations.

Concernant la discussion audio et vidéo, c’est déjà moins simple. Il faut contacter les personnes pour créer une conversation directe, puis vous pouvez appeler le groupe.

L’outil existe en version gratuite, ou payante, par utilisateur et par mois, qui ajoute quelques fonctionnalités à l’outil, principalement d’administration et de stockage de données.

Avantages Inconvénients
• Beaucoup de plugins et addons pour augmenter les fonctionnalités Ex: Bot Jenkins, GitLab et d’autres notifiers utiles (ou non) • Gourmand en ressources
• Audio et Vidéo pas très user-friendly

Remarque: Il existe Mattermost, véritable jumeau de Slack, si vous souhaitez installer votre propre instance sur un serveur de l’entreprise. En plus, il est opensource !

Teams, le challenger

Outillage du Scrum Master d'équipes distribuées (partie I)

Après Lync et le rachat de Skype, Microsoft a créé la solution Teams pour venir jouer sur le terrain de Slack.

Cet outil est devenu très rapidement l’outil principal de beaucoup d’entreprises. L’atout majeur de Teams est qu’il est très connecté aux autres outils de la suite Office de Microsoft (Excel, Word, Sharepoint and co.).

Il est également gratuit avec une version payante par utilisateur et par mois, pour plus de support aux entreprises.

Avantages Inconvénients
• Environnement Office • Sentiment de lourdeur
• Navigation dans les menus ou création de conversation pas toujours intuitive

Gmail/Hangout/Meet

Google propose aussi ses solutions : Gmail, l’indémodable client mail, mais aussi Hangout et Meet. Le premier permet la création de conversations via des messages instantanés, mais aussi par audio ou vidéo. Quand au second, il est lui spécialisé dans la communication par vidéoconférences. Pas toujours évident de faire la différence.

Outillage du Scrum Master d'équipes distribuées (partie I)

Il est facile avec Google Agenda ou Gmail de créer une vidéoconférence Meet pour tous vos participants.
Vous n’avez pas fini d’entendre :

”Est-ce qu'il y a un lien Hangout disponible pour la réunion kata de ce midi ?”

Discord, l’outsider

Outillage du Scrum Master d'équipes distribuées (partie I)

Moins connu par les entreprises, il est très populaire dans l’univers du jeux vidéo.

Discord a une vision produit très différente de celle de Slack ou de Teams puisqu’il est véritablement orienté sur la voix — dans le domaine du jeu vidéo.

ll est possible de créer des canaux de discussion exclusivement textuels, mais surtout des canaux uniquement vocaux, ce qui est son point fort. Très facile donc pour garder l’esprit de l'open space. Changer de canal est très simple pour entamer une discussion “face à face” ou à plusieurs, sans devoir créer systématiquement des invitations.

Un autre point fort est indéniablement la qualité du son, lors des conversations vocales.

Avantages Inconvénients
• Appuyer pour parler • Pas ou peu d’intégration avec des outils professionnels “classiques”
• Canal de discussion vocal dédié • Partage d'écran en 720p (dans la version gratuite)
• Peu gourmand en ressource

Gestion de projet

La gestion de projet et des tickets de travail est importante pour tracer des idées de fonctionnalités, suivre l’avancement, observer et corriger les dérives, planifier la suite.

Jira

Sans conteste la solution dans toutes les têtes aujourd’hui pour répondre à ce besoin. Jira vous permet de créer des tickets, les ajouter dans un tableau de bord et suivre l’avancement. Je fais simple : il y a tellement plus à faire avec cet outil !

Malgré une interface très fournie, il reste agréable à utiliser, une fois bien pris en main.

Attention néanmoins à garder un flux de gestion des tickets simple et de limiter le nombre de champs par ticket, sinon vous aurez rapidement une usine à gaz que seule l’équipe dirigeante voudra utiliser.Il existe une version SaaS, mais vous pouvez avoir votre propre instance sur votre serveur d’entreprise.

Outillage du Scrum Master d'équipes distribuées (partie I)
Avantages Inconvénients
• Il peut tout faire • Licence
• Grosse communauté avec beaucoup de connexions et d’applications tierces qui permettent d’enrichir l’outil • Il peut tout faire

GitLab

GitLab est un gestionnaire de version ++. Ou, pour vulgariser, un dépôt de code source versionné.

Au fil du temps, GitLab a étoffé son offre et maintenant, il possède également une gestion du backlog riche, un tableau de bord type Kanban, les épopées, graphiques d’avancement, etc.

L’avantage est qu'il est déjà dans l’univers de vos développeurs, ça leur parle. Sur le même modèle que Jira, il existe une version SaaS, mais vous pouvez avoir votre propre instance chez vous.

Avantages Inconvénients
• Outil tout-en-un : de l’idée à la priorisation, réalisation du code et tests, jusqu’au déploiement en production. “Alors, heureuse ?” • Nécessite une licence
• Logiciel open source • Univers moins familier pour un non-développeur

Trello

Beaucoup plus limité que GitLab et Jira, Trello reste simple et efficace pour la création de tickets et la gestion en colonnes des tâches à réaliser pour faire le suivi de manière collaborative.

Outillage du Scrum Master d'équipes distribuées (partie I)

Avantages Inconvénients
• Gratuit • Limité (Keep It Simple Stupid ?)
• Simple d’utilisation
• Attacher des check-list aux tickets, pratique pour les DOD


Travail collaboratif

Google Drive

Si vous avez un compte Google, vous avez certainement déjà utilisé Google Drive pour stocker et partager des fichiers. Il permet également de créer des documents, à la manière de la suite Office :

  • Traitement de texte avec Google Docs (Word),
  • Tableau, Google Sheets (Excel),
  • Présentation, Googles Slides (Powerpoint)

Et ce, de manière collaborative !

"Seul on va vite, ensemble on va loin" — Proverbe africain

Si vous n’avez pas Microsoft Office, c’est une bonne alternative gratuite, dans la limite de l’espace de stockage offert.
Il existe également une version Google Suite pour les entreprises voulant totalement se couper des services de Microsoft.

Avantages Inconvénients
• Gratuit • Google, ce qui peut être limitant, notamment avec l’équipe Chinoise
• Google :)
• Terriblement bien intégré à notre quotidien, il est encore plus facile de ne plus décrocher, même sur son smartphone

Sharepoint

La solution Microsoft pour l’intranet de travail en équipe et de stockage documentaire. Cet outil est aujourd’hui bien intégré dans l'écosystème Office, voire même transparent, par exemple dans Teams.
Je n’ai pas spécifiquement travaillé dessus, mais la solution est à envisager si vous avez déjà une utilisation de Microsoft Office 365.

Klaxoon

Mon coup de cœur depuis longtemps !

Outillage du Scrum Master d'équipes distribuées (partie I)

Klaxoon est un pur outil collaboratif, de type “tableau blanc numérique”. Des post-its, du dessin, des images... Il vous permet d’animer un atelier d’idéation sans devoir ranger la salle après.

Vous pouvez également en sortir un rapport complet avec les images, les discussions, les feedbacks de l’atelier, que vous pourrez réutiliser dans votre Excel adoré.

Je l’utilise pour mes rétrospectives de sprint, partager une roadmap ou animer un atelier d’EventStorming. Mais il y a tellement d’autres utilisations possibles ! Car l’outil ne se limite pas qu’au tableau blanc : quizs, questionnaires, formations, par exemple.

C’est Made in France. Il est gratuit pendant 3 mois (COVID oblige), je ne sais plus quoi dire d’autre… Foncez !
https://klaxoon.com/fr/

Outillage du Scrum Master d'équipes distribuées (partie I)

Avantages Inconvénients
• Rétrospective Scrum ou un autre atelier d’introspection plus originale que Trello • Prise en main pas évidente pour les participants
• Modules de Reporting • Pas possible de masquer les post-it en mode libre
• Riche de fonctionnalités (quizs, formations, sondages, etc.)

Miro

Sans faire de mauvais jeux de mots, c’est l’équivalent de Klaxoon. Je ne l’ai personnellement pas testé, mais d’après un retour que j’ai reçu d’une personne l’ayant essayé, il est certes moins complet que Klaxoon mais plus facile à appréhender.

Outillage du Scrum Master d'équipes distribuées (partie I)

Autres

PointingPoker, pour le Poker planning

Il faut bien continuer à estimer. PointingPoker est un outil simple et efficace pour votre atelier d’estimation relative, en Sprint Planning, ou en ateliers d’affinage.

Et surtout pas besoin de créer un compte !

CoVid-19 oblige, le succès de l’outil met l’outil à rude épreuve. Il connaît ces derniers temps des pics d’utilisation qui peuvent ralentir ou rendre indisponible l’application web.

https://www.pointingpoker.com

Une alternative :  https://www.planitpoker.com

Pomodoro, l’art de rester concentré

Si comme moi perdre le focus sur votre travail est votre cauchemar quotidien, il existe une technique simple : le pomodoro

Outillage du Scrum Master d'équipes distribuées (partie I)
  • 25 minutes de travail sur une tâche
  • 5 minutes pour traiter ce que vous avez en attente ou une pause technique
  • Vous bouclez 4 fois comme ça et vous faites une vraie pause de 15 min.

Personnellement, j’utilise Be Focused (Mac). Il existe un équivalent pour Windows ici, Linux ici et android ici.

Lorsque vous êtes seul.e chez vous à travailler, c’est aussi un bon moyen de rythmer votre journée et de réussir à vous imposer des coupures dans votre travail.

Reveal.js, le “Powerpoint” du dev

Il faut l’admettre, faire une présentation Powerpoint, pour beaucoup, ce n’est pas la définition du plaisir. Et c’est souvent le cas dans la communauté des développeurs.

Une solution alternative est Reveal.js. Avec un Docker, un GitLab, vous pouvez ainsi partager des présentations et les versionner sans encombre dans l’environnement habituel de l’équipe de développement.

Outillage du Scrum Master d'équipes distribuées (partie I)

Avantages Inconvénients
• Permet d’aller droit à l’essentiel • La personnalisation de l’outil demande de faire un peu de code HTML/CSS
• Nécessite d’avoir des connaissances en développement ou de se faire aider par un dev pour pouvoir démarrer un nouveau projet de ce type

Also nominated (Aussi nominés)

Dans la liste des nominés, il y a certains outils que je n’ai pas testé ou utilisé personnellement. Certains d’entre eux seraient dignes d’un article dédié pour une analyse plus en profondeur 🤔

Communication

Gestion de projet

  • Redmine, logiciel open source pour la gestion de tickets
  • Mantis Bug Tracker, pour la gestion de tickets pure et dure
  • GitHub, même chose que GitLab, racheté par Microsoft ;)

Collaboratifs

  • Mural, dans la lignée de Klaxoon et Miro, en moins “inspiré”. Mais il possède pas mal de canevas pour aller plus vite dans la mise en place d’ateliers.
  • FunRetro, rien de bien “fun”, mais pour faire des rétros et garder une confidentialité sur les post-it lors de l’étape l’idéation, c’est cool !
  • IdeaBoardz, dans le principe de Klaxoon & Miro aussi.

Autres

  • Confluence, Outil de type Wiki par Atlassian (Jira)

Ma liste pour mon contexte projet

Dans le cadre du développement de ce produit, nous utilisons :

Teams (Client)

Quand : Pour les cérémonies Scrum, le Daily Scrum Meeting et les réunions en visioconférence.

Avis : C’est la solution aujourd’hui que nous utilisons pour communiquer avec notre client. C’est un produit assez lourd, je trouve, mais qui fait bien le job. Les outils de bureautique en entreprises sont principalement signés Microsoft et c’est mon avis, mais aujourd’hui les alternatives ne sont pas au même niveau.

Google Drive (Ippon) avec GSuite

Quand : L’outil privilégié chez Ippon. Nous l’utilisons pour le partage de fichiers et la préparation de supports pour les comités de pilotage, par exemple.

Avis : Fait très largement le job. Même si l’écriture à huit ou douze mains avec Google Suite est top, je trouve qu’un petit Powerpoint est plus riche aujourd’hui pour certaines fonctionnalités.

Klaxoon (Ippon et Client)

Quand : Pour les rétrospectives à distance, le partage d’un User Story Mapping et pour les ateliers de travail

Avis : Efficace, stable, apprentissage rapide. J’aime, et pis c'est tout.

GitLab (Client) version Silver

Quand : Product Backlog et Sprint backlog, gestionnaire de configuration CI/CD

Avis : Habitué à Jira, j’étais un peu frileux au début et finalement il fait très bien le travail. Dommage pour le prix de la licence, car en dessous de la Silver (voir Gold), il faut ruser pour rédiger/gérer les épopées, par exemple.

Gmail/Hangout/Meet (Ippon)

Quand : Pair-programming, discussions quotidiennes

Avis : Simple et efficace. Mais clairement pas la solution efficiente.
Avec Meet par exemple, il faut créer ou transférer sans arrêt des liens de conférence. Pour Hangout, ce sont les fenêtres qui s'empilent aussi vite que le CoVid19 se propage. Au fil du temps, il faut également faire le ménage dans les conversations et ne surtout pas lancer un appel audio/vidéo avec une ancienne discussion. #ButtCall
Enfin, toujours avec Hangout, ce n’est pas toujours évident de gérer les participants à une conversation.

Reveal.Js

Quand : Support de présentation pour les cérémonies de Sprint Review

Avis : Clairement pas l’outil qu’un non-développeur va mettre en place. Mais une fois la présentation faite, le “Faire Simple” est très vite apprécié de tous.

Be Focused

Quand : Pour moi et mon focus

Avis : Merci Mr. Pomodoro


Si tu as d’autres suggestions d’outils, n’hésite pas à écrire un commentaire, pouce bleu, abonne-toi à la chaîne, toussa, toussa… >_<

La suite dans le prochain épisode.

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

$
0
0

Introduction

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

Le but de cet article est de vous partager mon retour d'expérience quant à la mise en place d'une solution de sauvegarde pour des applications stateful hébergées sous Kubernetes.

L'utilisation de Kubernetes est principalement axée sur le déploiement d'applications de type stateless, c’est-à-dire sans stockage persistant.

Mais il arrive fréquemment que l'on ait besoin de stockage persistant pour des applications dites stateful, comme par exemple Cassandra, CouchBase, CouchDB etc.

Le cycle de vie (déploiement, provisionnement, maintenance, etc.) est grandement facilité via l'usage de Kubernetes pour ce type d'applications.

Cependant, il reste une problématique à résoudre : comment pouvons-nous sauvegarder ces données dans le cas d'un Disaster Recovery ?

Même si les données sont réparties sur des volumes redondés et séparés, cela ne nous protège pas d'un sinistre majeur. C'est là qu'intervient le besoin de sauvegarder nos données.

Avec l’émergence de l’utilisation d’applications stateful, l'écosystème Kubernetes commence à voir arriver des solutions de sauvegarde pour les données persistantes.

L'une d'entres elle, Velero, anciennement Ark Heptio, est la plus aboutie à ce jour.

Contexte

Aujourd'hui nous hébergeons des applications stateful sur notre Kubernetes on-premise pour lesquelles leurs volumes sont rattachés en mode bloc (RBD) à un cluster Ceph existant.

La jonction entre Kubernetes et Ceph sera expliquée dans un second article. (voir POC 2)

Nous allons voir ensemble comment nous pouvons procéder afin de sauvegarder nos applications stateful sur Kubernetes avec des volumes externes attachés.

Présentation de l’infrastructure

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

Sauvegarde des volumes persistants k8s avec Velero

Velero est l'outil le plus mature pour sauvegarder les clusters Kubernetes.

Il s'appuie sur des fonctionnalités de snapshots offerts par les cloud providers afin de réaliser des sauvegardes des volumes persistants.

Velero s’utilise pour effectuer des sauvegardes complètes (ex: configmaps, deployment, etc.), ou bien uniquement des sauvegardes de certains namespaces ou types de ressources (ex: pods etc.). Il prend en charge la sauvegarde de presque tous les types de volumes Kubernetes, quel que soit le fournisseur de stockage utilisé.

L'exécution de Velero peut se faire manuellement selon le besoin ou bien via une tâche programmée pour s’exécuter à interval de temps régulier.

Dans notre cas pratique, nous n'utilisons pas les snapshots mais nous couplons Velero avec Restic et Minio afin de réaliser et stocker nos sauvegardes.

Dans sa version 1.2, Velero permet essentiellement d’utiliser un stockage objets pour stocker nos sauvegardes et inclut de nouvelles fonctionnalités et une amélioration de l'intégration avec Restic.

Dans le cas d'une utilisation sur AWS il est recommandé d'utiliser le service S3 afin d’avoir une compatibilité native.

Pour une utilisation on-Prem, nous substituerons le service S3 par Minio (service de storage objets) compatible avec l'API Amazon S3.

Pourquoi Minio et non pas Rook ? Tout simplement parce que Minio est plus simple à mettre en place et nécessite beaucoup moins d'artéfacts.

Pour une utilisation plus avancée du stockage objets il est préférable de se tourner vers Rook qui permet une mise à l'échelle bien plus performante et permet de s’adapter à l’évolution de nos besoins (volumétrie, type de service etc.).

Et Restic alors ?

Restic sera notre clef de voûte, c’est lui qui va nous permettre de faire le lien entre notre orchestrateur de sauvegarde et notre espace de stockage. Il va s’occuper de prendre en charge les sauvegardes de nos volumes persistants.

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

Pour profiter de cette intégration, il faut utiliser au minimum la version 1.10 de Kubernetes.

Voyons ensemble comment faire pour faire fonctionner tout ce beau monde.

installation de HELM

Nous allons nous appuyer sur HELM afin de réaliser les déploiements des composants Velero et Minio.

L’installation de Restic sera incluse dans l’installation de Velero lors de l’initialisation.

Pour cela il faut s'assurer d'installer les composants nécessaires pour faire fonctionner HELM.

2 étapes sont requises :

  • Télécharger Helm sur un client :

brew install kubernetes-helm ou via les binaires présents sur github.

  • Initier l'installation de la partie serveur via la commande :

helm init

Cela va installer le pod Tiller sur le namespace kube-system afin que les appels API puissent être interprétés par Kubernetes.

Il se peut que vous rencontriez une erreur lors du lancement du pod Tiller. Veuillez à vérifier les logs et assurez-vous d'avoir les bonnes autorisations (RBAC) configurées.

Ici, un exemple de compte de service et RBAC "type" pour Tiller:

cat << EOF | kubectl apply -f -

apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1

kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system
EOF
helm init --service-account tiller

Une fois le pod Tiller opérationnel, on est en mesure d’utiliser la commande helm pour faire nos déploiements.

Installation de Minio

L'installation de Minio est simplifiée grâce à l’usage de Helm. Le repository stable de Helm inclut les charts nécessaires pour installer Minio, il suffit d'exécuter la commande suivante :

helm install stable/minio --name minio --namespace velero -f minio-aws.yaml --debug

Cela va installer la version stable de Minio dans le namespace velero. Le déploiement est constitué de 2 jobs et d'un pod en mode standalone.

Pour notre cas d’usage nous n’avons pas besoin de faire fonctionner Minio en mode cluster.

L'option -f nous permet de passer un fichier de paramètres qui va surcharger les valeurs initiales afin de coller à notre besoin.

Exemple de surcharge

image:
  tag: latest
accessKey: "accessKeyMinio"
secretKey: "secretKeyMinio" ## L'utilisation est semblable au service Amazon S3

service:
  type: ClusterIP
defaultBucket:
  enabled: true
  name: velero ## permet la création du bucket de sauvegarde à l’installation
persistence:
  enabled: true ## activation de la persistance du volume 
  accessMode: ReadWriteOnce
  size: 500Gi ## on définit la taille de notre PV dédié à Minio

ingress:
  enabled: true
  annotations:
    kubernetes.io/ingress.class: nginx
  path: /
  hosts:
    - notreURL.minio.ext.zone ## On définit une URL d'accès pour la webui Minio à travers notre ingress pour exposer le service minio

Installation de Minio client

L'accès aux données de Minio peut se faire via l’interface web ou bien directement en console via une communication interne.

Nous utiliserons un pod dédié pour installer le client Minio.

Le processus reste simple:

  1. On télécharge le MC Minio Client (voir ici) :

docker pull minio/mc

  1. On configure la connexion au serveur :

mc config host add minio-local http://minio-svc:9000 accessKeyMinio secretKeyMinio S3v4

Ne pas oublier de spécifier l’algorithme d'authentification Amazon S3 Signature Version 4 à la fin de la commande mc, sans quoi l'authentification ne sera pas reconnue.

  1. On effectue les opérations voulues :

mc ls minio-local / mc rb minio-local

Les commandes mc disponibles sont semblables à celle de la commande awscli pour S3 (c’est-à-dire rb bucket / mb / ls etc.)

Nous sommes maintenant en mesure de naviguer dans l’arborescence de notre bucket.

installation de Velero

Nous gardons le même principe d'installation via HELM :

helm install stable/velero --name velero --namespace velero -f velero-aws.yaml --debug

Exemple de surcharge utilisé

image:
  tag: v1.2.0 ## Choix de la dernière version de velero (v1.2 à ce jour)
configuration:
  provider: aws ##  Minio étant compatible avec l’API S3 on laisse aws comme provider 
  backupStorageLocation:
    name: aws
    bucket: velero
    config:
      region: minio ## permet d’informer velero que l’on utilise un endpoint spécifique (non aws)
      s3ForcePathStyle: true
      publicUrl: http://notreURL.minio.ext.zone ## url utilisé pour l’interface web et l’accès aux logs
      s3Url: http://minio.velero.svc.cluster.local:9000 ## url utilisé en interne dans k8s
credentials:
  useSecret: true
  secretContents:
    cloud: |
      [default]
      aws_access_key_id = accessKeyMinio
      aws_secret_access_key = secretKeyMinio
snapshotsEnabled: false ## On n’active pas cette fonctionnalité

configMaps:
  restic-restore-action-config:
    labels:
      velero.io/plugin-config: ""
      velero.io/restic: RestoreItemAction
    data:
      image: gcr.io/heptio-images/velero-restic-restore-helper:v1.2.0 ## Choix de l’image pour la restauration des pods via restic
deployRestic: true ## Permet l’activation et la création des pods Restic

Cela va installer la version stable de velero dans le namespace velero. Le déploiement sera constitué d'un pod Velero gérant les appels API et d'un pod Restic par node gérant les accès aux volumes.

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

Lors de son déploiement Velero va créer de nombreuses ressources CRD (Custom Resources Definitions).

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

Les 3 ressources essentielles à connaître sont :

  • PodVolumeBackup

Il représente une sauvegarde Restic d'un volume dans un pod.

Ainsi, lors d’une sauvegarde, Velero va créer une ressource de ce type dès qu’il trouvera un pod ayant l’annotation backup.velero.io/backup-volumes.

  • PodVolumeRestore

Cette ressource représente une restauration d’un volume pour un pod.

Lors d’une restauration Velero va créer une ressource de ce type et Restic prendra le relai afin de restaurer les volumes associés aux pods.

  • ResticRepository

C’est tout simplement la définition de l’endroit où les données seront stockées et la gestion des actions Restic.

installation de Velero client

Nous installons localement la partie cliente de Velero mais cela pourrait très bien être fait directement dans un pod. La partie cliente nous servira à envoyer nos requêtes au serveur Velero afin que nos actions de sauvegardes/restaurations soient effectuées au sein du cluster Kubernetes.

Le processus reste identique à celui de Minio dans les grandes lignes :

  1. On installe le client :

brew install velero ou via les binaires

  1. On effectue nos commandes Velero:
velero backups get
velero restore get
etc.

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

Test de sauvegardes

Une fois l'infrastructure en place, il ne reste plus qu'à effectuer nos premières sauvegardes ;)

Pour l'instant, Velero nous oblige à annoter l'ensemble de nos ressources (PV) afin que la sauvegarde prenne en compte les volumes persistantes.

Pour cela, soit on le fait dans la définition de notre StatefulSet en indiquant le préfixe de nos volumes soit on le fait dans chacun de nos pods avec le nom du volume exact.

Exemple

# Annotation du pod avec velero.io/backup-volumes (volume prefix name: couchdb-data)

kubectl -n couchdb annotate pod/couchdb-0 backup.velero.io/backup-volumes=couchdb-data-couchdb-0

# Création de la sauvegarde pour le namespace complet (avec toutes les ressources présentes)

velero backup create backup-couchdb-test --include-namespaces couchdb

# Obtenir des détails

velero backup describe backup-couchdb-test --details

L’option --details permets de nous assurer que le volume attaché au pod à bien été pris en compte lors de la création de la tâche de sauvegarde. Cette vérification peut également être faite dans les logs de velero.

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

Il est également possible de vérifier le contenu et la taille du bucket créé par Restic pour notre tâche de sauvegarde est cohérent avec la source via minio-client.

Après quelques heures de manipulations on arrive à bien comprendre le principe de backup et comment les différentes briques s'orchestrent entres elles.

Création d'un job programmé de type autoBackup

Quoi de mieux que des sauvegardes lancées automatiquement ?

Velero nous permet de lancer plusieurs jobs de sauvegarde à interval de temps régulier afin de respecter notre RPO (Recovery Point Objective) vis-à-vis de nos clients. Les sauvegardes seront incrémentales et nous pourrons avoir un retour arrière suffisant pour pallier à une perte de données par exemple.

Voici les 2 tâches programmées :

# Tous les heures avec une rétention de 24h (suppression au-delà)

velero schedule create hourly-cassandra --schedule="@every 1h" --ttl 24h0m0s

ou également :

velero schedule create hourly-cassandra --schedule="0 * * * *" --ttl 24h0m0s
# Tous les jours avec une rétention de 7 jours

velero schedule create daily-cassandra --schedule="@every 24h" --ttl 168h0m0s

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

Il est bien évident que l’on peut adapter ce principe aux besoins clients selon les types d’applications que l’on veut sauvegarder, leurs criticités etc.

Test ultime : la restauration

Le moment de vérité. Théoriquement, nos sauvegardes sont opérationnelles. Vérifions cela.

La première chose à faire et de s'assurer que notre backup est Completed avec la prise en compte du volume (PV) dans les logs du backup.

Une fois cela fait, nous pouvons faire notre test de restauration en supprimant complètement notre environnement de test.

kubectl delete ns awsjordan

La policy du StorageClass Ceph est laissée sur "Delete" pour s'assurer que nos volumes sont bien supprimés lorsqu’un pod est détruit sinon il faut s’assurer de faire la suppression manuellement.

# Obtenir les infos sur la sauvegarde

velero backup get

velero backup logs backup-couchdb-test --details

# On initie le processus de restauration, depuis notre dernier backup, verdict ?

velero restore create restore-couchdb-test --from-backup backup-couchdb-test

# Obtenir plus de détails

velero restore describe restore-couchdb-test

velero restore logs restore-couchdb-test --details

Exemple de cas concret :

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

La restauration complète du namespace peut prendre un certains temps mais nous pouvons vérifier sa progression grâce à l’option --details.

Pour les pods, Restic provisionne un sidecar qui va permettre de recréer les volumes originaux présent sur Minio.

Et enfin, une fois le pod à nouveau Running, nous retrouvons la présence des données dans le nouveau pod restauré :

POC 1 Velero : Sauvegarder des applications stateful sur Kubernetes

Hourra \o/ nos données sont de nouveau là.

Conclusion

Il s'agit d'un simple retour d'expérience pour vous aider à sauvegarder vos applications stateful sur Kubernetes.

Nous avons pu voir que l’ensemble des composants se configure aisément et correspond à notre besoin, à savoir, sauvegarder les données Stateful de nos apps sur Kubernetes.

Les développements sont actifs du côté de Velero et l’écosystème Kubernetes commence à porter un peu plus d’attention aux apps stateful jusqu’alors mise de côté.

J'espère que cela aura pu aider certains d'entres vous à démystifier l'univers Kubernetes et notamment la sauvegarde de vos applications stateful.

Viewing all 938 articles
Browse latest View live