Performance des RPS ovh

Je viens de m’offrir un serveur privé chez OVH, un RPS. Cela semble de jolies machine pour un cout très modeste (25€ / mois environ). Seul hic, la perf du disque qui est mutualisé dans un NAS et ne garantit que 1 Mo/s dans la version que j’ai. Après c’est plus cher. D’où la question … à quoi correspondent vraiment ses 1Mo. Du coup je lui ait appliqué mes tests habituels, dont je vous livre les résultats.

  • hdparm -t /dev/sda1 : donne 2.8Mo /s ce qui est plutôt bon puisque 1Mo/s sont promis
  • seeker donne 11 seeks/s avec un temps d’accès de 86.46ms. On a ici un debit de 44 Ko / s
  • hdparm -t /dev/sda1 : donne 523Mo /s
  • bonnie++ : write (seq char / bloc / rewrite ) – 11M – 11M – 1.8M || read (seq char / bloc ) – 2M – 2M

Les premiers éléments de performance valent grosso modo ceux d’une clef USB 1.0, autant dire que ce n’est pas l’extase. Les performance obtenues avec Bonnie sont de l’ordre du disque USB ou disque reseau NFS sur 100Mbs. Grosso-modo 3 fois moindre qu’un disque interne.
En tout cas, pour mysql, je pense qu’un gros cache est nécessaire ! A suivre avec des tests plus fonctionnels et moins technique ; a noter aussi que la QoS mise en place sur les I/O offre une certaine souplesse puisque les mesures faites ne sont pas systématiquement bloquées à 1Mo/s et tant mieux !

Coté performance calcul le résultat de lmbench est le suivant:

Process | null call / null IO / open-close / slct TCP / fork / exec prog / sh prog | 0,09 / 0,35 / 3.18 / 11.8 / 191 / 654 / 2649
Integer | calculs bits / addition / mult/ div / modulo | 0,48 / 0,48 / 0.19 / 20.5 / 19.6
Float | calculs addition / mult/ div / bogo | 1.9 / 1.9 / 8.4 / 7.63
Latency | context switch / AF UNIX / UDP / TCP / TCP-CON | 2.3 / 7.79 / 20.4 / 25.2 / 80

Ok … c’est barbare, mais il faut le comparer à d’autres tests fait. Globalement, je dirai que la machine est correct, sans plus, pas tres bonne en réseau ni en addition par rapport à mon epia 1.8G, mon P4 ou mon athlon 1.5G ; certe l’outil de bench n’utilise pas le dual core. Par contre la machine est performante en floatant et en mult / div entiere. Bref, correct et suffisant pour mon usage.
voir ici pour les autres tests faits.

Mon pense bête Ubuntu

Petite liste de commandes à ne pas oublier lorsque l’on part d’un RPS vierge. (A partir d’un UBUNTU serveur) … snif, ils n’ont pas de suse.

  • apt-get update
  • apt-get install synaptic
  • apt-get install update-manager
  • dans synaptic, ajouter les repo third party puis installer tomcat5 et java (a voir)
  • apt-get install apache2 mysql-server php5 libapache2-mod-php5 php5-mysql
  • mettre a jour les paquets en lançant update-manager -c

Création de clef usb bootable

Un petit tool utile pour créer des clefs USB qui soient bootable, avec une ISO par exemple : UnetBooin qui se télécharge ici. L’outil existe pour Linux et Windows. Au passage, si vous souhaitez créer une clef avec une distribution de Linux, il ira la chercher tout seul comme un grand.

Quelques notions Oracle

En ce moment, je bricole pas mal avec Oracle pour chercher pourquoi certaines de nos applications rament … D’où l’envie de mettre quelques informations sur les principaux point à regarder. Cet article n’a pas de vocation exhaustive mais ce sont plutôt quelques notes sur un coin de table…

