{"id":412,"date":"2019-04-19T15:42:14","date_gmt":"2019-04-19T13:42:14","guid":{"rendered":"https:\/\/blog.besharp.it\/?p=412"},"modified":"2021-03-17T12:34:27","modified_gmt":"2021-03-17T11:34:27","slug":"come-creare-un-replicaset-di-mongodb-con-self-healing-usando-i-servizi-di-aws","status":"publish","type":"post","link":"https:\/\/blog.besharp.it\/it\/come-creare-un-replicaset-di-mongodb-con-self-healing-usando-i-servizi-di-aws\/","title":{"rendered":"Come creare un ReplicaSet di MongoDB con Self-Healing usando i servizi di AWS"},"content":{"rendered":"
MongoDB<\/strong> \u00e8 un database NOSQL documentale immediato da configurare e da utilizzare e sta avendo una grandissima diffusione nei nuovi progetti di sviluppo. In questo articolo vedremo come sia possibile creare un sistema di self healing<\/strong> per i cluster di Mongo creati su AWS in modo da prevenire un possibile downtime.<\/span><\/p>\n MongoDB consente di creare un cluster distribuito in alta affidabilit\u00e0<\/strong> tramite i Replica Sets e lo Sharding:<\/span><\/p>\n La configurazione in Sharding non \u00e8 tollerante ad alcun fallimento, infatti in caso di down di una macchina le Collection presenti sulla stessa diventano inaccessibili. Per ovviare a questo problema si opta per una configurazione mista basata su Sharding e Replication<\/strong> dove ogni nodo dello sharding \u00e8 in realt\u00e0 un Replica Set.<\/span><\/p>\n Ogni Replica Set \u00e8 composto da un Master che si occupa di eseguire le operazioni di scrittura e lettura e da almeno due Repliche che non accettano direttamente scritture ma vengono tenute sincronizzate con i dati presenti nel Master e possono eseguire solo operazioni in lettura. Ogni nodo comunica agli altri continuamente (ogni 2 secondi) il proprio stato tramite un sistema di heartbeats e in caso di fallimento del master i nodi secondari eseguono una votazione con cui viene eletto il nuovo Master. <\/span><\/p>\n Affinch\u00e9 la votazione avvenga correttamente tuttavia devono partecipare alla votazione pi\u00f9 del 50% dei nodi che compongono il cluster. <\/strong><\/span><\/p>\n Nel caso di un deploy su AWS \u00e8 pertanto consigliabile distribuire equamente le EC2 su almeno tre Availability Zones<\/strong> (AZ) se si desidera che il Replica Set resti funzionante anche in caso di down di una AZ.<\/span><\/p>\n Per database di dimensioni contenute e non <\/span>read intensive,<\/span><\/i> oppure per database con Sharding, molto spesso si usa una configurazione con tre nodi per il Replica Set. In questa configurazione in caso di fallimento di un nodo ne rimangono sempre disponibili altri due per la votazione, uno dei quali verr\u00e0 promosso a master.<\/span><\/p>\n Tuttavia, soprattutto in condizioni di traffico intenso, il fallimento di un nodo deve essere trattato come un emergenza e risolto il prima possibile in quanto qualunque ulteriore fallimento comporterebbe una interruzione del servizio. <\/span><\/p>\n Per risolvere in modo automatico questo tipo di situazione e consentire a chi si occupa di gestire il db di portare a termine l\u2019analisi post mortem dell’istanza mongodb fallita abbiamo implementato un sistema di self-healing per mongodb<\/strong> in grado di ricreare automaticamente un istanza identica a quella non pi\u00f9 raggiungibile e riconfigurare il replica set per usare la nuova EC2 al posto di quella corrotta.<\/span><\/p>\n Gli strumenti di AWS utilizzati per implementare \u00a0questa soluzione sono i seguenti:<\/span><\/p>\n <\/p>\n Per procedere nella creazione del Replica set con self healing<\/strong> \u00e8 innanzi tutto necessario creare un AMI di base per le macchine del replica set con tutti i pacchetti necessari installati: \u00a0AWSCLI, Chrony, Ruby e ovviamente MongoDB (master e client) nella versione desiderata<\/a>\u00a0\u00e8 inoltre necessario istallare il CodeDeploy agent.<\/strong><\/a><\/span><\/p>\n Per configurare il replica set \u00e8 necessario creare un keyfile<\/strong> che deve essere presente su tutte le macchine cluster e che mongo utilizza per autenticare le connessioni dell\u2019 heartbeat. Il file deve contenere caratteri alfanumerici generati in modo pseudo-random e pu\u00f2 essere creato col comando <\/span><\/p>\n Il keyfile \u00e8 una forma minimale di sicurezza ed \u00e8 accettabile solo su una rete sicura (subnet private in VPC), per l\u2019ambiente di produzione \u00e8 comunque preferibile usare un certificato x.509. Il file di configurazione di MongoDB sar\u00e0 simile al seguente:<\/span><\/p>\n La creazione iniziale del cluster MongoDB pu\u00f2 essere completamente automatizzata usando CloudFormation<\/strong>, oppure pu\u00f2 essere eseguita manualmente utilizzando l\u2019ami appena creata e uno script di configurazione da eseguire sulle singole macchine del cluster.<\/span><\/p>\n Una delle macchine va configurata inizialmente per essere il master e inizializzare il Replica Set. Per fare ci\u00f2 \u00e8 necessario prima avviare Mongo senza i campi security e replication nel file di configurazione e poi creare un utente admin col comando:<\/span><\/p>\n A questo punto Mongo va riavviato col file di configurazione contenente security e replication. <\/span><\/p>\n Dopo aver acceso anche le altre macchine, che inizialmente saranno repliche, \u00e8 necessario creare degli A name<\/em> su una private hosted zone di R53 per tutte le macchine del replica set. Nelle configurazioni della VPC \u00e8 inoltre necessario selezionare le opzioni enableDnsHostnames e enableDnsSupport per attivare la risoluzione dei DNS interni di R53.<\/span><\/p>\n Fatto ci\u00f2 \u00e8 finalmente possibile connettersi in SSH al master e tramite la cli di mongo attivare il replica set col comando:<\/span><\/p>\n Ora\u00a0che il Replica Set \u00e8 configurato e funzionante \u00e8 giunto il momento di occuparci della parte di self healing.\n
\n
Creazione del Replica Set<\/span><\/h2>\n
openssl rand -base64 756 > <path-to-keyfile><\/span>\r\nchmod 400 <path-to-keyfile><\/span><\/pre>\n
storage:<\/span>\r\n \u00a0dbPath: \/mnt\/mongo\/data<\/span>\r\n \u00a0journal:<\/span>\r\n \u00a0\u00a0\u00a0enabled: true<\/span>\r\n\r\nsystemLog:<\/span>\r\n \u00a0destination: file<\/span>\r\n \u00a0logAppend: true<\/span>\r\n \u00a0path: <logs-path><\/span>\r\n\r\nsecurity:<\/span>\r\n \u00a0keyFile: <keyfile-path>\r\n<\/span>\r\nreplication:<\/span>\r\n \u00a0replSetName: test-rs<\/span>\r\n\r\nnet:<\/span>\r\n \u00a0port: 27017<\/span>\r\n \u00a0bindIpAll: true<\/span><\/pre>\n
db.createUser({user: \"<ADMIN_USER>\", pwd: \"<PWD>\", roles:[{role: \"root\", db: \"admin\"}]});<\/span><\/pre>\n
rs.initiate( {<\/span>\r\n \u00a0\u00a0_id : \"test-mongo-rs\",<\/span>\r\n \u00a0\u00a0members: [<\/span>\r\n \u00a0\u00a0\u00a0\u00a0\u00a0{ _id: 0, host: \"mongodb-1.test.it:27017\" },<\/span>\r\n \u00a0\u00a0\u00a0\u00a0\u00a0{ _id: 1, host: \"mongodb-2.test.it:27017\" },<\/span>\r\n \u00a0\u00a0\u00a0\u00a0\u00a0{ _id: 2, host: \"mongodb-3.test.it:27017\" }<\/span>\r\n \u00a0\u00a0]<\/span>\r\n});<\/span>\r\n<\/pre>\n
\n<\/span><\/p>\nSet up del Self Healing<\/span><\/h2>\n