Problème de connection à Oracle

06/11/2015 prod, tips No comments , , , , , ,

Deux problèmes assez courant peuvent survenir sur les connections à une base de donnée Oracle. Ces problèmes peuvent être à l’origine de timeout sur les connections HTTP, etc…

Ces deux problèmes touchent deux choses totalement différente, l’entropie du système et la coupure de connection par un firewall.

Entropie

Pourquoi l’entropie ? L’entropie est une mesure de l’incertitude d’un message par rapport à celui qui le précède. Sur un système POSIX c’est /dev/random qui est mesuré avec l’entropie. Hors la JVM utilise ce device pour la génération de nombres aléatoires utilisable pour des fonctions cryptographique, SecureRandom.

Hors le driver Oracle 11g (possiblement dans les versions précédentes aussi) établie un lien sécurisé avec la base donnée pour protéger les échanges de credentials.

Le problème vient du fait que la lecture dans /dev/random est bloquante tant que le système (Linux, BSD, etc.) considère qu’il n’y a pas assez d’entropie. Heureusement en bon lecteur de la javadoc il y a une note sur SecureRandom.

Note: Depending on the implementation, the generateSeed and nextBytes methods may block as entropy is being gathered, for example, if they need to read from /dev/random on various unix-like operating systems.

La MAUVAISE solution

Java permet de changer la source du random avec la propriété java.security.egd, si on prend le device/dev/urandom. Ce device à l’inverse de /dev/random est non bloquant. Donc sur la ligne de comande il suffirait d’ajouter cette option pour s’en sortir ?

Non surtout pas. Pourquoi ce n’est pas une bonne solution ? Le soucis ici est qu’on abaisse le niveau de sécurité de la JVM. Que ce soit pour l’établissement de connexion à Oracle ou une connexion HTTPS, la sécurité est compromise. Comme il n’y a plus assez d’entropie un attaquant peut connaitre ou determiner quel sera les prochains nombres qui sortiront de SecureRandom et donc potentiellement reconstruire les éléments cryptographiques tel que les clé privé, à partir de là l’attaquant à les mains libres.

Ce qu’il faut faire

Les OS alimente /dev/random généralement à partir de plusieurs sources, comme les sonde de température, l’activité du CPU, le trafic réseau, mais cela s’avère parfois pas assez efficace. L’idée est donc d’aider l’OS. Installer un démon qui ajoute de l’entropie au système. Il en existe plusieurs, celui que j’utilise est HAVEGED ; il utilise les états des composants internes des processeurs modernes pour augmenter significativement l’entropie du système. À noter il tourne dans le user space donc assez facile à installer.

Avec un Firewall

Suivant les infra et les besoins de légalité, il faut protéger les bases de données par un firewall. Le firewall va inspecter et protéger les équipements derrières mais il fait aussi de l’assainissement des connections TCP, il va couper les connections inactive au bout d’un certain temps.

Avec le pool de connection

En général quand on fait du connection pooling sur des connections longues (typiquement le rôle d’une Datasource) ça n’arrange pas les choses. Quand le pool donne une connection il ne sait pas forcement qu’elle à été fermé par un composant tierce (un firewall). Heureusement c’est un simple manque de configuration, il n’y a qu’à lui dire de vérifier les connections régulièrement par exemple tomcat-jdbc :

  • minEvictableIdleTimeMillis : The minimum amount of time an object may sit idle in the pool before it is eligible for eviction. The default value is 60000 (60 seconds).
  • timeBetweenEvictionRunsMillis : The number of milliseconds to sleep between runs of the idle connection validation/cleaner thread. This value should not be set under 1 second. It dictates how often we check for idle, abandoned connections, and how often we validate idle connections. The default value is 5000 (5 seconds).

A simple example of a datasource configuration to be adapted to your infrastructure settings.

Certains pool offrent une configuration plus fine et peut-être plus sûre comme HirakiCP. Mais c’est hors propos. Quoiqu’il en soit cette option n’est pas optimale car elle ne traite pas le problème à sa source.

TCP Keepalive

