VK Cloud logo

MongoDB репликациясы және Ubuntu жүйесінде жаңарту

Бұл мақалада Ubuntu 18.04 жүйесінде MongoDB-ді қалай репликациялау және жаңарту керектігін қарастырамыз.

MongoDB ReplicaSet баптауы

Replicaset  — бұл бірдей деректер жиынын қамтитын, ақаулардан қорғанысты және деректердің жоғары қолжетімділігін қамтамасыз ететін бірнеше сервер. MongoDB  Replicaset ішінде  жазу мен оқу үшін бір primary түйіні және primary түйінімен синхрондалған әрі жүктемені азайту үшін деректерді оқу мүмкіндігін беретін бір немесе бірнеше secondary түйіндері болады. Primary түйіні істен шыққан жағдайда, secondary түйіндерінің бірі автоматты түрде primary түйіні болып тағайындалады. Жаңа primary түйінін таңдауды жеделдету үшін деректерді қамтымайтын арбитр түйіні арналған. Сонымен қатар, Replicaset  артықшылықтарының бірі — кластердің жұмысын тоқтатпай жаңарту мүмкіндігі.

  1. Барлық үш серверде 27017 порты ашық екеніне көз жеткізіңіз.
  2. Әр хосттың атауы (mongo1.testdomain.com, mongo2.testdomain.com, mongoar.testdomain.com) әр серверде белгілі екеніне көз жеткізіңіз. Егер атаулар DNS ішінде көрсетілмесе, әр серверде оларды /еtc/hosts файлына жазыңыз. Біздің жағдайда:
10.0.0.2 mongo1 mongo1.testdomain.com10.0.0.3 mongo2 mongo2.testdomain.com10.0.0.4 mongoar mongoar.testdomain.com
  1. /etc/mongod.conf конфигурациялық файлының replication секциясына келесіні қосыңыз:
replication:    replSetName: "rs0"security:    authorization: enabled    clusterAuthMode: x509    clusterIpSourceWhitelist:    - 10.0.0.2    - 10.0.0.3    - 10.0.0.4    - 127.0.0.1
  1. mongod қызметін қайта іске қосыңыз:
root@mongo1:~# systemctl restart mongod.service
  1. mongo консоліне кіріп, команданы орындаңыз:
\> rs.initiate(){    "info2" : "no configuration specified. Using a default configuration for the set",    "me" : "mongo1:27017",    "ok" : 1}rs0:SECONDARY>rs0:PRIMARY>

Replicaset инициализацияланды, түйін primary күйінде тұр.

  1. Конфигурациялық файлдағы host айнымалысында mongo1:27017 мәнінің орнына сертификаттың CommonName мәнін көрсетіңіз:
rs0:PRIMARY> cfg.members[0].host = "mongo1.testdomain.com:27017"mongo1.testdomain.com:27017rs0:PRIMARY> rs.reconfig(cfg){    "ok" : 1,    "operationTime" : Timestamp(1577365311, 1),    "$clusterTime" : {        "clusterTime" : Timestamp(1577365311, 1),        "signature" : {            "hash" : BinData(0,"4b6xDb/6y5tuq9jDjEDjbscYmGk="),            "keyId" : NumberLong("6774685910094053378")        }    }}rs0:PRIMARY>
  1. mongo2 серверінде авторизациядан өтіңіз, MongoDB репозиторийінің кілтін импорттаңыз, MongoDB репозиторийін қосыңыз және MongoDB-ді орнатыңыз (мұны қалай жасау керектігін Ubuntu жүйесінде MongoDB орнату және баптау мақаласынан оқыңыз).
  2. Егер /etc/hosts файлын mongo1 серверінде өзгерткен болсаңыз, ағымдағы серверде де соны қайталаңыз.
  3. mongo1 серверінен /etc/mongod.conf конфигурациялық файлын ағымдағы серверге көшіріңіз, файлда PEMKeyFile: кілтінің атауын /etc/ssl/mongo1.pem мәнінен PEMKeyFile: /etc/ssl/mongo2.pem мәніне ауыстырыңыз.
  4. Ағымдағы серверге /etc/ssl/mongoCA.pem кілтін көшіріңіз.
  5. mongo1 серверіндегідей сервер сертификатын шығарыңыз, бұл ретте CommonName ретінде mongo2.testdomain.com қолданыңыз:
