mongodb使用docker搭建replicaSet集群与变更监听

news2024/10/5 21:20:00

在mongodb如果需要启用变更监听功能(watch),mongodb需要在replicaSet或者cluster方式下运行。

replicaSet和cluster从部署难度相比,replicaSet要简单许多。如果所存储的数据量规模不算太大的情况下,那么使用replicaSet方式部署mongodb是一个不错的选择。

安装环境

mongodb版本:mongodb-6.0.5

两台主机:主机1(192.168.1.11)、主机2(192.168.1.12)

docker方式mongodb集群安装

在主机1和主机2上安装好docker,并确保两台主机能正常通信

目录与key准备

在启动mongodb前,先准备好对应的目录与访问key

#在所有主机都创建用于存储mongodb数据的文件夹
mkdir -p ~/mongo-data/{data,key,backup}
#设置key文件,用于在集群机器间互相访问,各主机的key需要保持一致
cd ~/mongo-data
#在某一节点创建key
openssl rand -base64 123 > key/mongo-rs.key
sudo chown 999 key/mongo-rs.key
#不能是755, 权限太大不行. 
sudo chmod 600 key/mongo-rs.key
#将key复制到他节点
scp key/mongo-rs.key root@192.168.1.12:/root/mongo-data/key

以上操作在各主机中创建了 ~/mongo-data/{data,key,backup} 这3个目录,且mongo-rs.key的内容一致。

运行mongodb

执行下列命令,启动mongodb

sudo docker run --name mongo --network=host -p 27017:27017 -v ~/mongo-data/data:/data/db -v ~/mongo-data/backup:/data/backup -v ~/mongo-data/key:/data/key -v /etc/localtime:/etc/localtime -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=123456 -d mongo:6.0.5 --replSet haiyangReplset --auth --keyFile /data/key/mongo-rs.key --bind_ip_all

上面主要将27017端口映射到主机中,并设了admin的默认密码为123456。
–replSet为指定开启replicaSet,后面跟的为副本集的名称。

配置节点

进入某一节点,进行集群配置

sudo docker exec -it mongo bash
mongosh

初始化集群前先登录验证超级管理员admin

use admin
db.auth(“admin”,“123456”)

再执行以下命令进行初始化

var config={
     _id:"haiyangReplset",
     members:[
         {_id:0,host:"192.168.1.11:27017"},
         {_id:1,host:"192.168.1.12:27017"},
]};
rs.initiate(config)

执行成功后,可以看到一个节点为主节点,另一个节点为从节点

mongosh

其他相关命令

#查看副本集状态
rs.status()
#查看副本集配置
rs.conf()
#添加节点
rs.add( { host: "ip:port"} )
#删除节点
rs.remove('ip:port')

官方客户端验证

在mongodb安装好后,再用客户端连接验证一下。
官方mongodb的客户端下载地址为:https://www.mongodb.com/try/download/compass

下载完毕后,在客户端中新建连接。
在本例中,则mongodb的连接地址为:

mongodb://admin:123456@192.168.1.11:27017,192.168.1.12:27017/?authMechanism=DEFAULT&authSource=admin&replicaSet=haiyangReplset

mongo-compass

库与监控信息一目了然~

变更监听

对于mongodb操作的api在mongodb的官网有比较完备的文档,java的文档连接为:https://www.mongodb.com/docs/drivers/java/sync/v4.9/

这里试一下mongodb中一个比较强悍的功能,记录的变更监听。
用这项功能来做一些审计的场景则会非常方便。

官方链接为:
https://www.mongodb.com/docs/drivers/java/sync/v4.9/usage-examples/watch/

这里以java客户端为例写个小demo,试一下对于mongodb中集合的创建及watch功能。

package io.github.puhaiyang;

import com.google.common.collect.Lists;
import com.mongodb.client.*;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Scanner;
import java.util.concurrent.CompletableFuture;

/**
 * @author puhaiyang
 * @since 2023/3/30 20:01
 * MongodbWatchTestMain
 */
public class MongodbWatchTestMain {