Oracle est une base possédant un énorme moteur d’optimisation de requêtes, sans doute très fort pour le traitement massif de données, cependant, le moindre grain de sable transforme immédiatement votre Ferrarie en une 2CV. Au premier rang des grains de sable se trouvent les statistiques. Il s’agit d’une donnée Oracle indiquant le nombre de lignes que la table doit contenir. Fonction de ce nombre, l’optimiseur choisira une methode de recherche des données dans une table plutôt qu’une autre. Il pourra utiliser des INDEX ou des CLEFS ou choisir de faire un FULL SCAN (essayer les lignes une à une). S’il se trompe… c’est la cata. Le premier point est donc de vérifier ces stats en consultant le nombre de ligne qu’ORACLE pense avoir dans “all_tables” et le comparer aux nombre de lignes reellement dans la table count(*).
Ceci étant dit, je n’ai pas dit grand chose car il est avant nécessaire d’identifier quelles sont les tables concernées, ceci peut se faire de 2 façons, la première, lorsque le temps de réponse est catastrophique, consiste à regarder les session actives et visualiser le sql en cours de traitement. Ceci se fait facilement avec des outils comme TOAD ou DbVisualizer.
La requête peut aussi être identifiée à l’aide du stat_pack oracle. Cet outil permet de mémoriser l’état de la SGA avant et après un traitement puis de faire une comparaison de entre les deux images. Cet outil permet alors de savoir quelles sont les requêtes qui ont consommées le plus de temps, quelle est l’utilisation de la SGA ou de la PGA … Bref … une fois la requête identifiée, il est possible de demander à Oracle un Explain plan qui indiquera quels est la complexité de la requête et par quelles méthode les données sont recherchées (full scan, index…)
Il est alors possible d’identifier les problèmes. Il faut identifier s’il existe un index qui pourrait être utilisé et qui ne l’est pas par exemple ou s’il faudrait créer un nouvel index. Dans le premier cas, il est possible que les stats ne soient pas bonnes car si oracle préfère un fullscan à un index, c’est sans doute qu’il croit que la table ne contient que très peu de lignes.
Si tout semble normal de ce point de vue, il arrive que les index aient besoin d’être rebuildés : il se peu que les arbre binaires associés soient déséquilibrés, que le nombre de niveau devienne trop grand et que son utilisation ne soit pas efficace. Un rebuild peut résoudre cela. Il est aussi possible, à l’aide de Hints de forcer Oracle à utiliser un index donné. Mais ceci n’est valable que lorsque vous avez accès aux sources de l’application.
On peut enfin penser à faire un reset de la High Water Mark sur une table donnée si vraiment on constate des soucis sur cette table alors que tout le reste est ok.

Avant de vraiment s’attaquer à tout cela, il peut être utile de jeter un oeil aux estimations que donne le stat pack sur la taille des SGA, PGA et Shared Pool car des espaces mémoire trop réduits vont fortement pénaliser Oracle qui devra faire trop d’accès aux disques. Dans le même esprit, il faut jeter un oeil aux taille des redo-log qui peuvent conduire à des fréquences d’I/O trop élevées dans les système de type batch.

Bon courage avec toutes ces notions et idées un peu en vrac … il y a ici surtout des mots clefs pour chercher ensuite sur google. A l’occasion, je mettrai des information plus opérationnelles, promis !

Recalcul d’index dans une base Oracle

Deux petits scripts permettant le recalcul des index d’une base oracle lorsque ceux-ci ont l’air louche … Les scripts sont à passer l’un après l’autre sur la base

--- AnalyseIndex.sql
set pages 9999;
set heading off;
set feedback off;
set echo off;
set linesize 255;

spool step1.sql;
select 'drop table system.temp_stats_paul;' from dual;
select 'create table system.temp_stats_paul as select name, most_repeated_key, distinct_keys, del_lf_rows, height, blks_gets_per_access, lf_rows from index_stats;' from dual;

select 'analyze index '||owner||'.'||index_name||' validate structure;',
'insert into system.temp_stats_paul ( select name, most_repeated_key, distinct_keys, del_lf_rows, height, blks_gets_per_access, lf_rows from index_stats where height > 3 or ( 100 * del_lf_rows / (lf_rows+1) ) > 20 or BLKS_GETS_PER_ACCESS > 5 );'
from dba_indexes
where
owner not in ('SYS','SYSTEM');

spool off;
set heading on;
set feedback on;
set echo on;

@step1.sql
quit
--- RebuildIndex.sql
set pages 9999;
set heading off;
set feedback off;
set echo off;
set linesize 255;

spool step2.sql;

select 'alter index '||owner||'.'||name||' rebuild tablespace '||tablespace_name||';'
from system.temp_stats_paul, dba_indexes
where system.temp_stats_paul.name = dba_indexes.index_name;

spool off;

drop table system.temp_stats_paul;

set heading on;
set feedback on;
set echo on;

@step2.sql
quit

Tutoriel Ajax – Création d’un diaporama

(‘Article rédigé par un groupe d’étudiants d’IUT dans le cadre d’un projet tutoré)

