Comparatif MySQL dans le PaaS, épisode 3 : Amazon RDS (1/2)

mardi, mai 7, 2019
By David Baffaleuf in AWS (dbaffaleuf@capdata-osmozium.com) [77 article(s)]

Rappel des épisodes précédents :
– épisode 1 : MySQL sur Google Cloud platform.
– épisode 2 : MySQL et MariaDB sur Microsoft Azure.

Bon alors là ça devient compliqué. Volet 1/2 de l’épisode 3 ça commence à ressembler au code civil cette affaire…

Il faut réaliser à quel point l’offre PaaS d’Amazon est nettement plus avancée que les autres : à thème égal (limitations, connectivité, configuration, performance, MCO, haute dispo, réplication, coûts, etc…) il y a – beaucoup – plus de choses à dire sur RDS. Et si on veut que cela reste lisible, il faut découper en deux parties.

Quand je repense qu’au départ il ne devait y avoir que 3 épisodes avec MySQL et Aurora dans le même article, j’étais optimiste… Il y aura donc encore un épisode 4 en deux articles au moins juste pour parler d’Aurora.

Bref dans cet épisode 3 partie 1/2, nous allons découvrir le contexte technique dans lequel une base RDS peut évoluer : régions, AZ, tiers, stockage, etc… Ce que je vais dire ici s’applique aussi aux autres bases de données dans RDS, c’est d’ailleurs un atout important pour Amazon, l’homogénéité des fonctions et des méthodes, de sorte que l’on s’y retrouve en passant d’un SGBD à un autre.

On entrera un peu dans le sujet MySQL sur les questions initiales de limitations, déploiement, configuration, accès aux logs, etc… Puis nous verrons la suite et le comparatif final dans le volet 2/2.

1/2, clap, c’est parti.

AWS Global

Déjà quelques éléments de contexte. RDS est une des principales briques historiques du cloud d’Amazon avec S3 et EC2. Ce cloud s’appuie sur une infrastructure déployée sur 4 et bientôt 5 continents. Rien qu’en Europe nous avons 5 régions ou pays dans lesquels des infrastructures sont déployées: Irlande, Londres, Francfort, Stockholm et Paris. Milan sera la 6ième région déployée.

Mono-AZ , Multi-AZ:

Chaque région compte 3 zones de disponibilité ou AZ, et si vous avez suivi les épisodes précédents rien n’est vraiment différent de GCP ou Azure. Une AZ peut être vue comme un datacenter mettant à disposition des ressources de calcul, stockage, d’interconnexion réseau, ainsi que des briques applicatives. Dans le monde AWS, on parle de Mono-AZ ou de Multi-AZ pour évoquer le niveau de distribution d’une brique comme RDS:

En mode Mono-AZ à gauche sur le schéma, notre instance RDS serait isolée dans une seule AZ. Les équipements confinés à l’AZ sont redondés comme les hyperviseurs, le stockage, etc… mais il n’y a pas de secours en cas de perte de l’AZ complète. A droite en revanche, une instance en déploiement Multi-AZ est secourue par une seconde instance de standby dans une autre zone de disponibilité, l’équivalent du failover replica sur GCP, et donc sans équivalence sur Azure.

Le mode de déploiement est choisi lors de la création de l’instance mais peut aussi être modifié plus tard. Evidemment Multi-AZ signifie aussi surcoût, nous verrons ces aspects un peu plus loin.

Les modes de facturation:

Deux modes disponibles:
– Le Pay-as-you-go : paiement à la seconde d’utilisation depuis peu, le tarif par instance varie en fonction de sa classe, de son déploiement dans la région (Mono vs multi-AZ) et du stockage employé.
– La réservation d’instances : engagement sur 1 ou 3 ans avec paiement tout en avance (all upfront) ou partiellement en avance (partial upfront). Attention seul le prix de l’instance est payable en avance, les autres coûts (stockage, IOPS provisionnés, backup, support) restent des coûts mensuels.