TCP, le protocole réseau sur lequel transite la connection oracle, fourni un mécanisme de keepalive. Ce mécanisme va envoyer un paquet sur la connection pour que les équipements de l’infrastructure réseau dont le fameux firewall maintiennent cette connection ouverte.

Avec Java ça se fait en passant la bonne option à l’ouverture de la socket SopcketOptions.SO_KEEPALIVE. La plupart des drivers, frameworks exposent une API pour activer cette option. Avec le driver Oracle cette option s’active donc aussi.

D’après la documentation Oracle il y a plusieurs moyens de configurer le driver JDBC pour travailler avec un firewall.

Dans le cas d’une configuration style TNSNAMES il faudra utiliser la chaine suivante ENABLE=BROKEN pour activer le keepalive. Par exemple :

Dans le cas d’une configuration sans TNSNAMES il faut passer la propriété oracle.net.keepAlive à true programmatiquement via les properties passée à l’API JDBC java.sql.DriverManager#getConnection(java.lang.String, java.util.Properties). Attention à la casse! Les propriété non documentées du driver sont disponible sur la javadoc de oracle.jdbc.OracleConnection

Dans tout les cas configurer le keepalive sur l’OS

Sur Linux par exemple, la documentation indique comment il faut faire. Pour vérifier qu’il correspondent :

Ces paramètres disent la pile TCP enverra la première sonde (premier paquet de keepalive) au bout de 40min, attendra 75 millisecondes avant de renvoyer une sonde dans la limite de 6 essais. Si aucun ACK n’est reçu alors la connection est reconnue par l’OS comme fermée.

Quoiqu’il en soit il faut régler ces paramètres en accord avec les réglages des équipement réseau.

À noter que la documention indique bien que le keepalive est un comportement à activer volontairement, d’ou l’option SopcketOptions.SO_KEEPALIVE dans la JVM.

Remember that keepalive support, even if configured in the kernel, is not the default behavior in Linux. Programs must request keepalive control for their sockets using the setsockopt interface.

Générer le script DDL programmatiquement avec Hibernate 4.x

07/08/2015 architecture, code, tips No comments , , ,

Si par hasard votre base donnée est gérée par un véritable DBA, donc avec des scripts SQL. Mais que vous utilisez hibernate pour mapper les tables avec une configuration non triviale, modules bien découpés, package annotés, etc…. Les utilitaires comme hibernate4-maven-plugin ne suffisent plus.

Voici un petit exemple code qui utilise le SchemaExporter de hibernate. Le code est bien sûr à adapter à la structure du code de l’application.

Le principe est de passer soit même les classes annotées ET les package annotés (typiquement par @TypeDef dans le package-info.java). Pour plus de commodité ce code utilise le framework Reflections pour scanner les classes annotées par les annotations JPA @Entity et @MappedSuperClass. Par défaut le script génère les drop statements, mais ce comportement peut se changer à travers les options de SchemaExport.

gist : https://gist.github.com/bric3/370654ecad0eb81aca22

Note pour plus tard: Problème avec jVisualVM sur OSX

10/10/2012 tips No comments , , , , , , , , , ,

Au cour d’un petit development, j’ai remarqué que mon process ne se terminait pas, une fois l’exécution de mon code terminé. Il devait y avoir soit une thread qui tournait encore, soit un deadlock quelque part, j’optais plus pour la seconde option.

Du coup je lance jvisualvm depuis mon terminal (celui du JDK7 update 7). Là j’ai la liste des process java qui tournent malheureusement quand je choisi d’investiguer ce process, jvisualvm me rapporte sur le terminal :

L’onglet du process s’ouvre bien dans jvisualvm mais impossible monitorer les threads ni faire de heap dump (au cas ou ça m’intéresserai), d’ailleurs ces sous-onglets ne sont même pas affiché.

