Attention ceci est mon brouillon avant de faire une belle documentation sur Docker (il y a à boire et à manger).
On va dire que ce pas va être un pas de coté. Mon but va être d’améliorer le server4 pour en faire un server5 (source server5.c). Mais je vais aussi faire un programme de stress : client_stress.c afin de bien vérifier tout le fonctionnement.
Voici donc les amélioration sur server5.c :
- Ajout des logs dans syslog (même si je suis sur un échec sur la redirection des logs : voir le précédent post).
- Ajout d’une commande TIME pour indiquer le temps en milliseconde depuis l’acceptation.
- Ajout d’une commande CLIENT pour indiquer l’IP du client.
- Création d’une table dans Postgresql au lancement du serveur.
- Ajout d’une commande pour faire l’insertion des performances dans Postresql : DBINSERT.
Voici donc le source que je vous propose :
[root@localhost ~]# cat server5.c #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/wait.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/un.h> #include "libpq-fe.h" #include <syslog.h> #define MYPORT 80 #define BACKLOG 5 #define MAXCLIENTS 5 #define MAXDATASIZE 100 long getMicrotime () { struct timeval currentTime; gettimeofday (¤tTime, NULL); return currentTime.tv_sec * (int) 1e6 + currentTime.tv_usec; } int main (void) { int sockfd = -1, new_fd, numbytes, highest = 0, i; int clients[MAXCLIENTS]; long clients_t[MAXCLIENTS]; char clients_ip[MAXCLIENTS][MAXDATASIZE]; char buffer[MAXDATASIZE]; char localip[MAXDATASIZE]; struct sockaddr_in my_addr, their_addr; socklen_t sin_size; struct timeval tv; fd_set readfds; char conninfo[MAXDATASIZE]; PGconn *conn; PGresult *res; FILE *f; char line[100], *p, *c; const char *google_dns_server = "8.8.8.8"; int dns_port = 53; struct sockaddr_in serv; int sock = socket (AF_INET, SOCK_DGRAM, 0); setlogmask (LOG_UPTO (LOG_NOTICE)); openlog ("server5", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); f = fopen ("/proc/net/route", "r"); while (fgets (line, 100, f)) { p = strtok (line, " \t"); c = strtok (NULL, " \t"); if (p != NULL && c != NULL) { if (strcmp (c, "00000000") == 0) { printf ("Default interface is : %s \n", p); break; } } } if (sock < 0) { perror ("Socket error"); syslog (LOG_ERR, "Error on socket"); closelog (); } memset (&serv, 0, sizeof (serv)); serv.sin_family = AF_INET; serv.sin_addr.s_addr = inet_addr (google_dns_server); serv.sin_port = htons (dns_port); int err = connect (sock, (const struct sockaddr *) &serv, sizeof (serv)); struct sockaddr_in name; socklen_t namelen = sizeof (name); err = getsockname (sock, (struct sockaddr *) &name, &namelen); const char *p2 = inet_ntop (AF_INET, &name.sin_addr, localip, 100); if (p2 != NULL) { printf ("Local ip is : %s \n", localip); } else { printf ("Error number : %d . Error message : %s \n", errno, strerror (errno)); strcpy (localip, "Error"); } close (sock); printf ("POSTGRES2_PORT_5432_TCP_ADDR : %s \n", getenv ("POSTGRES2_PORT_5432_TCP_ADDR")); if (getenv ("POSTGRES2_PORT_5432_TCP_ADDR") == NULL) { sprintf (conninfo, "hostaddr=%s port=%s user=postgres password=%s", "127.0.0.1", "5432", "password"); syslog (LOG_NOTICE, "Local mode"); } else { sprintf (conninfo, "hostaddr=%s port=%s user=postgres password=%s", getenv ("POSTGRES2_PORT_5432_TCP_ADDR"), getenv ("POSTGRES2_PORT_5432_TCP_PORT"), getenv ("POSTGRES2_ENV_POSTGRES_PASSWORD")); syslog (LOG_NOTICE, "Docker mode"); } conn = PQconnectdb (conninfo); if (PQstatus (conn) != CONNECTION_OK) { fprintf (stderr, "Connection to database failed: %s \n", PQerrorMessage (conn)); } else { res = PQexec (conn, "select count(*) from STATISTIQUE;"); if (PQresultStatus (res) != PGRES_TUPLES_OK) { printf ("KO : Table STATISTIQUE \n"); PQclear (res); res = PQexec (conn, "CREATE TABLE STATISTIQUE ( ID serial primary key, CLIENT CHAR(20) NOT NULL, SERVER CHAR(20) NOT NULL, TEMPS_MILLI INT NOT NULL, TEMPS_CUR INT);"); if (PQresultStatus (res) != PGRES_COMMAND_OK) { printf ("KO : Table STATISTIQUE (CREATE) \n"); PQclear (res); } else { printf ("OK : Table STATISTIQUE (CREATE) \n"); PQclear (res); } } else { printf ("OK : Table STATISTIQUE \n"); PQclear (res); } } PQfinish (conn); syslog (LOG_NOTICE, "End of check of table"); if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1) { perror ("socket"); syslog (LOG_ERR, "Error on socket"); closelog (); exit (-1); } my_addr.sin_family = AF_INET; my_addr.sin_port = htons (MYPORT); my_addr.sin_addr.s_addr = INADDR_ANY; bzero (&(my_addr.sin_zero), 8); if (bind (sockfd, (struct sockaddr *) &my_addr, sizeof (struct sockaddr)) == -1) { perror ("bind"); syslog (LOG_ERR, "Error on bind"); closelog (); exit (-1); } if (listen (sockfd, BACKLOG) == -1) { perror ("listen"); syslog (LOG_ERR, "Error on listen"); closelog (); exit (-1); } bzero (clients, sizeof (clients)); highest = sockfd; while (1) { sin_size = sizeof (struct sockaddr_in); tv.tv_sec = 0; tv.tv_usec = 250000; FD_ZERO (&readfds); for (i = 0; i < MAXCLIENTS; i++) { if (clients[i] != 0) { FD_SET (clients[i], &readfds); } } FD_SET (sockfd, &readfds); if (select (highest + 1, &readfds, NULL, NULL, &tv) >= 0) { if (FD_ISSET (sockfd, &readfds)) { if ((new_fd = accept (sockfd, (struct sockaddr *) &their_addr, &sin_size)) == -1) { perror ("ACCEPT"); syslog (LOG_ERR, "Error on accept"); continue; } for (i = 0; i < MAXCLIENTS; i++) { if (clients[i] == 0) { clients[i] = new_fd; clients_t[i] = getMicrotime (); break; } } if (i != MAXCLIENTS) { if (new_fd > highest) { highest = clients[i]; } printf ("Connexion received from %s (slot %i) ", inet_ntoa (their_addr.sin_addr), i); strcpy (clients_ip[i], inet_ntoa (their_addr.sin_addr)); syslog (LOG_NOTICE, "Connexion received from %s (slot %i) ", inet_ntoa (their_addr.sin_addr), i); send (new_fd, "\nHELLO\n", 7, MSG_NOSIGNAL); } else { send (new_fd, "\nTOO MANY CLIENT\n", 17, MSG_NOSIGNAL); close (new_fd); } } for (i = 0; i < MAXCLIENTS; i++) { if (FD_ISSET (clients[i], &readfds)) { if ((numbytes = recv (clients[i], buffer, MAXDATASIZE, 0)) <= 0) { printf ("Connexion lost from slot %i", i); syslog (LOG_NOTICE, "Connexion lost from slot %i", i); close (clients[i]); clients[i] = 0; } else { buffer[numbytes] = '\0'; printf ("Received from slot %i : %s", i, buffer); syslog (LOG_NOTICE, "Received from slot %i : %s", i, buffer); if (strncmp (buffer, "POSTGRES", 6) == 0) { conn = PQconnectdb (conninfo); if (PQstatus (conn) != CONNECTION_OK) { fprintf (stderr, "Connection to database failed: %s", PQerrorMessage (conn)); send (new_fd, "\nDB KO\n", 7, MSG_NOSIGNAL); syslog (LOG_ALERT, "Connection to database failed: %s", PQerrorMessage (conn)); } else { send (new_fd, "\nDB OK\n", 7, MSG_NOSIGNAL); } PQfinish (conn); } if (strncmp (buffer, "DBINSERT", 6) == 0) { conn = PQconnectdb (conninfo); if (PQstatus (conn) != CONNECTION_OK) { fprintf (stderr, "Connection to database failed: %s", PQerrorMessage (conn)); send (new_fd, "\nDBINSERT KO (1)\n", 16, MSG_NOSIGNAL); syslog (LOG_ALERT, "Connection to database failed: %s", PQerrorMessage (conn)); } else { char query_string[256]; send (new_fd, "\nDBINSERT OK\n", 7, MSG_NOSIGNAL); sprintf (query_string, "INSERT INTO STATISTIQUE (CLIENT,SERVER,TEMPS_MILLI,TEMPS_CUR) VALUES ('%s','%s','%ld','%ld')", clients_ip[i], localip, getMicrotime () - clients_t[i], time (0)); res = PQexec (conn, query_string); if (PQresultStatus (res) != PGRES_COMMAND_OK) { send (new_fd, "\nDBINSERT KO (2)\n", 16, MSG_NOSIGNAL); send (new_fd, query_string, strlen(query_string), MSG_NOSIGNAL); send (new_fd, "\n", 1, MSG_NOSIGNAL); PQclear (res); } else { send (new_fd, "\nDBINSERT OK (1)\n", 16, MSG_NOSIGNAL); PQclear (res); } } PQfinish (conn); } if ((strncmp (buffer, "QUIT", 4) == 0)) { printf ("Connexion QUIT from slot %i \n", i); syslog (LOG_NOTICE, "End of cnx : QUIT (slot n°%i)", i); close (clients[i]); clients[i] = 0; } if ((strncmp (buffer, "TIME", 4) == 0)) { printf ("TIME from slot %i : %ld ms \n", i, getMicrotime () - clients_t[i]); } if ((strncmp (buffer, "EXIT", 4) == 0)) { printf ("Connexion EXIT from slot %i \n", i); syslog (LOG_NOTICE, "End of cnx : EXIT (slot n°%i)", i); close (clients[i]); clients[i] = 0; } if ((strncmp (buffer, "CLOSE", 5) == 0)) { printf ("Connexion CLOSE from slot %i \n", i); syslog (LOG_NOTICE, "End of cnx : CLOSE (slot n°%i)", i); close (clients[i]); clients[i] = 0; } if ((strncmp (buffer, "INTERFACE", 9) == 0)) { send (new_fd, "\n", 1, MSG_NOSIGNAL); send (new_fd, localip, strlen (localip), MSG_NOSIGNAL); send (new_fd, "\n", 1, MSG_NOSIGNAL); } if ((strncmp (buffer, "IP", 2) == 0)) { send (new_fd, "\n", 1, MSG_NOSIGNAL); send (new_fd, p, strlen (p), MSG_NOSIGNAL); send (new_fd, "\n", 1, MSG_NOSIGNAL); } if ((strncmp (buffer, "CLIENT", 6) == 0)) { send (new_fd, "\n", 1, MSG_NOSIGNAL); send (new_fd, clients_ip[i], strlen (clients_ip[i]), MSG_NOSIGNAL); send (new_fd, "\n", 1, MSG_NOSIGNAL); } if ((strncmp (buffer, "DBCNX", 2) == 0)) { send (new_fd, "\n", 1, MSG_NOSIGNAL); send (new_fd, conninfo, strlen (conninfo), MSG_NOSIGNAL); send (new_fd, "\n", 1, MSG_NOSIGNAL); } } } } } else { perror ("SELECT"); syslog (LOG_ERR, "Error on select"); continue; } } return 0; }
Ensuite on compile :
[root@localhost ~]# gcc -o server5 server5.c -lpq
Et on fait un test avec deux terminaux :
- Terminal n°1 : le serveur
[root@localhost ~]# ./server5 Default interface is : enp0s3 Local ip is : 192.168.10.159 POSTGRES2_PORT_5432_TCP_ADDR : (null) OK : Table STATISTIQUE Connexion received from 127.0.0.1 (slot 0) Received from slot 0 : DBINSERT Received from slot 0 : TIME TIME from slot 0 : 8470474 ms Received from slot 0 : CLIENT Received from slot 0 : QUIT Connexion QUIT from slot 0 ^C
- Terminal n°2 : le client et la vérification en base de donnée
[root@localhost ~]# telnet 127.0.0.1 80 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. HELLO DBINSERT DBINSE DBINSERT OK (1) hostaddr=127.0.0.1 port=5432 user=postgres password=password TIME CLIENT 127.0.0.1 QUIT Connection closed by foreign host. [root@localhost ~]# psql -h localhost -p 5432 -d postgres -U postgres Mot de passe pour l'utilisateur postgres : psql (9.2.15, serveur 9.5.2) ATTENTION : psql version 9.2, version du serveur 9.5. Certaines fonctionnalités de psql pourraient ne pas fonctionner. Saisissez « help » pour l'aide. postgres=# select * from statistique; id | client | server | temps_milli | temps_cur ----+----------------------+----------------------+-------------+------------ 1 | 127.0.0.1 | 192.168.10.159 | 4035350 | 1460738997 (1 ligne) postgres=# \quit
Maintenant on va tuer les anciens server4 pour mettre les server5 à la place.
[root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 78f6bc54152e my-server4 "/sbin/server4" 11 hours ago Up 11 hours 0.0.0.0:8083->80/tcp my-server4-4 fce6865343f1 my-server4 "/sbin/server4" 11 hours ago Up 11 hours 0.0.0.0:8082->80/tcp my-server4-3 a75937eb980d my-server4 "/sbin/server4" 11 hours ago Up 11 hours 0.0.0.0:8081->80/tcp my-server4-2 eacf3e4bc897 my-server4 "/sbin/server4" 11 hours ago Up 11 hours 0.0.0.0:8080->80/tcp my-server4-1 2fc533c55725 postgres "/docker-entrypoint.s" 21 hours ago Up 21 hours 0.0.0.0:5432->5432/tcp postgres2 [root@localhost ~]# docker stop 78f6bc54152e 78f6bc54152e [root@localhost ~]# docker stop fce6865343f1 fce6865343f1 [root@localhost ~]# docker stop a75937eb980d a75937eb980d [root@localhost ~]# docker stop eacf3e4bc897 eacf3e4bc897 [root@localhost ~]# cat Dockerfile FROM fedora MAINTAINER toto toto@cyber-neurones.org COPY ./server5 /sbin/server5 RUN dnf install postgresql -y # Le port en ecoute EXPOSE 80 # Pour lancer postgres CMD ["/sbin/server5"] [root@localhost ~]# docker build -t my-server5 . Sending build context to Docker daemon 173.1 kB Step 1 : FROM fedora ---> ddd5c9c1d0f2 Step 2 : MAINTAINER toto toto@cyber-neurones.org ---> Using cache ---> bb6bc55cbbfc Step 3 : COPY ./server5 /sbin/server5 ---> 2fe1490bb5ce Removing intermediate container f1423fb336e8 Step 4 : RUN dnf install postgresql -y ---> Running in 6543ce6e13d1 Last metadata expiration check performed 0:07:57 ago on Fri Apr 15 17:11:57 2016. Dependencies resolved. ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: postgresql x86_64 9.4.7-1.fc23 updates 1.1 M postgresql-libs x86_64 9.4.7-1.fc23 updates 240 k Transaction Summary ================================================================================ Install 2 Packages Total download size: 1.3 M Installed size: 4.4 M Downloading Packages: -------------------------------------------------------------------------------- Total 3.8 kB/s | 1.3 MB 06:03 Running transaction check Transaction check succeeded. Running transaction test Transaction test succeeded. Running transaction Installing : postgresql-libs-9.4.7-1.fc23.x86_64 1/2 Installing : postgresql-9.4.7-1.fc23.x86_64 2/2 Verifying : postgresql-9.4.7-1.fc23.x86_64 1/2 Verifying : postgresql-libs-9.4.7-1.fc23.x86_64 2/2 Installed: postgresql.x86_64 9.4.7-1.fc23 postgresql-libs.x86_64 9.4.7-1.fc23 Complete! ---> 525d14c0b7bd Removing intermediate container 6543ce6e13d1 Step 5 : EXPOSE 80 ---> Running in 5e5c9d20a133 ---> 8e17ff5fd52f Removing intermediate container 5e5c9d20a133 Step 6 : CMD /sbin/server5 ---> Running in 45bf70b1fd01 ---> 07c7d4591a0f Removing intermediate container 45bf70b1fd01 Successfully built 07c7d4591a0f [root@localhost ~]# docker rm my-server4-1 my-server4-1 [root@localhost ~]# docker rm my-server4-2 my-server4-2 [root@localhost ~]# docker rm my-server4-3 my-server4-3 [root@localhost ~]# docker rm my-server4-4 my-server4-4 [root@localhost ~]# docker run -p 8080:80 --link postgres2:postgres2 --name my-server4-1 -d my-server5 4fb8f79456af940d23ecd9913cb737326d2f9e9dc61ecb09e3ad99c669b57543 [root@localhost ~]# docker run -p 8081:80 --link postgres2:postgres2 --name my-server4-2 -d my-server5 5b9099ae80d024518259d65c3519b05149164e4f0f8a1a7959ec17f032724a0c [root@localhost ~]# docker run -p 8082:80 --link postgres2:postgres2 --name my-server4-3 -d my-server5 1e87ae6b009be77a8795620aada0855b23f309d427f3d30ba9b822b09e98ae57 [root@localhost ~]# docker run -p 8083:80 --link postgres2:postgres2 --name my-server4-4 -d my-server5 eb76431e86e0b7519e8314e93b5e8a48acfb2a26e60305564ccc1c35a69b2907 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES eb76431e86e0 my-server5 "/sbin/server5" 3 seconds ago Up 2 seconds 0.0.0.0:8083->80/tcp my-server4-4 1e87ae6b009b my-server5 "/sbin/server5" 13 seconds ago Up 12 seconds 0.0.0.0:8082->80/tcp my-server4-3 5b9099ae80d0 my-server5 "/sbin/server5" 22 seconds ago Up 21 seconds 0.0.0.0:8081->80/tcp my-server4-2 4fb8f79456af my-server5 "/sbin/server5" 38 seconds ago Up 38 seconds 0.0.0.0:8080->80/tcp my-server4-1 2fc533c55725 postgres "/docker-entrypoint.s" 22 hours ago Up 22 hours 0.0.0.0:5432->5432/tcp postgres2 [root@localhost ~]# docker rm mon-haproxy-v15b mon-haproxy-v15b [root@localhost ~]# docker run -d --link my-server4-1 --link my-server4-2 --link my-server4-3 --link my-server4-4 -p 80:80 --name mon-haproxy-v15b my-haproxy-v15 1f22de2c194bb252882d941ed9b8c14eff48f1fc97089121497c898c9a969d61 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1f22de2c194b my-haproxy-v15 "/docker-entrypoint.s" 4 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp mon-haproxy-v15b eb76431e86e0 my-server5 "/sbin/server5" About a minute ago Up About a minute 0.0.0.0:8083->80/tcp my-server4-4 1e87ae6b009b my-server5 "/sbin/server5" About a minute ago Up About a minute 0.0.0.0:8082->80/tcp my-server4-3 5b9099ae80d0 my-server5 "/sbin/server5" About a minute ago Up About a minute 0.0.0.0:8081->80/tcp my-server4-2 4fb8f79456af my-server5 "/sbin/server5" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp my-server4-1 2fc533c55725 postgres "/docker-entrypoint.s" 22 hours ago Up 22 hours 0.0.0.0:5432->5432/tcp postgres2
Maintenant on fait un petit test afin de voir que tout fonctionne.
[root@localhost ~]# telnet 127.0.0.1 80 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. HELLO DBINSERT DBINSE DBINSERT OK (1) hostaddr=172.17.0.2 port=5432 user=postgres password=password QUIT Connection closed by foreign host. [root@localhost ~]# telnet 127.0.0.1 80 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. HELLO DBINSERT DBINSE DBINSERT OK (1) hostaddr=172.17.0.2 port=5432 user=postgres password=password QUIT Connection closed by foreign host. [root@localhost ~]# psql -h localhost -p 5432 -d postgres -U postgres Mot de passe pour l'utilisateur postgres : psql (9.2.15, serveur 9.5.2) ATTENTION : psql version 9.2, version du serveur 9.5. Certaines fonctionnalités de psql pourraient ne pas fonctionner. Saisissez « help » pour l'aide. postgres=# select * from statistique; id | client | server | temps_milli | temps_cur ----+----------------------+----------------------+-------------+------------ 1 | 127.0.0.1 | 192.168.10.159 | 4035350 | 1460738997 2 | 172.17.0.7 | 172.17.0.3 | 5405983 | 1460742112 3 | 172.17.0.7 | 172.17.0.4 | 3369612 | 1460742123 (3 lignes) postgres=# \quit
On va pouvoir faire notre programme de stress : client_stress.c. Voici le source que je vous propose (je ne regarde pas les réponses du serveur sur le socket afin de faire un programme court).
#include <sys/types.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> int socket_client (char *serveur, unsigned short port) { int client_socket; struct hostent *hostent; struct sockaddr_in serveur_sockaddr_in; client_socket = socket (PF_INET, SOCK_STREAM, 0); if (client_socket == -1) { perror ("socket"); exit (EXIT_FAILURE); } if (inet_addr (serveur) == INADDR_NONE) /* nom */ { hostent = gethostbyname (serveur); if (hostent == NULL) { perror ("gethostbyname"); exit (EXIT_FAILURE); } } else /* adresse IP */ { unsigned long addr = inet_addr (serveur); hostent = gethostbyaddr ((char *) &addr, sizeof (addr), AF_INET); if (hostent == NULL) { perror ("gethostbyaddr"); exit (EXIT_FAILURE); } } memset (&serveur_sockaddr_in, 0, sizeof (serveur_sockaddr_in)); serveur_sockaddr_in.sin_family = AF_INET; serveur_sockaddr_in.sin_port = htons (port); memcpy (&serveur_sockaddr_in.sin_addr.s_addr, hostent->h_addr_list[0], hostent->h_length); if (connect (client_socket, (struct sockaddr *) &serveur_sockaddr_in, sizeof (serveur_sockaddr_in)) == -1) { perror ("connect"); exit (EXIT_FAILURE); } return client_socket; } int main (int argc, char **argv) { char *serveur; unsigned short port = 80; int client_socket = -1; int i = 0; unsigned long letime = 0; if (argc != 3) { fprintf (stderr, "usage: %s serveur port\n", argv[0]); exit (EXIT_FAILURE); } serveur = argv[1]; port = atoi (argv[2]); printf ("Start \n"); letime = time (0); while (1) { client_socket = -1; client_socket = (int) socket_client (serveur, port); usleep (100); write (client_socket, "DBINSERT", strlen ("DBINSERT") * sizeof (char)); usleep (100); write (client_socket, "QUIT", strlen ("QUIT") * sizeof (char)); close (client_socket); i++; if (i % 500 == 0) { printf ("Nombre %d le temps %d \n", i, time (0) - letime); } } exit (EXIT_SUCCESS); } /* EOF */
Avant de faire le test on vide la base de donnée :
postgres=# delete from statistique;
Et maintenant on passe à la compilation et la phase de test :
[root@localhost ~]# gcc -o client_stress client_stress.c
[root@localhost ~]# ./client_stress 127.0.0.1 80
Start
Nombre 500 le temps 3
Nombre 1000 le temps 6
Nombre 1500 le temps 9
Nombre 2000 le temps 12
Nombre 2500 le temps 17
Nombre 3000 le temps 25
Nombre 3500 le temps 34
Nombre 4000 le temps 38
Nombre 4500 le temps 43
gethostbyaddr: Invalid argument
Le programme fini par planter, je vous laisse voir pourquoi 😉 Et on contrôle que la répartition de charge c’est faites de façon équivalente entre tous les serveurs.
postgres=# select count(*),server from statistique group by server; count | server -------+---------------------- 1238 | 172.17.0.5 1239 | 172.17.0.6 1239 | 172.17.0.3 1237 | 172.17.0.4 (4 lignes)
Si vous êtes un PRO de SQL vous pouvez faire plus complexe en regardant le temps de traitement en fonction du server :
postgres=# select min(temps_milli),max(temps_milli),avg(temps_milli),count(*),server from statistique group by server; min | max | avg | count | server ------+---------+--------------------+-------+---------------------- 1750 | 1037158 | 41649.365105008078 | 1238 | 172.17.0.5 1883 | 1029440 | 37218.885391444713 | 1239 | 172.17.0.6 1799 | 1032792 | 46888.554479418886 | 1239 | 172.17.0.3 1816 | 1046117 | 46996.953112368634 | 1237 | 172.17.0.4 (4 lignes)
Pas de doute, il est plus facile pour moi de faire du code 😉 Je vous donne la solution pour ne pas avoir l’erreur.
[root@localhost ~]# ./client_stress localhost 80 Start Nombre 500 le temps 2 Nombre 1000 le temps 4 Nombre 1500 le temps 6 Nombre 2000 le temps 8 Nombre 2500 le temps 10 Nombre 3000 le temps 12 Nombre 3500 le temps 14 Nombre 4000 le temps 17 Nombre 4500 le temps 19 Nombre 5000 le temps 21 Nombre 5500 le temps 23 Nombre 6000 le temps 26 Nombre 6500 le temps 28 Nombre 7000 le temps 30 Nombre 7500 le temps 32 Nombre 8000 le temps 35 Nombre 8500 le temps 37 Nombre 9000 le temps 39 Nombre 9500 le temps 41 Nombre 10000 le temps 43 Nombre 10500 le temps 46 Nombre 11000 le temps 63 Nombre 11500 le temps 74 Nombre 12000 le temps 77
A noter le gros delta que j’ai eu entre 63 etc 46, mais vu que je n’ai pas de logs cela va rester un mystère. Voici les statistiques :
postgres=# select min(temps_milli),max(temps_milli),avg(temps_milli),count(*),server from statistique group by server; min | max | avg | count | server ------+---------+--------------------+-------+---------------------- 1750 | 1037158 | 39815.738331678252 | 4028 | 172.17.0.5 1867 | 1029440 | 38359.346345101939 | 4022 | 172.17.0.6 1799 | 1032792 | 41384.980841005225 | 4019 | 172.17.0.3 1808 | 1046117 | 41427.165548098434 | 4023 | 172.17.0.4 (4 lignes)
Avant de vous laissé, j’ai quand même envie de remettre NGINX afin de faire un petit test comparatif 😉
[root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1f22de2c194b my-haproxy-v15 "/docker-entrypoint.s" 37 minutes ago Up 37 minutes 0.0.0.0:80->80/tcp mon-haproxy-v15b eb76431e86e0 my-server5 "/sbin/server5" 39 minutes ago Up 39 minutes 0.0.0.0:8083->80/tcp my-server4-4 1e87ae6b009b my-server5 "/sbin/server5" 39 minutes ago Up 39 minutes 0.0.0.0:8082->80/tcp my-server4-3 5b9099ae80d0 my-server5 "/sbin/server5" 39 minutes ago Up 39 minutes 0.0.0.0:8081->80/tcp my-server4-2 4fb8f79456af my-server5 "/sbin/server5" 40 minutes ago Up 40 minutes 0.0.0.0:8080->80/tcp my-server4-1 2fc533c55725 postgres "/docker-entrypoint.s" 22 hours ago Up 22 hours 0.0.0.0:5432->5432/tcp postgres2 [root@localhost ~]# docker stop 1f22de2c194b 1f22de2c194b [root@localhost ~]# docker run --name mon-nginx-v7 --link my-server4-1 --link my-server4-2 --link my-server4-3 --link my-server4-4 -p 80:80 -v /root/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx b37844241909fb69646f02d3541428671a8024a5cfa0fa578bf5be0d8b957068 [root@localhost ~]# cat nginx.conf worker_processes 4; events { worker_connections 8192; } http { include mime.types; default_type application/octet-stream; } stream { upstream stream_backend { server my-server4-1:80 weight=5; server my-server4-2:80; server my-server4-3:80; server my-server4-4:80; } server { listen 80; proxy_pass stream_backend; } } [root@localhost ~]# psql -h localhost -p 5432 -d postgres -U postgres Mot de passe pour l'utilisateur postgres : psql (9.2.15, serveur 9.5.2) ATTENTION : psql version 9.2, version du serveur 9.5. Certaines fonctionnalités de psql pourraient ne pas fonctionner. Saisissez « help » pour l'aide. postgres=# delete from statistique; DELETE 16092 postgres=# \quit [root@localhost ~]# ./client_stress localhost 80 Start Nombre 500 le temps 1 Nombre 1000 le temps 3 Nombre 1500 le temps 5 Nombre 2000 le temps 7 Nombre 2500 le temps 9 Nombre 3000 le temps 11 Nombre 3500 le temps 13 Nombre 4000 le temps 15 Nombre 4500 le temps 17 Nombre 5000 le temps 19 Nombre 5500 le temps 21 Nombre 6000 le temps 23 Nombre 6500 le temps 25 Nombre 7000 le temps 28 Nombre 7500 le temps 30 Nombre 8000 le temps 32 Nombre 8500 le temps 34 Nombre 9000 le temps 36 Nombre 9500 le temps 42 Nombre 10000 le temps 44 Nombre 10500 le temps 50 Nombre 11000 le temps 58 Nombre 11500 le temps 75 Nombre 12000 le temps 122
J’ai 122 sec (pauses comprises) pour 12000 inserts … alors qu’avec HAProxy c’était 77 sec. Maintenant je regarde en base de donnée :
postgres=# select min(temps_milli),max(temps_milli),avg(temps_milli),count(*),server from statistique group by server; min | max | avg | count | server ------+----------+--------------------+-------+---------------------- 1596 | 7035984 | 51478.137139311201 | 3223 | 172.17.0.3 1723 | 8038108 | 68590.102406267487 | 1787 | 172.17.0.5 1660 | 7043045 | 67068.732963988920 | 1805 | 172.17.0.6 1680 | 16047502 | 76722.983117613956 | 1777 | 172.17.0.4 (4 lignes) postgres=# select count(*) from statistique; count ------- 8592 (1 ligne)
La répartition n’a pas été homogène, je pense que mon fichier de configuration n’est pas bon. En plus nous avons un grand nombre de perte : 12000-8592 🙁 Et pour finir le temps de traitement est plus long quand cela fonctionne. On voit donc l’utilité du programme de charge, quand on fait les tests de façon unitaire il est rare de tomber sur un problème. Et quand on commence à faire de la charge, les vrais problèmes apparaissent.