Dans cet article, je vais vous montrer comment réaliser un diaporama en Ajax. Pour cela je vais utiliser trois langages: le HTML, du JavaScript ainsi que du PHP.
Le code du diaporama est scindé en 3 fichier: galerie.html, galerie.js et galerie.php.
Le premier est la page web contenant la mise en page avec les différents évènements possibles tels que le clic sur la flèche précédente ou suivante.
Voici son code avec des explications:
—————————————

<!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>
<html>
<head>
<meta content=”text/html; charset=ISO-8859-1″
http-equiv=”content-type”/>
<!– On inclut notre future fichier JavaScript –>
<script type=”text/javascript” src=”/ajax/galerie.js”></script>
<title>galerie</title>
</head>

<body style=”background-color: rgb(170, 0, 0);”>
<h1 style=”text-align: center;”>GALERIE D’ IMAGES</h1>
<hr />
<!– Voilà l’endroit où le résultat sera affiché, reconnu dans notre futur fichier JavaScript par son id. Pour le moment, on affiche rien. –>
<div style=”background:black; text-align: center” >
<br /><br />
<img id=”i_pred” src=”/ajax/pred.png” onClick=”javascript:galerie=pred()” style=”cursor:pointer”/>
———-
<img id=”i_suiv” src=”/ajax/suiv.png” onClick=”javascript:galerie=suiv();” style=”cursor:pointer”/>
<br />
<img id=”image” src=”/ajax/start.jpg”/>
<br /><br />
</div>
<hr />
<script type=”text/javascript” >galerie=suiv();</script>
</body>
</html>

—————————————

Ce sont les fonctions pred et suiv, appelées une fois qu’une flèche a été cliquée, qui modifieront l’image. A la fin du body, on appel la fonction suiv pour initialiser l’image.

Jetons un coup d’oeil dans le fichier JavaScript:

—————————————

/*
Fonction qui crée un objet XHR.
Cette fonction initialisera la valeur dans la variable globale “requete”
*/

var requete = null; /* On crée une variable qui contiendra l’objet XHR */
var galerie =-1;

function creerRequete() {
try {
requete = new XMLHttpRequest(); /* On essaye de créer un objet XmlHTTPRequest */
} catch (microsoft) {
/* Si cela ne marche pas, on a peut-être affaire à un navigateur de Microsoft. On tente alors de créer un objet ActiveX */
try {
requete = new ActiveXObject(‘Msxml2.XMLHTTP’);
} catch(autremicrosoft) {
/* Autre méthode si la première n’a pas marché */
try {
requete = new ActiveXObject(‘Microsoft.XMLHTTP’);
} catch(echec) {
/* Si aucune méthode ne fonctionne, on laisse l’objet vide*/
requete = null;
}
}
}
if(requete == null) {
alert(‘Votre navigateur ne semble pas supporter les object XMLHttpRequest.’);
}
}

function pred()
{
creerRequete();
galerie –;
var url = ‘galerie.php?image=’+galerie;
requete.open(‘GET’, url, true);
requete.onreadystatechange = function() {
if(requete.readyState == 4) {
if(requete.status == 200) {
if(requete.responseText!=””)
{
document.getElementById(‘image’).src=”/ajax/img/” + requete.responseText;
}
}
}
};
requete.send(null);
return galerie;
}

function suiv()
{
creerRequete();
galerie ++;
var url = ‘galerie.php?image=’+galerie;
requete.open(‘GET’, url, true);
requete.onreadystatechange = function() {
if(requete.readyState == 4) {
if(requete.status == 200) {
if(requete.responseText!=””)
{
document.getElementById(‘image’).src=”/ajax/img/” + requete.responseText;
}
}
}
};
requete.send(null);
return galerie;
}
—————————————

On initialise la variable galerie. Elle servira d’index.
Comme vous pouvez le voir, nos fonctions pred et suiv ont un code similaire.
Chacune effectue la création de l’objet XHR en appelant la fonction creerRequete.
Puis elles incrémentent ou décrémentent la variable relative à l’identifiant de l’image.
On construit ensuite l’URL, les arguments seront passés par la méthode GET.
On initialise la fonction de renvoi d’information.
On teste si on est au début du diaporama (galerie = 0) ou si on est a la fin (la requête retourne rien).
Si l’on est dans le cas optimal, on affiche la nouvelle image.
On retourne la variable galerie à la page HTML.
Pour comprendre la totalité du diaporama, il faut ensuite regarder le code qui sera exécuté sur le serveur : galerie.php

