prisma使用mongodb副本集群报错引发的一些列问题

prisma使用mongodb副本集群报错引发的一些列问题

  • 前提:因为prisma对于增删改有事务,所以必须使用mongdb副本集群

    • 详细参考官方:https://www.prisma.io/docs/concepts/database-connectors/mongodb#troubleshooting
  • 错误描述

    None of the available servers suitable for criteria Predicate. Topology: { Type: Unknown, Servers: [ { Address: localhost:27017, Type: RsGhost, Average RTT: 346.567µs, Last Update Time: DateTime(2022-02-16T20:00:59.552Z), Max Wire Version: 9, Min Wire Version: 0 }, ] }
    

    错误描述很清楚Address: localhost:27017,没有找到合适可用的服务

  • .env文件

    DATABASE_URL="mongodb://自己的云服务器ip地址:27018/test?authSource=admin&retryWrites=true&w=majority"
    
  • schema.prisma

    datasource db {
      provider = "mongodb"
      url      = env("DATABASE_URL")
    }
    
    generator client {
      provider        = "prisma-client-js"
    }
    

一切都很平平无奇,下面进行排查流程,此处不做如何搭建mongodb副本集群的教程,可以百度,上面有很多教程

思考1:db url字段

  • 很显然,我的肯定是没问题,用一些gui 可视化mongodb连接工具即可

思考2:mongodb副本集群host字段不能为localhost或127.0.0.1

  • 查看错误信息,如果是副本集群报错应该是多个数组(这里拿的是别人的错误,所以只有一个)

    Topology: { 
      Type: Unknown, 
        Servers: [ 
          { 
            Address: localhost:27017, 
            Type: RsGhost, 
            Average RTT: 346.567µs, 
            Last Update Time: DateTime(2022-02-16T20:00:59.552Z), 
          Max Wire Version: 9, 
          Min Wire Version: 0 
          }, 
       	] 
    }
    
  • 可以看到address字段为localhost:port形式,那么,会不会因为prisma会向mongodb副本集群获取rs.config()然后再根据配置的host进行连接?

  • 这里直接告诉结论:是的,prisma就是这样做的

    1. 首先查看自己的配置信息,进入mongo/mongosh,rs.config()可以发现你配置的所有副本集群信息

    2. host: localhost进行修改

      // 进入主机节点,比如27017是主节点
      mongo/mongosh localhost:27017
      
      config = rs.config();
      // 打印config信息
      members: [
        {
          _id: 1,
          host: 'localhost:27017',
          arbiterOnly: false,
          buildIndexes: true,
          hidden: false,
          priority: 1,
          tags: {},
          secondaryDelaySecs: Long("0"),
          votes: 1
        },
        {
          _id: 2,
          host: 'localhost:27018',
          arbiterOnly: false,
          buildIndexes: true,
          hidden: false,
          priority: 1,
          tags: {},
          secondaryDelaySecs: Long("0"),
          votes: 1
        }
      ],
      
      // 因为使用了对host都是localhost, 所以直接修改配置文件会报错:Either all host names in a replica set configuration must be localhost references, or none must be; found 1 out of 2.
      // 意思就是,所有副本集的host配置要么是localhost要么都不是localhost
      // 移除副本节点
      rs.remove('loclhost:27018');
      
      // 修改配置
      reconfig = rs.config().members[0].host = 'ip:port'; // 要么修改成ip:端口,也可以用域名代替
      rs.reconfig(reconfig);
      
      // 查看是否修改成功
      rs.config();
      
      // 添加子节点
      rs.add('ip:port'); // 或域名:端口
      
      // 查看是否修改成功
      rs.config();
      // 查看状态
      rs.status();
      
  • 最后验证

    1. npx prisma studio:进去后不报错就是ok

    2. 跑一个查询代码

      import { PrismaClient } from '@prisma/client';
      const prisma = new PrismaClient();
      
      async function main() {
        await prisma.$connect();
        const allUsers = await prisma.user.findMany();
        console.log(allUsers);
      }
      
      main()
        .catch((e) => {
          console.log(e);
        })
        .finally(async () => {
          await prisma.$disconnect();
        });
      
      

      结果不管怎样,只要没报错就是ok的

使用docker-compose部署

贴上一个简单实用keyFile集群成员认证 + 客户端账号密码认证的1主2从副本集群攻略

日期:2022-07-31

  • docker-compose文件

    version: '3.1'
    
    services:
      mongodb1:
      	# 默认最新
        image: mongo
        # 错误后自动重启
        restart: on-failure
        container_name: mongo1
        volumes:
        	# 数据存放目录
          - ./db/mongo1:/data/db
          # keyfile:用于集群之间的认证
          - /data/mongodb/mongodb.key:/data/mongodb.key
          # 配置目录
          - ./config/mongo1:/data/configdb
        ports:
          - 27017:27017
        environment:
          MONGO_INITDB_ROOT_USERNAME: admin
          MONGO_INITDB_ROOT_PASSWORD: admin
        networks:
          - mongoNet
        command: mongod --replSet rs0 --keyFile /data/mongodb.key
        entrypoint: 
          - bash 
          - -c 
          - | 
            chmod 400 /data/mongodb.key 
            chown 999:999 /data/mongodb.key
            exec docker-entrypoint.sh $$@
    
            
    
      mongodb2:
        image: mongo
        restart: on-failure
        container_name: mongo2
        volumes:
          - ./db/mongo2:/data/db
          - /data/mongodb/mongodb.key:/data/mongodb.key
          - ./config/mongo2:/data/configdb
        ports:
          - 27018:27017
        environment:
          MONGO_INITDB_ROOT_USERNAME: admin
          MONGO_INITDB_ROOT_PASSWORD: admin
        networks:
          - mongoNet
        command: mongod --replSet rs0 --keyFile /data/mongodb.key
        entrypoint:
          - bash
          - -c
          - |
            chmod 400 /data/mongodb.key 
            chown 999:999 /data/mongodb.key
            exec docker-entrypoint.sh $$@
    
      mongodb3:
        image: mongo
        restart: on-failure
        container_name: mongo3
        volumes:
          - ./db/mongo3:/data/db
          - /data/mongodb/mongodb.key:/data/mongodb.key
          - ./config/mongo3:/data/configdb
        ports:
          - 27019:27017
        environment:
          MONGO_INITDB_ROOT_USERNAME: admin
          MONGO_INITDB_ROOT_PASSWORD: admin
        networks:
          - mongoNet
        command: mongod --replSet rs0 --keyFile /data/mongodb.key
        entrypoint:
          - bash
          - -c
          - |
            chmod 400 /data/mongodb.key 
            chown 999:999 /data/mongodb.key
            exec docker-entrypoint.sh $$@
        
    networks:
      mongoNet:
        driver: bridge
    
  • 进入节点:docker exec -it mongo1 /bin/bash

    rs.initiate({ 
      // 集群名称,一定要和配置文件保持一致
      _id: "rs0", 
      members: [ 
        // 一定要用公网,否则访问不到
        { _id: 0, host: "xxxxxxxx:port" }, 
        { _id: 1, host: "xxxxxxxx:port" }, 
        { _id: 2, host: "xxxxxxxx:port" }
      ] 
    });
    
  • 测试,使用gui通过账号密码登陆测试

    // 我用的DataGrip(all in one 工具) 你可以用navicat、stdio 3T
    mongodb://admin:admin@xxx:port1,xxx:port2,xxx:port3/test?replicaSet=rs0&authSource=admin&slaveOk=true&connectTimeoutMS=5000
    

你可能感兴趣的:(node,mongodb,数据库,prisma)