    public static void main(String[] args) throws Exception {
        String uri = "mongodb://admin:123456@192.168.1.11:27017,192.168.1.12:27017/?replicaSet=haiyangReplset";
        MongoClient mongoClient = MongoClients.create(uri);
        MongoDatabase mongoDatabase = mongoClient.getDatabase("my-test-db");
        String myTestCollectionName = "myTestCollection";
        //获取出collection
        MongoCollection<Document> mongoCollection = initCollection(mongoDatabase, myTestCollectionName);
        //进行watch
        CompletableFuture.runAsync(() -> {
            while (true) {
                List<Bson> pipeline = Lists.newArrayList(
                        Aggregates.match(Filters.in("ns.coll", myTestCollectionName)),
                        Aggregates.match(Filters.in("operationType", Arrays.asList("insert", "update", "replace", "delete")))
                );
                ChangeStreamIterable<Document> changeStream = mongoDatabase.watch(pipeline)
                        .fullDocument(FullDocument.UPDATE_LOOKUP)
                        .fullDocumentBeforeChange(FullDocumentBeforeChange.WHEN_AVAILABLE);

                changeStream.forEach(event -> {
                    String collectionName = Objects.requireNonNull(event.getNamespace()).getCollectionName();
                    System.out.println("--------> event:" + event.toString());
                });
            }
        });

        //数据变更测试
        {
            Thread.sleep(3_000);
            InsertOneResult insertResult = mongoCollection.insertOne(new Document("test", "sample movie document"));
            System.out.println("Success! Inserted document id: " + insertResult.getInsertedId());
            UpdateResult updateResult = mongoCollection.updateOne(new Document("test", "sample movie document"), Updates.set("field2", "sample movie document update"));
            System.out.println("Updated " + updateResult.getModifiedCount() + " document.");
            DeleteResult deleteResult = mongoCollection.deleteOne(new Document("field2", "sample movie document update"));
            System.out.println("Deleted " + deleteResult.getDeletedCount() + " document.");
        }

        new Scanner(System.in).next();
    }

    private static MongoCollection<Document> initCollection(MongoDatabase mongoDatabase, String myTestCollectionName) {
        ArrayList<Document> existsCollections = mongoDatabase.listCollections().into(new ArrayList<>());
        Optional<Document> existsCollInfoOpl = existsCollections.stream().filter(doc -> StringUtils.equals(myTestCollectionName, doc.getString("name"))).findFirst();
        existsCollInfoOpl.ifPresent(collInfo -> {
            //确保开启了changeStreamPreAndPost
            Document changeStreamPreAndPostImagesEnable = collInfo.get("options", Document.class).get("changeStreamPreAndPostImages", Document.class);
            if (changeStreamPreAndPostImagesEnable != null && !changeStreamPreAndPostImagesEnable.getBoolean("enabled")) {
                Document mod = new Document();
                mod.put("collMod", myTestCollectionName);
                mod.put("changeStreamPreAndPostImages", new Document("enabled", true));
                mongoDatabase.runCommand(mod);
            }
        });
        if (!existsCollInfoOpl.isPresent()) {
            CreateCollectionOptions collectionOptions = new CreateCollectionOptions();
            //创建collection时开启ChangeStreamPreAndPostImages
            collectionOptions.changeStreamPreAndPostImagesOptions(new ChangeStreamPreAndPostImagesOptions(true));
            mongoDatabase.createCollection(myTestCollectionName, collectionOptions);
        }
        return mongoDatabase.getCollection(myTestCollectionName);
    }
}

输出结果如下:

--------> event:ChangeStreamDocument{ operationType=insert, resumeToken={"_data": "8264255A0F000000022B022C0100296E5A10046A3E3757D6A64DF59E6D94DC56A9210446645F6964006464255A105A91F005CFB2E6D20004"}, namespace=my-test-db.myTestCollection, destinationNamespace=null, fullDocument=Document{{_id=64255a105a91f005cfb2e6d2, test=sample movie document}}, fullDocumentBeforeChange=null, documentKey={"_id": {"$oid": "64255a105a91f005cfb2e6d2"}}, clusterTime=Timestamp{value=7216272998402097154, seconds=1680169487, inc=2}, updateDescription=null, txnNumber=null, lsid=null, wallTime=BsonDateTime{value=1680169487686}}
Success! Inserted document id: BsonObjectId{value=64255a105a91f005cfb2e6d2}
Updated 1 document.
--------> event:ChangeStreamDocument{ operationType=update, resumeToken={"_data": "8264255A0F000000032B022C0100296E5A10046A3E3757D6A64DF59E6D94DC56A9210446645F6964006464255A105A91F005CFB2E6D20004"}, namespace=my-test-db.myTestCollection, destinationNamespace=null, fullDocument=Document{{_id=64255a105a91f005cfb2e6d2, test=sample movie document, field2=sample movie document update}}, fullDocumentBeforeChange=Document{{_id=64255a105a91f005cfb2e6d2, test=sample movie document}}, documentKey={"_id": {"$oid": "64255a105a91f005cfb2e6d2"}}, clusterTime=Timestamp{value=7216272998402097155, seconds=1680169487, inc=3}, updateDescription=UpdateDescription{removedFields=[], updatedFields={"field2": "sample movie document update"}, truncatedArrays=[], disambiguatedPaths=null}, txnNumber=null, lsid=null, wallTime=BsonDateTime{value=1680169487708}}
--------> event:ChangeStreamDocument{ operationType=delete, resumeToken={"_data": "8264255A0F000000042B022C0100296E5A10046A3E3757D6A64DF59E6D94DC56A9210446645F6964006464255A105A91F005CFB2E6D20004"}, namespace=my-test-db.myTestCollection, destinationNamespace=null, fullDocument=null, fullDocumentBeforeChange=Document{{_id=64255a105a91f005cfb2e6d2, test=sample movie document, field2=sample movie document update}}, documentKey={"_id": {"$oid": "64255a105a91f005cfb2e6d2"}}, clusterTime=Timestamp{value=7216272998402097156, seconds=1680169487, inc=4}, updateDescription=null, txnNumber=null, lsid=null, wallTime=BsonDateTime{value=1680169487721}}
Deleted 1 document.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/421154.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