root@mongo2:~# openssl genrsa -out /tmp/mongo2.key 4096root@mongo2:~# openssl req -new -key /tmp/mongo2.key -out /tmp/mongo2.csr...Common Name (e.g. server FQDN or YOUR name) []:mongo2.testdomain.com...root@mongo2:~# openssl x509 -req -in /tmp/mongo2.csr -CA /etc/ssl/mongoCA.pem -CAcreateserial -out /tmp/mongo2.crt -days 10000root@mongo2:~# cat /tmp/mongo2.key /tmp/mongo2.crt > /etc/ssl/mongo2.pemroot@mongo2:~# rm /tmp/mongo2.key /tmp/mongo2.crt /tmp/mongo2.csr
  1. Егер var/lib/mongodb директориясы бос болмаса, оның ішіндегі барлық файлдарды жойыңыз.
  2. mongod серверін қайта іске қосыңыз және оны автоматты түрде жүктелетін қолданбалар тізіміне қосыңыз.
  3. mongo1 серверіне кіріп, mongo консоліне өтіңіз.
  4. mongo2 серверін replicaset құрамына қосыңыз:
root@mongo1:~# mongo --ssl --sslPEMKeyFile /etc/ssl/client.pem --sslCAFile /etc/ssl/mongoCA.pem  --host mongo1.testdomain.com -u adminMongoDB shell version v4.0.14Enter password:connecting to: mongodb://mongo1.testdomain.com:27017/?gssapiServiceName=mongodbImplicit session: session { "id" : UUID("7a4087c2-470c-48ce-8c8d-af10fb4aa9a7") }MongoDB server version: 4.0.14rs0:PRIMARY> rs.add({ host: "mongo2.testdomain.com:27017" }){    "ok" : 1,    "operationTime" : Timestamp(1577364817, 1),    "$clusterTime" : {        "clusterTime" : Timestamp(1577364817, 1),        "signature" : {            "hash" : BinData(0,"t5nfdP1DMgNaAcUsvYXy2luwNvg="),            "keyId" : NumberLong("6774685910094053378")        }    }}rs0:PRIMARY>
  1. replicaset күйін тексеріңіз:
rs0:PRIMARY> rs.status(){    "set" : "rs0",    "date" : ISODate("2019-12-26T13:06:09.455Z"),    "myState" : 1,    "term" : NumberLong(5),    "syncingTo" : "",    "syncSourceHost" : "",    "syncSourceId" : -1,    "heartbeatIntervalMillis" : NumberLong(2000),    "optimes" : {        "lastCommittedOpTime" : {            "ts" : Timestamp(1577365562, 1),            "t" : NumberLong(5)        },        "readConcernMajorityOpTime" : {            "ts" : Timestamp(1577365562, 1),            "t" : NumberLong(5)        },        "appliedOpTime" : {            "ts" : Timestamp(1577365562, 1),            "t" : NumberLong(5)        },        "durableOpTime" : {            "ts" : Timestamp(1577365562, 1),            "t" : NumberLong(5)        }    },    "lastStableCheckpointTimestamp" : Timestamp(1577365562, 1),    "electionCandidateMetrics" : {        "lastElectionReason" : "electionTimeout",        "lastElectionDate" : ISODate("2019-12-26T12:30:20.224Z"),        "electionTerm" : NumberLong(5),        "lastCommittedOpTimeAtElection" : {            "ts" : Timestamp(0, 0),            "t" : NumberLong(-1)        },        "lastSeenOpTimeAtElection" : {            "ts" : Timestamp(1577363413, 1),            "t" : NumberLong(4)    },    "numVotesNeeded" : 1,    "priorityAtElection" : 1,    "electionTimeoutMillis" : NumberLong(10000),    "newTermStartDate" : ISODate("2019-12-26T12:30:22.224Z"),    "wMajorityWriteAvailabilityDate" : ISODate("2019-12-26T12:30:22.358Z")    },    "members" : [        {            "_id" : 0,            "name" : "mongo1.testdomain.com:27017",            "health" : 1,            "state" : 1,            "stateStr" : "PRIMARY",            "uptime" : 2154,            "optime" : {                "ts" : Timestamp(1577365562, 1),                "t" : NumberLong(5)        },        "optimeDate" : ISODate("2019-12-26T13:06:02Z"),        "syncingTo" : "",        "syncSourceHost" : "",        "syncSourceId" : -1,        "infoMessage" : "",        "electionTime" : Timestamp(1577363420, 1),        "electionDate" : ISODate("2019-12-26T12:30:20Z"),        "configVersion" : 70500,        "self" : true,        "lastHeartbeatMessage" : ""    },    {        "_id" : 1,        "name" : "mongo2.testdomain.com:27017",        "health" : 1,        "state" : 2,        "stateStr" : "SECONDARY",        "uptime" : 26,        "optime" : {            "ts" : Timestamp(1577365562, 1),            "t" : NumberLong(5)    },    "optimeDurable" : {        "ts" : Timestamp(1577365562, 1),"t" : NumberLong(5)},            "optimeDate" : ISODate("2019-12-26T13:06:02Z"),            "optimeDurableDate" : ISODate("2019-12-26T13:06:02Z"),            "lastHeartbeat" : ISODate("2019-12-26T13:06:08.795Z"),            "lastHeartbeatRecv" : ISODate("2019-12-26T13:06:09.139Z"),            "pingMs" : NumberLong(1),            "lastHeartbeatMessage" : "",            "syncingTo" : "mongo1.testdomain.com:27017",            "syncSourceHost" : "mongo1.testdomain.com:27017",            "syncSourceId" : 0,            "infoMessage" : "",            "configVersion" : 70500        }    ],    "ok" : 1,    "operationTime" : Timestamp(1577365562, 1),    "$clusterTime" : {        "clusterTime" : Timestamp(1577365562, 1),        "signature" : {            "hash" : BinData(0,"9Y9LWPudizuTGUP0+M2wMihAFO8="),            "keyId" : NumberLong("6774685910094053378")        }    }}rs0:PRIMARY>