Si on compare le coût d’une instance de type db.m5.xlarge sur 1 an en pay-as-you-go ou en réservation:

On voit que l’économie est déjà substantielle par rapport au prix de l’instance:

Sur les plus grosses configurations et sur un engagement de 3 ans, l’économie peut être encore plus importante (50K$ sur 3 ans pour une instance de type db.r5.4xlarge à 5000$ par mois en pay-as-you-go). Cela va donc dépendre des capacités de financement et des objectifs à moyen terme. Mais c’est déjà une première avance sur les concurrents qui n’offrent pas de capacité de réservation sur toute leur gamme de bases en mode PaaS.

Les tiers disponibles pour RDS:

Deux grandes classes de tiers sont disponibles:
– La classe Standard: db.m5 pour les configurations standard, et db.t2 et db.t3 pour les petites configurations (hors prod, test, etc…). On note que ces instances t2 et t3 sont de type ‘Burstable’, on va voir un peu plus loin de quoi il s’agit…
– La classe Memory Optimized: db.r4 et db.r5 pour aller jusqu’à 96vCPUs et 768Gb de mémoire. Il existe d’autres tiers db.x1 et db.x1e en Memory Optimized mais ils ne sont pas disponibles dans toutes les régions, et notamment pas encore en France.

La tarification étant susceptible de changer, il vaut mieux se référer à la source officielle pour un pricing précis.

Le stockage disponible pour RDS:

Le stockage utilisable sur RDS est basé sur la brique EBS : Elastic Block Storage, qui est l’autre grosse brique stockage d’Amazon avec S3. Si S3 est orientée fichiers, EBS est un peu comme un block storage sous stéroides : encryption, snapshots, réplication intra-AZ, scalabilité en capacité et en IOPS provisionnés…

2 types de stockage seront disponibles :

General Purpose ou GP2: c’est un stockage SSD classique pour lequel on provisionne une capacité pour obtenir des IOPS, comme cela se fait chez GCP ou Azure.

Le système est calibré pour donner 3 IOPS/Gb avec un plafond à 16000 IOPS atteint à 5Tb. La différence est que pour des volumes inférieurs à 1Tb (aire ‘A’ sur le schéma ci-dessous), le système peut solliciter des pics au delà de ses 3 IOPS /Gb en utilisant des crédits d’IOPS. Tant que le système est idle, il accumule des crédits d’IOPS qui lui permettent ensuite de pouvoir effectuer des pics à 3000 IOPS jusqu’à épuisement de ses crédits:

Au delà de 1Tb, les IOPS sont fixes de 3000 jusqu’à 16000 en fonction de la volumétrie.

– Le deuxième type de stockage est Provisionned SSD ou IO1 : aussi basé sur des disques SSD, plus performants, mais surtout dans ce cas, on ne provisionne plus une capacité disque mais un nombre d’IOPS. Ce qui veut dire que l’on peut provisionner seulement 200Gb de disque tout en garantissant 5000 IOPS par exemple. Côté Amazon, cela signifie que notre petite LUN de 200Gb doit être probablement strippée sur plusieurs disques, ce qui revient supposément assez cher et complexe à maintenir pour Amazon, et donc le prix sur la facture est aussi non négligeable.

Evidemment on ne va pas pouvoir allouer 50 Gb et demander 10000 IOPS non plus, il y a donc des règles de capacité minimale en fonction des IOPS provisionnés:

Par exemple, si on veut 5000 IOPS on ne pourra pas descendre sous les 100Gb de capacité (pour tout de même 330$ par mois).

Burstable instances:

On en a un peu parlé, les tiers de type t2 et t3 sont de type burstable. Comme pour les disques gp2 sous 1Tb, les instances burstable ont la possibilité d’accumuler des crédits CPU pour pouvoir dépasser leur capacité CPU théorique momentanément lors de pics de charge.

