MongoDB 에서 insert 는 insertOne, insertMany 를 사용하는데 insertMany 테스트 

insertMany는 트랜잭션을 보장하지 않는다. insert 하다 에러가 발생하면 중단되고 그전에 insert 된것은 입력된 상태.

updateMany, deleteMany 도 동일할듯 

# 테스트용 test 컬렉션 생성 
test> db.test.insertOne({"name":"user1", "age":20})
{
  acknowledged: true,
  insertedId: ObjectId("61f52e50260badd9f57f3a1f")
}
# name 컬럼에 유니크 인덱스 생성 
test> db.test.createIndex(
...     {"name":1},
...     {unique: true}
... );
name_1

# insertMany 로 name: user2, user1 을 넣을 경우
test> to_insert = [
...      {"name":"user2", "age":19},
...      {"name":"user1", "age":20}
... ]
[ { name: 'user2', age: 19 }, { name: 'user1', age: 20 } ]

# 오류 발생 
test> db.test.insertMany(to_insert)
Uncaught:
MongoBulkWriteError: E11000 duplicate key error collection: test.test index: name_1 dup key: { name: "user1" }
Result: BulkWriteResult {
  result: {
    ok: 1,
    writeErrors: [
      WriteError {
        err: {
          index: 1,
          code: 11000,
          errmsg: 'E11000 duplicate key error collection: test.test index: name_1 dup key: { name: "user1" }',
          errInfo: undefined,
          op: {
            name: 'user1',
            age: 20,
            _id: ObjectId("61f52f4b260badd9f57f3a23")
          }
        }
      }
    ],
    writeConcernErrors: [],
    insertedIds: [
      { index: 0, _id: ObjectId("61f52f4b260badd9f57f3a22") },
      { index: 1, _id: ObjectId("61f52f4b260badd9f57f3a23") }
    ],
    nInserted: 1,
    nUpserted: 0,
    nMatched: 0,
    nModified: 0,
    nRemoved: 0,
    upserted: []
  }
}

# 먼저 입력된 name: user2 는 입력되고 name: user1 은 유니크 인덱스 오류로 입력 안됨 
test> db.test.find()
[
  { _id: ObjectId("61f52e50260badd9f57f3a1f"), name: 'user1', age: 20 },
  { _id: ObjectId("61f52f4b260badd9f57f3a22"), name: 'user2', age: 19 }
]

# name: user1, user2 순서로 입력하면 어떻게 될지 궁금해서 name:user2 를 삭제 
test> db.test.deleteMany({"name":"user2"})
{ acknowledged: true, deletedCount: 1 }
test> db.test.find()
[
  { _id: ObjectId("61f52e50260badd9f57f3a1f"), name: 'user1', age: 20 }
]

# name: user1, user2 순서로 입력
test> to_insert = [
...     {"name":"user1", "age":20}, 
...     {"name":"user2", "age":19}
... ]
[ { name: 'user1', age: 20 }, { name: 'user2', age: 19 } ]

# 유니크 인덱스 중복으로 오류 발생 
test> db.test.insertMany(to_insert)
Uncaught:
MongoBulkWriteError: E11000 duplicate key error collection: test.test index: name_1 dup key: { name: "user1" }
Result: BulkWriteResult {
  result: {
    ok: 1,
    writeErrors: [
      WriteError {
        err: {
          index: 0,
          code: 11000,
          errmsg: 'E11000 duplicate key error collection: test.test index: name_1 dup key: { name: "user1" }',
          errInfo: undefined,
          op: {
            name: 'user1',
            age: 20,
            _id: ObjectId("61f52f02260badd9f57f3a20")
          }
        }
      }
    ],
    writeConcernErrors: [],
    insertedIds: [
      { index: 0, _id: ObjectId("61f52f02260badd9f57f3a20") },
      { index: 1, _id: ObjectId("61f52f02260badd9f57f3a21") }
    ],
    nInserted: 0,
    nUpserted: 0,
    nMatched: 0,
    nModified: 0,
    nRemoved: 0,
    upserted: []
  }
}

# 입력 처리가 되지 않았다. 
test> db.test.find()
[
  { _id: ObjectId("61f52e50260badd9f57f3a1f"), name: 'user1', age: 20 }
]

 

 

 

 

OPS Manager를 쓸수 있으면 좋겠지만.. 라이센스 이슈로 사용하지 못할때 사용할만한 모니터링 솔루션!

Percona Monitoring and Management (PMM)

구성 계획

- OS : CentOS 8

- PMM Server : 192.168.137.100

- PMM Client : 192.168.137.21, 호스트명 mongodb 

 

PMM Server 설치 

참고 : https://www.percona.com/doc/percona-monitoring-and-management/2.x/index.html

# yum-config-manager 사용하기 위해 yum-utils설치 
sudo yum -y install yum-utils

# 레포지토리 설치
sudo --add-repo https://download.docker.com/linux/centos/docker-ce.repo
 
# Docker 설치 및 구동 
sudo yum -y install docker-ce
sudo usermod -aG docker $USER
sudo systemctl enable docker
sudo systemctl start docker

# 이미지 받아오기
docker pull percona/pmm-server:2

# 영구 데이터 컨테이너 생성 
docker create --volume /srv \
--name pmm-data \
percona/pmm-server:2 /bin/true

# PMM 서버 시작
docker run --detach --restart always \
--publish 443:443 \
--volumes-from pmm-data \
--name pmm-server \
percona/pmm-server:2