Көріп тұрғанымыздай, _id=1 болатын екінші түйін Repliset құрамына secondary күйінде қабылданды.

Түйінді replicaset құрамына қосқанда primary түйінінен синхрондау жүреді. Синхрондау аяқталғанша, екінші түйін STARTUP күйінде болады. Негізгі түйінге деректер жазу синхрондауды баяулатады, дегенмен бұл мүмкін сценарий (мысалы, көлемі шамамен 350 ГБ болатын базаға жазу кезінде синхрондау шамамен 14 сағатқа созылды).

Синхрондау аяқталғаннан кейін үшінші серверде (mongoar) екінші сервердегідей (mongo2) әрекеттерді орындаңыз, тек серверді repliset құрамына қосу қадамын қоспағанда:

rs0:PRIMARY> rs.addArb("mongoar.testdomain.com:27017"){        "ok" : 1,        "operationTime" : Timestamp(1577366355, 1),        "$clusterTime" : {        "clusterTime" : Timestamp(1577366355, 1),        "signature" : {            "hash" : BinData(0,"pA6zLoq8JmYCFM2HZVAhr4pvK1A="),            "keyId" : NumberLong("6774685910094053378")        }    }}rs0:PRIMARY>

Repliset күйін тексеріңіз (қысқалық үшін шығыстан елеусіз бөлігі алынып тасталды):