—————————————

<?php
/*
On vérifie que le paramètre GET est bien présent
*/
function isnotpoint($var)
{
return $var!=”.” && $var !=’..’;
}

if(isset($_GET[‘image’]))
{
$image = $_GET[‘image’];
$image = abs($image);
$tableau = scandir(‘./img/’);
$tableau = array_filter($tableau,”isnotpoint”);
$nbimage = count ($tableau);
$image = ($image%$nbimage)+2;

echo $tableau[$image];

}
else
echo “Erreur GET”;
?>

—————————————

L’algorithme de ce code est le suivant:
On vérifie que le paramètre image est présent. On prend la valeur absolue de notre paramètre, ceci est utile lorsque l’index est inférieur à zéro. Si c’est le cas on utilise la fonction scandir et on stocke le résultat dans la variable tableau. La fonction scandir est très utile dans ce cas, en effet elle va retourner chacun des fichiers du dossier mais aussi un “.” et “..”, c’est pour cela que l’on utilise la fonction array_filter qui va les enlever du tableau. La fonction count permet de retourner le nombre d’éléments du tableau. On effectue un modulo de l’index avec ce nombre, et on ajoute 2. En effet, la fonction array_filter ne créer pas un nouveau tableau, mais efface juste les éléments correspondant à la recherche, C’est pour cela qu’il faut penser que les deux premiers éléments du tableau sont vides et ajouter 2. On retourne par la suite l’élément voulu.

Voilà, ce tutorial est terminé, vous pouvez à présent créer un diaporama utilisant Ajax pour votre site web.

 

Tutoriel Ajax – Infobulle

(Article rédigé par un groupe d’étudiant d’IUT dans le cadre d’un projet tutoré)

Voici un tutorial qui permet lorsque l’utilisateur passe la souris au dessus d’un mot définie a préalable, d’afficher dans une bulle un texte, une image ou ce que l’on veut.

On peut ainsi utiliser ce principe pour donner la signification de certains mots, ou même pour un lien afficher dans la bulle la première phrase de la page cible du lien.
Dans cet exemple les mots et leur significations ce trouvent dans le fichier xml.

Voici le fichier html :

<html>

<head>

<link rel=”stylesheet” type=”text/css” href=”/ajax/bulle.css” media=”all” />

<script type=”text/javascript” src=”/ajax/bulles.js”></script>

</head>

<body>

<div id=”curseur”></div>

Mot :<br />

Connaissez vous l'<span onmouseover=”javascript:affbulle(this)” onmouseout=”javascript:cache()”>ajax</span> ?<br />

C’est un concept <span onmouseover=”javascript:affbulle(this)” onmouseout=”javascript:cache()”>informatique</span> !<br />

Retour à la ligne

</body>

</html>

Explication : On peut remarquer les balises <span>, ce sont elles qui vont nous servir pour récupérer le mot associé à la définition ;

Deux fonctions JavaScript vont être appelés :

-affbulle va servir pour charger la définition du mot et afficher la bulle lorsque le mot est survolé.

-cache va comme son nom l’indique masquer la bulle lorsque la souris ne se trouve plus sur le mot concerné.

On peut se demander a quoi va servir la balise <div>, c’est tout simplement la déclaration de la bulle.

 

Voici le fichier css associé :

.infobulle{

position: absolute;

visibility : hidden;

border: 1px solid Black;

padding: 10px;

font-family: Verdana, Arial;

font-size: 10px;

background-color: #FFFFCC;

}

 

.lienbulle{

color: #0000ff;

cursor: help;

text-decoration: underline;

}

 

Rien de particulier, infobulle concerne la bulle et lienbulle concerne le mot en question.

 

Voici maintenant le fichier xml :

 

<?xml version=”1.0″ ?>

<root>

<ajax>Texte correspondant a l’Ajax</ajax>

<informatique>Texte correspondant a l’informatique</informatique>

</root>

 

Il suffit de créer la balise <nom> (nom étant le mot qui va être décrit), puis entre cette balise ouvrante et la balise fermante, on placera la description qui apparaîtra dans la bulle

 

Attaquons nous maintenant au fichier JavaScript :

 

/*

Fonction qui crée un objet XHR.

Cette fonction initialisera la valeur dans la variable globale “requete”

*/

 

