Mongo集群快速搭建

一 Mongo集群

项目中,将大部分内容存储到了MongoDB中,这部分数据无疑是海量的,那么如何保证数据的容量和安全呢?答案是:集群

MongoDB有三种集群方式,分别是:主从集群(过时)、副本集群(推荐)、分片式集群。

其中主从集群官方已经不推荐了,一般用副本集群取代主从集群。

1 主从集群(了解)

主从架构一般用于备份或者做读写分离。由两种角色构成:

  • 主(Master):可读可写,当数据有修改的时候,会将oplog同步到所有连接的salve上去。
  • 从(Slave):只读不可写,自动从Master同步数据。

对于Mongodb来说,并不推荐使用Master-Slave架构,因为Master-Slave其中Master宕机后不能自动恢复,推荐使用Replica Set。

2 副本集群【演示】

介绍

为了防止单点故障就需要副本集群,包含三类角色:

  • 主节点(Primary)

    接收所有的写请求,然后把修改同步到所有Secondary。一个Replica Set只能有一个Primary节点,当Primary挂掉后,其他Secondary或者Arbiter节点会重新选举出来一个主节点。默认读请求也是发到Primary节点处理的.若需要转发到Secondary,需要客户端修改一下连接配置。

  • 副本节点(Secondary)

    与主节点保持同样的数据集。当主节点挂掉的时候,参与选主。

  • 仲裁者(Arbiter)

    不保有数据,不参与选主,只进行选主投票。使用Arbiter可以减轻数据存储的硬件需求,Arbiter跑起来几乎没什么大的硬件资源需求,但重要的一点是,在生产环境下它和其他数据节点不要部署在同一台机器上。

注意,一个自动failover的Replica Set节点数必须为奇数,目的是选主投票的时候要有一个大多数才能进行选主决策。

特殊说明

环境搭建

创建容器

docker run -d --name=master_mongo -p 27011:27017 mongo:4.0.3  --replSet mongo_clus 
docker run -d --name=backup_mongo -p 27012:27017 mongo:4.0.3  --replSet mongo_clus 
docker run -d --name=arbi_mongo   -p 27013:27017 mongo:4.0.3  --replSet mongo_clus

设置副本集名称,也就是设置集群名称,必须要设置,否则没法构建集群

配置

进入master_mongo容器中

docker exec  -it master_mongo /bin/bash

登录Mongo

mongo

创建集群

cfg={
  "_id":"mongo_clus",
  members:[{
      _id:0,
      host:"192.168.136.131:27011",
      priority:2
  },{
      _id:1,
      host:"192.168.136.131:27012",
      priority:1
  },{
      _id:2,
      host:"192.168.136.131:27013",
      arbiterOnly:true
  }]
}



rs.initiate(cfg)

通过 rs.status() 可以查看集群的状态

客户端测试

使用客户端连接主节点

use demo

db.createCollection("user")

db.user.insert({username:'zhangsan',age:18,address:'北京顺义'})

java代码测试

在之前的工程中创建 mongo-cluster 模块(不要在探花工程中)

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongodb-driver-sync</artifactId>
        <version>3.9.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
</dependencies>

实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.mapping.Document;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "account")
public class Account {
    private ObjectId id; //主键id
    private String username; //用户名
    private Double money; //金额
}

启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MongoClusterApplication {
    public static void main(String[] args) {
        SpringApplication.run(MongoClusterApplication.class,args);
    }
}

application.yml

server:
  port: 9999
  
spring:
  data:
    mongodb:
      uri: mongodb://192.168.136.131:27011,192.168.136.131:27012/demo?connect=replicaSet&replicaSet=mongo_clus
  • connect=replicaSet 连接方式是副本集
  • replicaSet=myrs 设置副本集的名称为mongo_clus

测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class MongoTest {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Test
    public void testSave() {
        Account account = new Account();
        account.setUsername("jack");
        account.setMoney(1000D);
        mongoTemplate.save(account);
        
        account = new Account();
        account.setUsername("tom");
        account.setMoney(1000D);
        mongoTemplate.save(account);
    }

    @Test
    public void testFindAll() {
        List<Account> accountList = mongoTemplate.findAll(Account.class);
        for (Account account : accountList) {
            System.out.println(account);
        }
    }
}

事务支持

MongoDB 4.0以上才开始支持事务。4.0-4.2版只支持副本集群事务,4.2以上版本开始支持所有集群事务

配置事务管理器

事务管理器:已经和Spring进行了整合

@SpringBootApplication
public class MongoClusterApplication {
    public static void main(String[] args) {
        SpringApplication.run(MongoClusterApplication.class,args);
    }

    @Bean
    public MongoTransactionManager initMongoTransactionManager(MongoDbFactory factory){
        return new MongoTransactionManager(factory);
    }
}

转账案例

package com.itheima.service;

import com.itheima.domain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class AccountService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Transactional
    public void transfer(String sourceName, String targetName, Double money) {
        //1. 更新sourceName的账户金额
        Query query = new Query(Criteria.where("username").is(sourceName));
        Account source = mongoTemplate.findOne(query, Account.class);

        Query query1 = new Query(Criteria.where("username").is(targetName));
        Account target = mongoTemplate.findOne(query1, Account.class);

        //2. 变动金额
        Update update = new Update();
        update.set("money", source.getMoney() - money);
        Update update1 = new Update();
        update1.set("money", target.getMoney() + money);


        //3. 更新账户金额
        mongoTemplate.updateFirst(query, update, Account.class);
        int i=1/0;
        mongoTemplate.updateFirst(query1, update1, Account.class);
    }
}

测试

@Autowired
private AccountService accountService;

@Test
public void testTransfer() {
    accountService.transfer("jack", "tom", 100D);
}

3 分片集群(了解)

介绍

当数据量比较大的时候,我们需要把数据分片运行在不同的机器中,以降低CPU、内存和IO的压力,Sharding就是这样的技术。

分片(sharding)是MongoDB用来将大型集合分割到不同服务器上所采用的方法。

如图所示:

例如,如果数据库1tb的数据集,并有4个分片,然后每个分片可能仅持有256 GB的数据。如果有40个分片,那么每个切分可能只有10TB的数据。

分片集群架构

  • 数据分片(Shards)

    保存数据,保证数据的高可用性和一致性。可以是一个单独的mongod实例,也可以是一个副本集。

    在生产环境下Shard是一个Replica Set,以防止该数据片的单点故障。所有Shard中有一个PrimaryShard,里面包含未进行划分的数据集合:

  • 查询路由(Query Routers)

    mongos的实例,客户端直接连接mongos,由mongos把读写请求路由到指定的Shard上去。

    一个Sharding集群,可以有一个mongos,也可以有多mongos以减轻客户端请求的压力。

  • 配置服务器(Config servers)

    保存集群的元数据(metadata),包含各个Shard的路由规则。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值