La solution: passer avant au process java qu’il faut monitorer les paramètres suivants (en fonction des besoins)

  • -Xverify:none : Désactive la vérification du bytecode dans la JVM. De base la JVM s’assure que le bytecode vérifie certaines règles. Bref il faut activer ce flag si vous voulez faire des thread dump ou des heap dump. Il s’agit probablement d’un bug du JDK7 ou de jVisualVM sur OSX.
  • -Xshare:off : Comme son nom l’indique il s’agit de partager de la mémoire, dans les faits ça se traduit par le partage des classes déjà chargé. Sur mac cette option est active par défaut. A priori cette option pose problème pour l’attachement à un process Java, du coup en isolant la mémoire du process on peut s’en sortir.
  • -Dcom.sun.management.jmxremote : Active l’export des MBean de la JVM, si vous voulez les monitorer

On dirait une réapparition dans le JDK7u7 d’un bug a priori déjà clos dans le JDK6 (pour OSX). A noter que les outils en ligne de commade tel que jmap peuvent aussi être affectés.

Bien entendu si j’ai loupé un truc je suis tout ouïe.

Référence : http://java.net/jira/browse/VISUALVM-326

Caliper me : Ou pourquoi les microbenchmarks aident !

29/08/2012 code, design, performance 6 comments , , , , , , , , ,

Contexte

Dans les news récemment

  • Guava 13.0 réduit la consommation en mémoire de plusieurs structures [source]
  • J’ai passé des tests d’algorithmie [source]

Premier point, on sait que Google est attentif sur les performances de ses librairies. Sur le deuxième point, ben j’ai finalement loupé un des exercices “timeboxés”, je n’ai pas eu le temps de le finir a temps, du coup le code soumis était 100 % foireux. Mais bon ce n’est pas le sujet du billet, ce qui est important c’est que j’ai fini après cet algo, puis je me suis rendu compte que celui-ci n’était pas optimal, il ressemblait à un algo en O(n2) O(n log n) (Merci Sam pour cette correction). Du coup j’ai repris le papier et le crayon, et je me suis rendu compte que je pouvais utiliser une technique similaire à celle que j’ai utilisé sur le premier algo du test (comment n’ai-je pas pu y penser à ce moment d’ailleurs ?).

De mémoire l’algo porte grosso modo sur le comptage de paires d’entier distante d’un nombre K dans un tableau A.

Ma première version :

Alors pourquoi je pense que cet algo n’est pas optimal : simplement du fait des boucles inbriquée, on dirait du O(n2) O(n log n) (voir ici pourquoi). Mais quand on parle de la performance ou de la complexité d’un algorithme il ne faut prendre uniquement compte de l’invariant mais aussi du jeu de données : quelle taille ? quelle distribution ? quel type de données ?

En effet un algorithme pour être efficace doit être adapté aux jeux de données qu’il aura à traiter et à l’usage qu’on en a ; peut-être à travers des paramètres ou des structures différentes, typiquement un des constructeur d’une HashMap prend des paramètres comme le facteur de charge et la taille initiale, on pourra choisir une TreeMap au lieu d’une HashMap si la recherche est un cas d’utilisation de la structure de donnée.

Bref du coup voilà à quoi ressemble la nouvelle version de cet algo :

Donc ici l’idée c’est de préparer dans un premier temps un dictionnaire  inversé basé sur un des entier et la distance demandée, en incrémentant pour chaque occurence. Ici une seule boucle for, car on parcours en entier le tableau. Dans un second temps on cherche les entiers qui correspondent effectivement à l’entrée de ce dictionnaire, et si oui on incrémente le compteur de paires. Là aussi une seule boucle sur le tableau donc O(n). Sachant qu’une HashMap a souvant une complexité de O(1) pour l’insertion et la recherche, a vue de nez l’algo est plutot pas mal.

Bon mais dans la réalité ca donne quoi, en effet comme Kirk Pepperdine et bien d’autres disaient : Measure ! Don’t guess !

Caliper me voilà !

Caliper est un outil codé par des personnes de chez Google, il est notamment utilisé par l’équipe en charge de Guava. On peut d’ailleurs voir dans les sources de Guava les benchmarks ici par exemple.

Avec un projet “mavenisé” on récupère la dernière version de caliper, la version 0.5-rc1 aujourd’hui.