凹凸/法线/移位贴图的区别

你是否在掌握 3D 资产纹理的道路上遇到过障碍&#xff1f; 不要难过&#xff01; 许多刚接触纹理或 3D 的艺术家在第一次遇到凹凸贴图&#xff08;Bump Map&#xff09;、法线贴图&#xff08;Normal Map&#xff09;和移位贴图&#xff08;Displacement Map&#xff09;时通常…

Linux Redis主从复制 | 哨兵监控模式 | 集群搭建 | 超详细

Linux Redis主从复制 | 哨兵监控模式 | 集群搭建 | 超详细一 Redis的主从复制二 主从复制的作用三 主从复制的流程四 主从复制实验4.1 环境部署4.2 安装Redis&#xff08;主从服务器&#xff09;4.3 修改Master节点Redis配置文件 (192.168.163.100)4.4 修改Slave节点Redis配置文…

MySQL-用户与权限

目录 &#x1f341;DB权限表 &#x1f341;新建普通用户 &#x1f342;创建新用户(create user) &#x1f342;创建新用户(grant) &#x1f341;删除普通用户 &#x1f341;修改用户密码 &#x1f342;Root用户修改自己的密码 &#x1f342;Root用户修改普通用户密码 &#x1f…

区块链概论

目录 1.概述 2.密码学原理 2.1.hash函数 2.2.签名 3.数据结构 3.1.区块结构 3.2.hash pointer 3.3.merkle tree 3.3.1.概述 3.3.2.证明数据存在 3.3.3.证明数据不存在 4.比特币的共识协议 4.1.概述 4.2.验证有效性 4.2.1.验证交易有效性 4.2.2.验证节点有效性 …

~~~~~不得不会的账号与权限管理小知识

目录一.用户账号和组账号概述二. useradd添加用户账号三. passwd 修改密码四. 修改用户账户的属性五 . userdel 删除用户账号六. 用户账号的初始配置文件七. 组账号文件八 . 文件/目录的权限及归属8.1设置文件和目录的权限chmod8.2 设置文件和目录的归属chown命令8.3 补充扩展:…

JAVA本地监听与远程端口扫描的设计与开发

随着Internet的不断发展&#xff0c;信息技术已成为社会进步的巨大推动力。不管是存储于服务器里还是流通于Internet上的信息都已成为一个关系事业成败的关键&#xff0c;这就使保证信息的安全变得格外重要。本地监听与远程端口扫描程序就是在基于Internet的端口扫描的基础上&a…

Optional类快速上手

目录 一、概述 二、使用 1、创建对象 2、安全消费值 3、安全获取值 4、过滤 5、判断 6、数据转换 一、概述 我们在编码的时出现最多的就是空指针异常&#xff0c;所以在很多情况下我们需要做各种非空的判断。 尤其是对象中的属性还是一个对象的情况下&#xff0c;这种…

Doris(3):创建用户与创建数据库并赋予权限

Doris 采用 MySQL 协议进行通信&#xff0c;用户可通过 MySQL client 或者 MySQL JDBC连接到 Doris 集群。选择 MySQL client 版本时建议采用5.1 之后的版本&#xff0c;因为 5.1 之前不能支持长度超过 16 个字符的用户名。 1 创建用户 Root 用户登录与密码修改 Doris 内置 ro…

从C出发 19 --- 函数定义细节剖析

因为编译器是自上而下执行代码的&#xff0c;当编译到 paw2 的时候不知道是什么东西&#xff0c;看起来像一个函数但是前面的代码没有发现它&#xff0c;这个时候编译器就会报错 为了防止编译器报错 应该在调用前先声明 &#xff0c;注意声明的三要素 声明的作用: 让编译器先…

# 切削加工形貌的相关论文阅读【1】-球头铣刀铣削球面的表面形貌建模与仿真研究