En fonction du dimensionnement du tier, il est établi une CPU baseline (par exemple 16.9% pour un t2.2xlarge, ou 30% pour une t3.large) au dessous de laquelle la machine va accumuler des crédits CPU. En gros un crédit CPU revient à pouvoir monter à 100% sur un CPU pendant 1 minute. Lorsqu’elle a passe au dessus de sa CPU baseline, la machine va commencer à dépenser ses crédits jusqu’à épuisement de ceux-ci, auquel cas elle sera bridée à 20% jusqu’à recapitaliser de nouveaux crédits. Le but de la manoeuvre étant de permettre à une machine de faible dimensionnement de pouvoir dépasser sa capacité CPU sans pour autant saturer la CPU pour les autres tiers mutualisés sur la même infrastructure physique.

Par exemple:

Dans ce cas de figure la CPU baseline est à 30% (en bleu), et on distingue 4 phases:
– Une première phase où la charge reste sous 30% et les crédits sont accumulés.
– Une deuxième phase où la charge passe au dessus des 30% et les crédits sont peu à peu dépensés.
– Une troisième phase où les crédits sont épuisés, et la charge CPU sera bridée à 20%.
– Et enfin une quatrième où la charge retombe et les crédits peuvent être cumulés à nouveau.

Vous l’aurez compris, une burstable instance utilise ses crédits au besoin et au fil de l’eau. Mais elle peut aussi obtenir d’AWS une ‘avance’ sur ses crédits, et la possibilité de pouvoir les dépenser immédiatement sans avoir besoin d’attendre de les cumuler. Ce mode est appelé unlimited:

Dans cet exemple, l’instance obtient la totalité de ses 288 crédits immédiatement et peut les dépenser jusqu’à épuisement. En revanche, lorsqu’ils sont épuisés, la machine sera plafonnée à 20% CPU jusqu’au lendemain.

Maintenant que l’on a posé le décor, on va pouvoir commencer à parler vraiment de MySQL sur RDS.

MySQL et MariaDB sur RDS

En réalité RDS n’est qu’une facette du PaaS bases de données sur AWS, dans la mesure où il regroupe simplement les bases de données dites relationnelles. Mais il existe aussi d’autres solutions non relationnelles (DynamoDB, DocumentDB), périphériques (Elasticache) ou orientées gros volumes (Neptune, Redshift) pour compléter l’offre.

On retrouvera donc dans RDS les bases de données que l’on connaît déjà, plus le moteur maison, Aurora, que l’on verra dans un prochain épisode:

A noter qu’AWS est la seule plateforme en dehors d’Oracle Cloud à proposer du PaaS sur Oracle, et supporte depuis peu la 12.2…

Support et limitations:

– Pour les versions à ce jour, RDS supporte de MySQL 5.5.46 à 8.0.15 , et MariaDB de 10.0.24 à 10.3.13. C’est le seul PaaS à supporter MySQL 8.0, depuis le 23 octobre dernier.
– Sur le plan des storage engines, il est annoncé le support de InnoDB et MyISAM, avec toutefois les réserves de rigueur quant à la garantie de restaurabilité point-in-time lorsque les tables sont en MyISAM ou que les moteurs sont mixés. Federated n’est pas supporté.
– Memcached et le plugin d’audit MariaDB sont disponibles via les options groups que nous allons détailler plus loin.
– Support GTIDs à partir de la 5.7.23+
– Support du préchargement du buffer pool innodb à partir de la version 5.6.
– Pas de privilège SUPER, comme pour les autres PaaS MySQL, mais la plupart des commandes son disponibles via des procédures stockées dans la base mysql : rds_% (KILL, KILL QUERY, CHANGE MASTER TO, RESET MASTER, START SLAVE, etc…)
– Pas de support de SET PERSIST en 8.0 pour l’instant, le paramétrage passe par des Parameter Groups que l’on va aussi voir en détail plus loin…
– Pas de support pour la réplication semi-synchrone.

Connectivité:

Lors de la création de l’instance, il ne sera évidemment pas proposé par défaut d’associer l’endpoint à une IP publique :