Pour écrire un benchmark caliper il suffit d’étendre la classe SimpleBenchmark, puis d’écrire des méthodes public int avec le préfixe times et un paramètre répétition utilisé dans une boucle for. Pour passer des paramètres particuliers au benchmark on utilisera un ou des champs annoté(s) par @Param.

Enfin comme Caliper lance une nouvelle VM, fait quelques travaux pour chauffer la VM (warmup), etc, il faut pour l’instant lancer ces tests avec une commande manuelle :

La ligne de commande pourra varier suivant les besoins ; on peut notamment se rendre sur leur site pour y voir les options (le lien wiki est à ce jour en retard par rapport au code) à passer au Runner Caliper. Malgré la jeunesse du framework sa documentation parfois spartiate, le projet a de réelles forces et s’avère de plus en plus populaire dans le domaine. Bien que le développement de ce projet avance lentement, ce projet est aujourd’hui maintenu par des membres de l’équipe Guava.

Donc le benchmark que j’ai mis en place :

Dans le temps

Voilà il faut maintenant lancer le benchmark en ligne de commande. Et voici une partie de la sortie standard :

Donc en fait Caliper créé une matrice multi-dimensionnelle des différents paramètres et pour chaque coordonnée dans cette matrice lance le test, bref un Scénario.

On voit dans les mesures faites par Caliper le temps pris par chaque méthode, l’écart type, et le nombre d’essai. Enfin dans une deuxième partie Caliper donne un synopsis des différents run et en particulier une colonne très intéressante ‘linear time‘.

En observant le temps pris en fonction du nombre d’éléments pour chaque algo, on s’aperçoit que le temps pris par le premier algo augmente en effet par rapport au deuxième algo d’un facteur 5 qui augmente avec la taille du tableau. Bref on est loin d’un temps linéaire aka O(n).

Ce qui est aussi intéressant, c’est que le premier algo est plus efficace tant que le nombre d’élément dans le tableau d’entrée est inférieur à 100. Alors que la deuxième  qui utilise une structure plus élaboré ne montre des signes avantageux qu’à partir d’une centaine d’éléments. Ca me rappelle étrangement l’électronique ou les comportements des capacités et inductances changeant de nature lorsqu’on passe en haute fréquence.

Dans l’espace

Alors pour faire les mesures des allocations, on peut aussi utiliser caliper, mais à l’heure de l’écriture de ce blog, il faut faire quelques petites choses en plus.

  1. Caliper 0.5 RC1 vient avec le jar java-allocation-instrumenter-2.0.jar qui est sensé servir d’agent, cependant ce jar n’a pas été généré correctement pour servir d’agent. En fait il faut télécharger le jar allocation.jar de ce projet : http://code.google.com/p/java-allocation-instrumenter/ daté du 1 er février 2012.
  2. Avant de lancer le Runner en ligne de commande il faut ajouter la variable d’environnement ALLOCATION_JAR
  3. Enfin il est possible de lancer le même benchmark avec des tests sur la mémoire :

 

A noter : Ne pas renommer allocation.jar en autre chose, sans ça vous n’aurez pas d’instrumentation !

Ce qui donne le résultat suivant, quasiment la même chose, mais avec les infos sur les allocations mémoire.

C’est effectivement une information utile, la première version de l’algo, ne fait en fait qu’une seule allocation de 16B (donc en fait un seul objet), c’est à dire peanuts, on est dans du O(1) en complexité spatiale. La deuxième qui est notamment basée sur une HashMap alloue nettement plus d’objets, mais est définitivement plus rapide, on a on ici une complexité spatiale de O(n).

Comme quoi il y a potentiellement des compromis à faire dans le choix d’un algo, la rapidité ou la faible consommation mémoire peuvent venir avec un coût dans une autre dimension.