rs0:PRIMARY> rs.status(){    "set" : "rs0",    "date" : ISODate("2019-12-26T13:21:20.710Z"),    "myState" : 1,"members" : [            {                "_id" : 0,                "name" : "mongo1.testdomain.com:27017",                "health" : 1,                "state" : 1,                "stateStr" : "PRIMARY",                "uptime" : 3065,            },            {                "_id" : 1,                "name" : "mongo2.testdomain.com:27017",                "health" : 1,                "state" : 2,                "stateStr" : "SECONDARY",                "uptime" : 937,        },        {                "_id" : 2,                "name" : "mongoar.testdomain.com:27017",                "health" : 1,                "state" : 7,                "stateStr" : "ARBITER",                "uptime" : 125,        }}

Нәтижесінде біз primary түйінін, secondary түйінін және arbiter түйінін алдық. Repliset синхрондалған және жұмысқа қабілетті күйде тұр.

MongoDB ReplicaSet жаңарту

Жаңартуды 4.0 нұсқасынан 4.2 нұсқасына көшу мысалында қарастырайық. Ағымдағы деректер сызбасын жұмыс істемейтін күйге әкелуі мүмкін өзгерістерді түсіну үшін құжатпен танысыңыз.

  1. Ағымдағы деректер жиынымен қолдануға болатын MongoDB нұсқасын шектейтін feature compatibility version параметрін өзгертіңіз. 4.0 нұсқасынан 4.2 нұсқасына жаңарту үшін оны 4.0 мәніне орнатыңыз:
rs0:PRIMARY> db.adminCommand( { setFeatureCompatibilityVersion: "4.0" } ){    "ok" : 1,    "operationTime" : Timestamp(1577429084, 1),    "$clusterTime" : {        "clusterTime" : Timestamp(1577429084, 1),        "signature" : {            "hash" : BinData(0,"mL6lecQQeLB8QkjNqrJIGA+ICiY="),            "keyId" : NumberLong("6774685910094053378")        }    }}
  1. Нәтижені тексеріңіз:
rs0:PRIMARY> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } ){        "featureCompatibilityVersion" : {            "version" : "4.0"    },    "ok" : 1,    "operationTime" : Timestamp(1577429094, 1),    "$clusterTime" : {        "clusterTime" : Timestamp(1577429094, 1),        "signature" : {            "hash" : BinData(0,"Mo5HB7K+IVwAivtJ4ZCC4GMKOAk="),            "keyId" : NumberLong("6774685910094053378")    }}
  1. Барлық үш серверде MongoDB-дің жаңа нұсқасы бар репозиторийді қосыңыз (бірінші серверге арналған мысал):
root@mongo1:~# wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add -OKroot@mongo1:~# echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.2.listdeb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.2 multiverseroot@mongo1:~# apt-get update
  1. Құжаттамаға сәйкес /etc/mongod.conf конфигурациялық файлына enableMajorityReadConcern: false опциясын қосыңыз және net:ssl параметрін net:tls параметріне ауыстырыңыз (арбитрге арналған мысал):
net:  port: 27017  bindIp: 0.0.0.0  tls:      mode: requireTLS      certificateKeyFile: /etc/ssl/mongoar.pem      CAFile: /etc/ssl/mongoCA.pemreplication:replSetName: "rs0"enableMajorityReadConcern: false
  1. Арбитр түйінін жаңартыңыз:
root@mongoar:~# systemctl stop mongod.serviceroot@mongoar:~# apt-get install -y mongodb-org mongodb-org-mongos mongodb-org-server mongodb-org-shell mongodb-org-toolsroot@mongoar:~# systemctl start mongod.service
  1. rs.status() күйін тексеріңіз. Арбитрдің жұмыс істеп тұрғанына көз жеткізіңіз және қалған екі түйіннің қайсысы secondary екенін қараңыз (команда шығысы қысқартылған):
rs0:PRIMARY> rs.status(){    "set" : "rs0",    "date" : ISODate("2019-12-27T06:54:13.228Z"),    "myState" : 1,    "term" : NumberLong(6),    "members" : [        {            "_id" : 0,            "name" : "mongo1.testdomain.com:27017",            "health" : 1,            "state" : 1,            "stateStr" : "PRIMARY",        },        {            "_id" : 1,            "name" : "mongo2.testdomain.com:27017",            "health" : 1,            "state" : 2,            "stateStr" : "SECONDARY",        },        {            "_id" : 2,            "name" : "mongoar.testdomain.com:27017",            "health" : 1,            "state" : 7,            "stateStr" : "ARBITER",}
  1. Қазіргі сәтте mongo2 сервері secondary болып тұр, онда MongoDB-ді жаңартыңыз:
root@mongo2:~# systemctl stop mongod.serviceroot@mongo2:~# apt-get install -y mongodb-orgThe following packages will be upgraded:mongodb-orgPreparing to unpack .../mongodb-org_4.2.2_amd64.deb ...Unpacking mongodb-org (4.2.2) over (4.0.14) ...Setting up mongodb-org (4.2.2) ...root@mongo2:~# systemctl start mongod.service
  1. rs.status() командасын қарап, түйіннің жұмыс істеп тұрғанына көз жеткізіңіз:
rs0:PRIMARY> rs.status(){    "set" : "rs0",    "date" : ISODate("2019-12-27T07:08:22.025Z"),    "myState" : 1,"members" : [    {        "_id" : 0,        "name" : "mongo1.testdomain.com:27017",        "health" : 1,        "state" : 1,        "stateStr" : "PRIMARY",    },    {        "_id" : 1,        "name" : "mongo2.testdomain.com:27017",        "health" : 1,        "state" : 2,        "stateStr" : "SECONDARY",    },    {        "_id" : 2,        "name" : "mongoar.testdomain.com:27017",        "health" : 1,        "state" : 7,        "stateStr" : "ARBITER",    }}
  1. primary түйінін күшпен бұрыннан жаңартылған түйінге ауыстырыңыз (біздің жағдайда — mongo2):
rs0:PRIMARY> rs.stepDown()2019-12-27T12:25:10.922+0000 I NETWORK [js] DBClientConnection failed to receive message from mongo1.testdomain.com:27017 - SocketException: stream truncated2019-12-27T12:25:10.923+0000 E QUERY [js] Error: error doing query: failed: network error while attempting to run command 'replSetStepDown' on host 'mongo1.testdomain.com:27017' :DB.prototype.runCommand@src/mongo/shell/db.js:168:1DB.prototype.adminCommand@src/mongo/shell/db.js:186:16rs.stepDown@src/mongo/shell/utils.js:1489:12@(shell):1:12019-12-27T12:25:10.924+0000 I NETWORK [js] trying reconnect to mongo1.testdomain.com:27017 failed2019-12-27T12:25:10.941+0000 I NETWORK [js] reconnect mongo1.testdomain.com:27017 okrs0:SECONDARY>
  1. Енді mongo1 түйіні secondary болды, оны алдыңғысына ұқсас жаңартыңыз.
  2. Жаңартудан кейін replicaset күйін тексеріңіз (шығыс қысқартылған):
rs0:SECONDARY> rs.status(){    "set" : "rs0",    "date" : ISODate("2019-12-27T12:30:03.888Z"),    "myState" : 2,    "term" : NumberLong(6),    "syncingTo" : "mongo2.testdomain.com:27017",    "syncSourceHost" : "mongo2.testdomain.com:27017",    "syncSourceId" : 1,    "heartbeatIntervalMillis" : NumberLong(2000),    "majorityVoteCount" : 2,    "writeMajorityCount" : 2,    "members" : [        {            "_id" : 0,            "name" : "mongo1.testdomain.com:27017",            "ip" : "89.208.223.162",            "health" : 1,            "state" : 2,            "stateStr" : "SECONDARY",        },        {            "_id" : 1,            "name" : "mongo2.testdomain.com:27017",            "ip" : "95.163.212.165",            "health" : 1,            "state" : 1,            "stateStr" : "PRIMARY",        },        {            "_id" : 2,            "name" : "mongoar.testdomain.com:27017",            "ip" : "95.163.215.118",            "health" : 1,            "state" : 7,        "stateStr" : "ARBITER",        }    ],    "ok" : 1,    "$clusterTime" : {        "clusterTime" : Timestamp(1577449801, 1),        "signature" : {            "hash" : BinData(0,"cC03fOHq3hLJX5oorqgTGlDuick="),            "keyId" : NumberLong("6775081949028417537")        }    },    "operationTime" : Timestamp(1577449801, 1)}rs0:SECONDARY>

Барлығы сәтті орындалды. Егер жаңартуға дейінгі түйіндер ретін сақтау қажет болса, ағымдағы primary түйінінің (mongo2) консоліне кіріп, команданы орындаңыз:

rs.stepDown()

Түйін secondary күйіне өтеді, ал primary түйіні жаңартуға дейінгідей mongo1 болады.

Біз жаңартуды кластерді жұмыстан шығармай, яғни жіксіз орындадық.

Жалғыз MongoDB серверін жаңартқан жағдайда feature compatibility version параметрін жаңартыңыз, mongodb жаңа нұсқасы бар репозиторийді қосыңыз, сервердің конфигурациялық файлын түзетіңіз және жоғарыда сипатталғандай mongodb серверін жаңа нұсқаға жаңартыңыз. Бұл жағдайда серверді тоқтату қажет болады.