var requete = null; /* On crée une variable qui contiendra l’objet XHR */

 

function creerRequete() {

try {

requete = new XMLHttpRequest(); /* On essaye de créer un objet XmlHTTPRequest */

} catch (microsoft) {

/* Si cela ne marche pas, on a peut-être affaire à un navigateur de Microsoft. On tente alors de créer un objet ActiveX */

try {

requete = new ActiveXObject(‘Msxml2.XMLHTTP’);

} catch(autremicrosoft) {

/* Autre méthode si la première n’a pas marché */

try {

requete = new ActiveXObject(‘Microsoft.XMLHTTP’);

} catch(echec) {

/* Si aucune méthode ne fonctionne, on laisse l’objet vide*/

requete = null;

}

}

}

if(requete == null) {

alert(‘Votre navigateur ne semble pas supporter les objets XMLHttpRequest.’);

}

}

 

Pour l’instant, nous avons le même code que pour l’implémentation.

 

function GetId(id)

{

return document.getElementById(id);

}

var i=false; // La variable i nous dit si la bulle est visible ou non

 

function move(e) {

if(i) { // Si la bulle est visible, on calcul en temps reel sa position idéal

if (navigator.appName!=”Microsoft Internet Explorer”) { // Si on est pas sous IE

GetId(“curseur”).style.left=e.pageX + 5+”px”;

GetId(“curseur”).style.top=e.pageY + 10+”px”;

}

else {

if(document.documentElement.clientWidth>0) {

GetId(“curseur”).style.left=20+event.x+document.documentElement.scrollLeft+”px”;

GetId(“curseur”).style.top=10+event.y+document.documentElement.scrollTop+”px”;

} else {

GetId(“curseur”).style.left=20+event.x+document.body.scrollLeft+”px”;

GetId(“curseur”).style.top=10+event.y+document.body.scrollTop+”px”;

}

}

}

}

 

La fonction qui précède ce charge de la position de la bulle par rapport au curseur

 

function montre() {

if(i==false) {

GetId(“curseur”).style.visibility=”visible”; // Si elle est cachée (la verification n’est qu’une sécurité) on la rend visible.

i=true;

}

}

 

La fonction montre() va simplement rendre visible la bulle.

 

function cache() {

if(i==true) {

GetId(“curseur”).style.visibility=”hidden”; // Si la bulle est visible on la cache

i=false;

}

}

 

A l’inverse cache() va masquer la bulle.

 

function affbulle(src) {

/* On crée notre super objet XHR global */

creerRequete();

 

/* On édite les propriété de l’objet : type de paramètre, url (avec paramètres) et une option autorisant une réponse du serveur */

requete.open(‘GET’, ‘test.xml’, true);

 

/* On initialise la fonction de renvoi d’information */

requete.onreadystatechange = function() {

if(requete.readyState == 4) {

if(requete.status == 200) {

 

/* On récupère le contenu de notre fichier */

var xml = requete.responseXML;

document.getElementById(‘curseur’).innerHTML = xml.getElementsByTagName(src.innerHTML).item(0).firstChild.data;//c’est ici que l’on charge la définition du mot

 

}

}

}

/* C’est partit ! On envoi la requête XHR au serveur */

requete.send(null);

montre();

}

document.onmousemove=move; // dés que la souris bouge, on appelle la fonction move pour mettre à jour la position de la bulle.

 

Cette fonction va donc accéder au fichier xml et charger la définition du mot et la retourner au ‘curseur’ pour qu’il affiche le tout dans la bulle.

Le ‘src.innerHTML’ correspond au mot qui se trouve dans le fichier html entre les balises span, ce mot doit être identique a la balise du fichier xml contenant la définition, il servira par conséquent d’identifiant.

Reparation Raid hardware sur carte nVidia

Comme évoqué dans un autre post, j’ai eu l’occasion ce jour de remonter un raid mirroring dont l’un des disque a rendu l’âme.
J’espérai cette manip transparente avec l’outil du bios, j’imaginais celui-ci re-clonant les disques … et bien non. sachez, amis LINUXIENS que dans une telle situation, il faudra installer un Windows pour lancer l’utilitaire nVidia vous permettant de procéder à la reconstruction. Ce n’est pas très long à condition d’avoir un disque en rab et les install du dit OS …
Bref, pour ma part, la prochaine réinstalle se fera avec un soft RAID Linux dont l’usage est finalement plus simple. Dommage car à la création ce mirroring nVidia etait très pratique..;