切削加工形貌论文【1】-球头铣刀铣削球面的表面形貌建模与仿真研究1. 论文【2】-球头铣刀加工表面形貌建模与仿真1.1 切削加工形貌仿真-考虑的切削参数1.2 其他试验条件1.3 主要研究目的1.4 试验与分析结果1.5 面粗糙度的评价指标2. 论文【1】-球头铣刀加工球面&#xff08;曲面…

Flutter Row 实例 —— 新手礼包

大家好&#xff0c;我是 17。 本文在 3.31 日全站综合热榜第一。 新手礼包一共 3 篇文章&#xff0c;每篇都是描述尽量详细&#xff0c;实例讲解&#xff0c;包会&#xff01; Flutter Row 实例 —— 新手礼包Flutter TextField UI 实例 —— 新手礼包Flutter TextField 交…

CDN如何成为大站标配?

在当下的互联网应用中充斥了大量的静态内容&#xff0c;这些静态和准动态内容在访问请求中占据了大量的网络资源&#xff0c;如果这些请求全部指向源站服务器&#xff0c;很容易导致网络的拥塞甚至是服务器的宕机&#xff0c;对正常的业务开展造成严重影响。为了解决这种情况&a…

共享电子邮件的运作方式

通过电子邮件共享&#xff0c;您可以使用评论轻松管理围绕电子邮件展开的讨论&#xff0c;而无需多次转发和回复。这提供了一种轻松的方式&#xff0c;让您可以通过电子邮件与同事分享信息&#xff0c;并获得他们对此的意见/反馈/建议。 电子邮件共享的运作方式 您收到或发送的…

开源流媒体服务器ZLMediaKit在Windows上运行、配置、按需拉流拉取摄像头rtsp视频流)并使用http-flv网页播放

场景 目前市面上有很多开源的流媒体服务器解决方案&#xff0c;常见的有SRS、EasyDarwin、ZLMediaKit和Monibuca等。 1、SRS GitHub - ossrs/srs: SRS is a simple, high efficiency and realtime video server, supports RTMP, WebRTC, HLS, HTTP-FLV, SRT, MPEG-DASH and …

【linux】 安装 java 环境

目录1.检查linux 下是否安装java(jdk)环境2.查看 linux 的操作系统版本3.下载jdk4.新建java文件夹用于安装jdk5.将下载到本地的jdk压缩包上传到linux服务器6.配置环境变量1.检查linux 下是否安装java(jdk)环境 可通过下面五条命令来查看linux 系统是否安装了java 环境 1、java …

$ZZZ 以 Launchpad 形式多平台首发,GoSleep 成 Sleep to Earn 叙事成 X2E 新宠

“ GoSleep 的治理代币 $ZZZ 将以 Launchpad 形式登录 Bitget、Gate.io以及MXC&#xff0c;这或许预示着 Sleep to Earn 叙事或成 X2E 新宠” “Sleep to Earn” 成为 X2E 市场新发力点 StepN 在去年为 X2E 赛道做了一个很好的示范&#xff0c;这也让这个领域不再仅仅局限于基于…

HarmonyOS/OpenHarmony应用开发-Stage模型ArkTS语言Ability基类

Ability模块提供对Ability生命周期、上下文环境等调用管理的能力&#xff0c;包括Ability创建、销毁、转储客户端信息等。 说明: 模块首批接口从API version 9 开始支持。模块接口仅可在Stage模型下使用。 导入模块: import Ability from ohos.app.ability.Ability; 接口说明…

虚拟化技术:实现资源高效利用和灵活管理的利器

虚拟化技术是一种通过软件或硬件手段&#xff0c;将物理资源抽象化&#xff0c;从而创建虚拟资源的技术。这种技术可以应用于计算、存储、网络等领域&#xff0c;通过将物理资源划分为多个虚拟资源&#xff0c;使得多个应用程序或用户可以共享同一组物理资源&#xff0c;从而提…

面试官:说说Java、Spring、Dubbo三者SPI机制的原理和区别

今天来跟大家聊一聊Java、Spring、Dubbo三者SPI机制的原理和区别。 其实我之前写过一篇类似的文章&#xff0c;但是这篇文章主要是剖析dubbo的SPI机制的源码&#xff0c;中间只是简单地介绍了一下Java、Spring的SPI机制&#xff0c;并没有进行深入&#xff0c;所以本篇就来深入…

数据结构2:顺序表和链表

目录 1.线性表 2.顺序表 2.1概念及结构 2.2接口实现 2.3数据相关面试题 2.4顺序表的问题及思考 3.链表 3.1链表的概念及结构 3.2链表的分类 3.3链表的实现 3.4链表面试题 3.5双向链表的实现 4.顺序表和链表的区别 1.线性表 线性表&#xff08;linear list&#x…