- 브라우저로  admin/admin 으로 로그인 
https://192.168.137.100/graph/login

 

PMM Client 설치 

참고 : https://www.percona.com/doc/percona-monitoring-and-management/2.x/setting-up/client/index.html

# PMM Client 설치 
sudo yum -y install https://repo.percona.com/yum/percona-release-latest.noarch.rpm
sudo yum -y install pmm2-client

# PMM Server 에 Client 등록 
sudo pmm-admin config --server-insecure-tls --server-url=https://admin:admin@192.168.137.100:443 192.168.137.21 generic mongodb

# MongoDB에 DB 모니터링 계정 생성 
db.getSiblingDB("admin").createRole({
    role: "explainRole",
    privileges: [{
        resource: {
            db: "",
            collection: ""
            },
        actions: [
            "listIndexes",
            "listCollections",
            "dbStats",
            "dbHash",
            "collStats",
            "find"
            ]
        }],
    roles:[]
})

db.getSiblingDB("admin").createUser({
   user: "pmm_mongodb",
   pwd: "password",
   roles: [
      { role: "explainRole", db: "admin" },
      { role: "clusterMonitor", db: "admin" },
      { role: "read", db: "local" }
   ]
})

# PMM Server 에 MongoDB 등록 
sudo pmm-admin add mongodb --username=pmm_mongodb --password=password --service-name=mongodb --host=127.0.0.1 --port=27017

 

EMail 알람 설정

참고 : https://www.percona.com/blog/2020/07/07/enable-email-sending-in-percona-monitoring-and-management-2/

# pmm-server 컨테이너 접속 
sudo docker exec -it pmm-server bash
# pmm-server 컨테이너의 /etc/grafana/grafana.ini 파일에 email 서버 설정 
vi /etc/grafana/grafana.ini
[smtp]
enabled = true
host = smtp.gmail.com:587
user = <gmail username>
password = <gmail password>
;cert_file =
;key_file =
skip_verify = false
from_address = <gmail email address>
;from_name = Grafana
;EHLO identity in SMTP dialog (defaults to instance_name)
;ehlo_identity = dashboard.example.com
[emails]
;welcome_email_on_sign_up = false
# pmm-server 컨테이너에서 빠져나온다.
exit

# pmm-server 컨테이너 재기동
sudo docker restart pmm-server

# 컨테이너 생성시에 email 서버를 지정하는 경우 
sudo docker run -d -p 80:80 -p 443:443 --volumes-from pmm-data --name pmm-server \
--restart always \
-e GF_SMTP_ENABLED=true \
-e GF_SMTP_HOST=smtp.gmail.com:587 \
-e GF_SMTP_USER=<gmail username> \
-e GF_SMTP_PASSWORD=<gmail password> \
-e GF_SMTP_SKIP_VERIFY=false \
-e GF_SMTP_FROM_ADDRESS=<gmail email address> \
-e GF_SMTP_FROM_NAME=Grafana \
percona/pmm-server:2

 

- google 의 smtp 를 사용하려면 Google 계정 관리 -> 보안 -> 보안 수준이 낮은 앱의 액세스를 허용으로 변경해야한다. 

 

- grafana 의 Alterting -> Notification channels 설정 후 "Test" 버튼을 클릭하면 테스트 메일이 발송된다.

'MongoDB' 카테고리의 다른 글

insertMany  (0) 2022.01.29
네이버의 MongoDB 활용 사례  (0) 2021.05.20
작은 컬렉션에서 슬로우 쿼리가 발생할때  (0) 2021.05.14

 

데이터 건수 130건 정도에 작은 컬렉션에서 슬로우 쿼리가 발생한다. 

db.컬렉션.find() 만 해도 1800ms 가 나온다. 

열심 찾아보니 repairDatabase를 하던지 compact를 하란다. 

먼저 compact 시도... 동일하다. 

그래 repairDatabase 를 하자

 

rs.printReplicationInfo()로 db.repairDatabase() 하고 그동안의 변경분을 oplog 에서 받아오는데

문제가 없을지 공간 확인을 한다. 

 

Replica Set을 구성하는 노드들을 한대를 shutdown 하고 Conf 파일에서 Replica Set 구성 부분을 주석처리하고

Standalone 으로 구동! 

해당 컬렉션이 있는 DB에서 db.repairDatabase() 를 실행하고 완료되면 Conf 파일에서 주석처리 했던 부분을 해제하고

Replica Set의 맴버로 구동해서 SECONDARY 로 올라오는지 확인한다.

(PRIMARY 에서 rs.status()로 resync 완료후 SECONDARY 로 올라왔는지 확인)

이 과정을 한대씩 다른 노드들에서 실행한다. 

 

마지막으로 PRIMARY에 접속해 rs.stepDown() 을 실행!

SECONDARY 가 PRIMARY 로 승격되는것을 확인하고 Shutdown 후 db.repairDatabase()를 실행 후 Replica Set의 맴버로 구동한다. 

 

이후 해당 증상 해결 정확한 원인을 알수 없어서 아쉽지만 해결!

 

점검 잡고 하면 좋겠지만 그게 안되면, 운영중에 어느정도 리스크를 감안하고 진행!

 

'MongoDB' 카테고리의 다른 글

insertMany  (0) 2022.01.29
Percona Monitoring and Management - MongoDB  (0) 2021.12.19
네이버의 MongoDB 활용 사례  (0) 2021.05.20

+ Recent posts