Un VPC dédié sera créé avec tout ce qui va avec (NACL, Security Group), la bonne pratique étant de placer l’instance sur un subnet privé et de gérer les ouvertures via le Security Group et éventuellement une NAT Gateway, et les filtrages avec le Network ACL.

Ensuite la connexion à l’instance peut se faire de 2 manières :
– Soit en utilisant un client classique (mysql ou GUI) depuis un bastion ou une autre machine on-prem / EC2. Par exemple ici en préconfigurant un login-path vers une instance RDS 5.7:

$ mysql_config_editor set --login-path=my57fromlocalPC \ 
--host=my57.xxxxxxxxxxx.eu-west-3.rds.amazonaws.com --port=3306 \
--user=my57_user --password
Enter password: ************
$ mysql --login-path=my57fromlocalPC --execute="select version();"
+------------+
| version()  |
+------------+
| 5.7.25-log |
+------------+

– Soit en utilisant l’authentification via le compte IAM utilisateur. Dans ce cas, une demande de token préalable permettra de se connecter sans fournir de mot de passe. Le token est valable 15 minutes, ensuite il devra être renouvelé.

$ TOKEN="$(aws rds generate-db-auth-token \
--hostname my57.xxxxxxxxxxx.eu-west-3.rds.amazonaws.com \
--port=3306 --region eu-west-3 --username my57_user)"

$ mysql --host=my57.xxxxxxxxxxx.eu-west-3.rds.amazonaws.com --port=3306 \
--user=my57_user --ssl-ca=~/rds-combined-ca-bundle.pem \
--ssl-mode=VERIFY_IDENTITY --enable-cleartext-plugin --password=${TOKEN} \
--execute="select version();"
+------------+
| version()  |
+------------+
| 5.7.25-log |
+------------+

AWS cli:

Comme chez les concurrents, AWS propose en plus de la console un utilitaire CLI de management des ressources, l’aws cli. Il est basé sur Python, peut s’installer sur Windows ou Linux, et il est directement prépackagé sur les AMI Amazon Linux. Toutes les briques principales sont accessibles avec une syntaxe type par service (service = { s3, ec2, rds, cloudwatch, lambda, etc…} ):

aws [service] [fonction] [parametres …]

Par exemple obtenir les caractéristiques d’une instance RDS:

$ aws rds describe-db-instances --db-instance-identifier my57
{
    "DBInstances": [
        {
            "DBInstanceIdentifier": "my57",
            "DBInstanceClass": "db.t2.micro",
            "Engine": "mysql",
            "DBInstanceStatus": "available",
            "MasterUsername": "my57_user",
            "DBName": "mysql_user",
            "Endpoint": {
                "Address": "my57.xxxxxxxxxxx.eu-west-3.rds.amazonaws.com",
                "Port": 3306,
                "HostedZoneId": "ZMESEXB7ZGGQ3"
(...)

Tout ce que nous allons voir par la suite sera porté par aws cli. Il est important de bien comprendre sa syntaxe et sa grammaire, car c’est un outil indispensable à tout bon devops aws qui se respecte…

Security groups:

On l’a dit un peu plus haut, lors de la création de l’instance, l’assistant proposera de créer un nouveau VPC et donc un nouveau security group. Juste pour information, un security group va jouer le rôle du firewall et permettre d’ouvrir les ports nécessaires à la connexion vers l’instance RDS. L’avantage dans le cas d’AWS est qu’il est détaché du reste de l’instance, de sorte que si l’instance est supprimée ou restaurée à partir d’un snapshot, les informations de filtrage réseau peuvent être réutilisées. Il est même possible de préparer un groupe de sécurité avant même de créer l’instance et le rattacher à la création:

Par défaut, chaque règle ajoutée dans un groupe de sécurité l’est dans les 2 sens: inbound et outbound. Donc on ouvrira seulement le port MySQL (3306 par défaut) soit sur l’IP publique soit sur la NAT gateway pour permettre un accès depuis l’extérieur.

Parameter Groups:

Que des bonnes nouvelles : déjà tous les paramètres MySQL ou MariaDB sont accessibles sur RDS.

Ensuite, les paramètres de configuration sont gérés via des parameter groups (PG). Comme le Security Group, le PG est un conteneur indépendant de l’instance et peut même s’appliquer à plusieurs instances RDS. Avec le même bénéfice, lorsque l’on supprime ou que l’on restaure une instance, le PG est immédiatement réutilisable.

A chaque instance est associé un PG par défaut, qui peut être modifié, mais la bonne pratique reste de créer un PG customisé en dupliquant le PG par défaut. Comme pour les Security Groups, un custom PG peut même être créé avant de créer l’instance RDS et être précisé lors de sa création:

Un des intérêts est aussi de pouvoir assurer une forme d’homogénéité du paramétrage sur une flotte d’instances. A travers la console, il est par exemple possible de comparer le contenu de 2 PG pour voir s’il existe des différences:

Une des premières actions à effectuer post ou pré-création selon le cas sera donc de dupliquer le PG par défaut et de créer un PG customisé pour pouvoir ensuite l’appliquer à l’instance. Ci-dessous, le PG par défaut pour MYSQL 5.7 est dupliqué pour créer un PG customisé baptisé “my57PG”, puis le nouveau PG est rattaché à l’instance RDS (on peut utiliser au choix create-db-parameter-group à partir d’un modèle ou copy-db-parameter-group)

$ aws rds create-db-parameter-group \
	--db-parameter-group-name my57PG \
	--db-parameter-group-family mysql5.7 \
	--description "My Private 5.7 PG"

$ aws rds modify-db-instance \
	--db-instance-identifier my57 \
	--db-parameter-group-name my57PG

Le rattachement d’un PG à une instance nécessite un redémarrage de celle-ci. On peut ensuite vérifier via la fonction générale aws rds describe-db-instance que le nouveau groupe de paramètres est bien actif:

$ aws rds reboot-db-instance --db-instance-identifier my57
$ aws rds describe-db-instances --db-instance-identifier my57
(...)	"DBParameterGroupName": "my57pg",
	"ParameterApplyStatus": "in-sync"

Comme dans le cas d’une instance on-prem, certains paramètres seront dynamiques et d’autres seront statiques et nécessiteront un redémarrage de l’instance pour être effectifs :

$ aws rds describe-db-parameters \ 
	--db-parameter-group-name my57PG \
	--query "Parameters[*][ParameterName,ParameterValue,ApplyType]" \
	--output text
allow-suspicious-udfs		None    static
autocommit			None    dynamic
auto_generate_certs		None    static
auto_increment_increment	None    dynamic
auto_increment_offset		None    dynamic
(...)

Sans privilège SUPER, il ne sera pas possible d’appliquer un paramètre via SET GLOBAL. La fonction aws rds modify-db-parameter-group permettra donc de pallier à ce problème :

$ aws rds modify-db-parameter-group  \
	--db-parameter-group-name my57PG \
	--parameters "ParameterName=max_connections, ParameterValue=200,ApplyMethod=immediate"

Si le paramètre est dynamique comme c’est le cas ici, il est immédiatement pris en compte au niveau de l’instance :

$ mysql --login-path=my57fromlocalPC --execute="select @@max_connections;"
+--------------------+
| @@max_connections  |
+--------------------+
|                200 |
+--------------------+

Accès aux journaux:

Trois types de journaux sont disponibles pour MySQL
– Le log d’erreur.
– Le log général
– Le log de requêtes lentes.

Par défaut, seul l’accès au log d’erreur est configuré. Les autres peuvent être activé via leurs paramètres respectifs (general_log, slow_query_log + long_query_time). La liste des journaux disponibles peut être obtenue et chaque journal peut être téléchargé pour être inspecté localement:

$ aws rds describe-db-log-files --db-instance-identifier my57
(...) {
            "LogFileName": "error/mysql-error.log",
            "LastWritten": 1554363300000,
            "Size": 0
        }, (...)

$ aws rds download-db-log-file-portion --db-instance-identifier my57 \
	--starting-token 0 --output text \
	--log-file-name "error/mysql-error.log"
2019-04-01T15:23:12.123344Z 0 [Note] Giving 1 client threads a chance to die gracefully
2019-04-01T15:23:12.124334Z 0 [Note] Shutting down slave threads
2019-04-01T15:23:14.124539Z 0 [Note] Forcefully disconnecting 0 remaining clients (...)

Par défaut, un équivalant de FLUSH LOGS est effectué toutes les 5 minutes sur les fichiers. Si la destination pour le log général ou le log de requêtes lentes est une table, alors les tables peuvent être recyclées manuellement en utilisant les procédures stockées mysql.rds_rotate_general_log et mysql.rds_rotate_slow_log.

mysql> call mysql.rds_rotate_slow_log ;
Query OK, 0 rows affected (0.03 sec)

La rétention quant à elle peut se gérer via la console, dommage qu’on ne puisse pas le faire via aws cli ou une procédure stockée:

Option groups:

Il est aussi possible d’activer des fonctionnalités externes pour les instances RDS MySQL et MariaDB, comme le plugin d’audit de MariaDB ou le support de memcached. Ces fonctionnalités seront intégrées sous la forme d’options groups.

Par exemple pour activer l’audit MariaDB:

$ aws rds create-option-group --option-group-name "mariadbaudit" \
	--engine-name mysql --major-engine-version 5.7 \
	--option-group-description "test MariaDB audit plugin"

$ aws rds add-option-to-option-group --option-group-name "mariadbaudit" \
	--options "OptionName=MARIADB_AUDIT_PLUGIN" \
	--apply-immediately

$ aws rds modify-db-instance --db-instance-identifier "my57" \ 
	--option-group-name "mariadbaudit" \ 
	--apply-immediately

Et le fichier d’audit nouvellement activé apparaît dans la liste des logs consultables et peut être téléchargé à son tour:

$ aws rds describe-db-log-files --db-instance-identifier my57
{
	"DescribeDBLogFiles": [
	{
		"LogFileName": "audit/server_audit.log",
		"LastWritten": 1554360583000,
		"Size": 24815
}, (...)

$ aws rds download-db-log-file-portion --db-instance-identifier my57 \
	--starting-token 0 --output text \
	--log-file-name "audit/server_audit.log"
20190404 06:46:17,ip-10-22-1-227,rdsadmin,localhost,3,1,QUERY,,'install plugin server_audit soname \'server_audit.so\'',0
20190404 06:46:17,ip-10-22-1-227,rdsadmin,localhost,3,2,QUERY,,'SELECT 1',0
20190404 06:46:17,ip-10-22-1-227,rdsadmin,localhost,3,3,QUERY,,'SET GLOBAL server_audit_file_path=\'/rdsdbdata/log/audit/server_audit.log\'',0
20190404 06:46:17,ip-10-22-1-227,rdsadmin,localhost,3,3,QUERY,,'SET GLOBAL server_audit_file_path=\'/rdsdbdata/log/audit/server_audit.log\'',0
20190404 06:46:17,ip-10-22-1-227,rdsadmin,localhost,3,4,QUERY,,'SELECT 1',0
20190404 06:46:17,ip-10-22-1-227,rdsadmin,localhost,3,5,QUERY,,'SET GLOBAL server_audit_query_log_limit = 1024',0
 (...)

Conclusion partie 1/2

Bon, dans cette première partie nous avons découvert l’environnement technique qui entoure RDS : les régions, AZ, tiers, types de stockage… et quelques caractéristiques de l’offre PaaS pour MySQL sur AWS. Restez connectés pour la suite : le reste des fonctionnalités et le comparatif final GCP / Azure / AWS.

A bientôt !

David.

Continuez votre lecture sur le blog :




Cliquer pour partager cet article sur Viadeo
Cliquer sur "CAPTURER" pour sauvegarder cet article dans Evernote Clip to Evernote

Tags: , , , , ,

Leave a Reply