Pour conclure

  • Premier point, il faut absolument être au point pour des tests d’embauche plus sur le sujet, même si je trouve limité ces tests dans leur capacité à identifier ou filtrer les bons développeurs (l’algorithmie n’est pas certainement pas le seul critère d’un individu doué), c’est toujours bien de pouvoir les reéussir !
  • Caliper offre un outillage plutôt facile d’utilisation pour faire des microbenchmark, dans la limite de validité d’un microbenchmark, il y a plein de mise en garde sur le sujet, sur le site de Caliper [1][2], Cliff Click en a parlé aussi à JavaOne [3][4].
  • Quand on écrit du code c’est une bonne idée de penser à la complexité temporelle et spatiale, dont la notation pour les deux est le grand O. Caliper pourrait d’ailleurs se voir ajouter le moyen de mesurer la consommation mémoire (en lien avec la complexité spatiale). Évidement ce que je dis ne veut pas dire optimiser prématurément, mais juste de réfléchir à quel type de performance on peut s’attendre pour telle ou telle partie du code, et éventuellement de porter plus tard un effort spécifique.

A noter que Caliper offre d’autres possibilités de mesurer la performance à travers une méthode annotée par @ArbitraryMeasurement.

Script d’installation du JDK 5 sur MacOSX Lion et Mountain Lion (Mis à jour)

30/07/2012 code 9 comments , , , , ,

MAJ 29/07/2012: Le script a été mis à jour pour fonctionner avec Mac OS X Mountain Lion. Le script a été mis à jour pour télécharger lui même le DMG chez Apple, en bref il n’y a plus qu’à commencer à l’étape 2.

JDK 5 installation on Mountain Lion


Original 22/08/2011 : Avec l’arrivée de Lion, Apple change les choses avec Java. Heureusement s’il s’agit d’une mise à jour depuis Snow Leopard, vous ne perdrez pas votre runtime JDK 6, en revanche si vous faites une installation clean, et bien il faudra télécharger le runtime ici :

http://support.apple.com/kb/DL1421

Bon ça fait une chose de plus pour nous ennuyer, mais bon comme toujours pour ceux qui veulent bosser sur un JDK 1.5, il vous faudra tricher un peu plus, il n’y a pas de mise à jour standard ou facile pour installer le JDK 5 sur 10.7.

Certains ont trouvé l’astuce en téléchargeant la mise à jour Java pour Mac OS X 10.5, et avec quelques outils et commandes dans le terminal. Cela dit le processus est un poil long. Du coup je me suis codé un petit script pour automatiser ces étapes. Pour l’instant le script repose sur un téléchargement manuel de cette mise à jour.

  1. En premier on télécharge la mise à jour du JDK5 ici :

    http://support.apple.com/kb/DL1359

  2. Ensuite dans le même répertoire on y téléchargera le script
  3. Dans un terminal dans le dossier du téléchargement
    [plain]chmod +x install_jdk5_lion.sh[/plain]
  4. Il faut être root, attention quand même, le script fonctionne sur les environnements Lion que j’ai pu testé, mais il peut très bien casser votre système, déclencher un tempête ou je ne sais quoi encore… je ne garantis rien.
    [plain]sudo -s[/plain]
  5. Bref il se lance comme ça :
    [plain]./install_jdk5_lion.sh[/plain]
  6. Si tout se passe bien alors, les préférences Java de Mac s’ouvriront en listant le JDK 5.
  7. exit

En images, ça donne :

Evidement si vous repérez une coquille, je suis à l’écoute. Bonne soirée 🙂

EDIT 29/08/2011: Tant qu’à faire autant montrer comment avoir plusieurs JDK dans IntelliJ sous macosx.

  1. Donc une fois le projet ouvert, il faut aller dans les préférences du projet (Project Settings).
    IntelliJ Project Setting
  2. Ensuite ajouter le JSDK.
    Add New JSDK
  3. Puis sélectionner dans l’explorateur le dossier /System/Library/Java/JavaVirtualMachines/1.5.0/Contents/Home
    Choose JDK 5 Home
  4. Hop, c’est fini, dans IntelliJ vous avez le JDK 5

Idée originale : Zend Studio 5.x for OS X Lion (Java SE 6)

Sources :

Optimization WordPress Plugins & Solutions by W3 EDGE