云服务器内容精选

  • 性能相关 规范 业务程序禁止执行全表扫描的查询。 执行查询时,只选择需要返回的字段,不需要的字段不要返回。从而减少网络和进程处理的负载,修改数据时,只修改变化需要修改的字段,不要整个对象直接存储全部修改。 避免使用$not。DDS并不会对缺失的数据进行索引,因此$not的查询条件将会要求在一个结果集中扫描所有记录。如果$not是唯一的查询条件,会对集合执行全表扫描。 用$and时把匹配最少结果的条件放在最前面,用$or时把匹配最多结果的条件放在最前面。 单个实例中,数据库的总的个数不要超过200个,总的集合个数不要超过500个。集合数量过多会导致内存压力变高,并且集合数量多会导致重启以及主备倒换性能变差,影响紧急情况下的高可用性能。 业务上线前,一定要对数据库进行性能压测,评估业务峰值场景下,对数据库的负载情况。 禁止同时执行大量并发事务,且长时间不提交。 业务正式上线前, 所有的查询类别,都应该先执行查询计划检查查询性能。 建议 每个连接在后台都是由一个单独线程处理,每个线程会分配1MB的栈内存。所以连接数不宜过多,否则会占用过多的内存。 使用连接池,避免频繁的建立连接和断开连接,否则会导致CPU过高。 减少磁盘读写:避免使用不必要的upsert命令,避免查询不必要的数据。 优化数据分布:对数据进行分片,同时分散热点数据,均衡地使用实例资源。如何进行数据分片,请参见设置数据分片。 减少锁冲突:避免对同一个Key过于频繁地操作。 减少锁等待:避免前台创建索引。 注意 开发过程中对集合的每一个操作都要通过执行explain()检查其执行计划,如: db.T_DeviceData.find({"deviceId":"ae4b5769-896f"}).explain(); db.T_DeviceData.find({"deviceId":"77557c2-31b4"}).explain("executionStats"); 对于查询而言,因为覆盖查询不需要读取文档,而是直接从索引中返回结果,这样的查询性能好,所以尽可能使用索引覆盖查询。如果explain()的输出显示indexOnly字段为真,则说明这个查询就被一个索引覆盖。 执行计划解析: 看执行时间:executionStats.executionStages.executionTimeMillisEstimate和executionStats.executionStages.inputStage. executionTimeMillisEstimate时间越短越好。 executionStats.executionTimeMillis表示执行计划选择和执行的所有时间。 executionStats.executionStages.executionTimeMillisEstimate表示执行计划的执行完成时间。 executionStats.executionStages.inputStage. executionTimeMillisEstimate表示执行计划下的子阶段执行完成时间。 看扫描条数:三个条目数相同为最佳。 executionStats. nReturned表示匹配查询条件的文档数。 executionStats .totalKeysExamined表示索引扫描条目数。 executionStats .totalDocsExamined表示文档扫描条目数。 看Stage状态,性能较好的Stage状态组合如下。 Fetch+IDHACK Fetch+ixscan Limit+(Fetch+ixscan) PROJECTION+ixscan 表1 状态说明 状态名称 描述 COLLSCAN 全表扫描 SORT 内存中进行排序 IDHACK 根据_id进行查询 TEXT 全文索引 COUNTSCAN 未用索引计数 FETCH 索引扫描 LIMIT 使用Limit限制返回数 SUBPLA 未用索引的$or查询阶段 PROJECTION 限定返回字段时stage的返回 COUNT_SCAN 使用索引计数
  • 数据库连接 使用DDS时,可能会遇到因为Mongod/dds mongos的连接数满了,导致客户端无法连接的问题。在Mongod/dds mongos的服务端,收到一个新的连接由一个单独的线程来处理,每个线程配置了1MB的栈空间,当网络连接数太多时,过多的线程会导致上下文切换开销变大,同时内存开销也会上涨。 客户端连接数据库的时候,要计算业务一共有多少个客户端,每个客户端配置的连接池大小是多少,总的连接数不要超过当前实例能承受的最大连接数的80%。 客户端与数据库的连接应尽量保持相对稳定的状态,每秒新增连接数建议保持在10以下。 建议客户端的连接超时时间至少设置为最大业务执行时长的3倍。 对于副本集实例,客户端需要同时配置主备节点的IP地址;对于集群实例,至少配置两个dds mongos的IP地址。 DDS默认提供rwuser用户,使用rwuser用户登录时认证库必须是admin。
  • 分片设计规范 对于使用DDS分片集群,建议尽可能的使用分片集合以充分利用性能,详情请参见设置数据分片以充分利用分片性能。 分片集合使用上建议如下: 对于大数据量(数据量过百万),并有较高读写请求的业务场景,数据量随着业务量增大而增大的,建议采用分片。 对于采用hash分片的集合,需要根据业务后面实际数据量大小,采用预分片,提前预置chunk数量,减少自动均衡和分裂对业务运行造成影响。 对于非空集合开启分片,应将均衡器的开启时间窗放在业务空闲时,避免分片间均衡数据与业务冲突影响性能。设置时间窗口的API接口详情请参见设置集群均衡活动时间窗。 需要基于分片键排序查询且增加数据时可以分布均匀建议使用范围分片,其他使用哈希分片。 合理设计shard key,防止出现大量的数据使用相同shard key,导致出现jumbo chunk。 使用分片集群,执行dropDatabase后,一定要执行flushRouterConfig命令,详情请参见如何规避dds mongos路由缓存缺陷。 业务的update请求需要注意与片键相适配。在使用分片表时,如果出现如下场景则update请求会报错,并返回“An upsert on a sharded collection must contain the shard key and have the simple collation”。 update请求的filter中未携带片键字段且选项multi:false set中未携带片键字段且选项upsert:true
  • 显示的创建一个集合 也可以通过 CreateCollection()方法显示的创建一个集合,并在创建时候指定该集合的属性。 db:= client.Database("test") ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second) defer cancel() sizeInBytes := int64(200000) testCollection := db.CreateCollection(ctx,"testCollection",&options.CreateCollectionOptions{SizeInBytes: &sizeInBytes})
  • 前提条件 连接数据库的弹性云服务器必须和DDS实例之间网络互通,可以使用curl命令连接DDS实例服务端的IP和端口号,测试网络连通性。 curl ip:port 返回“It looks like you are trying to access MongoDB over HTTP on the native driver port.”,说明网络互通。 如果开启SSL,需要在界面上下载根证书,并上传到弹性云服务器。
  • 驱动下载 建议使用go mod下载驱动 require go.mongodb.org/mongo-driver v1.12.1 go文件中导入: import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/readpref" )
  • 注意事项 避免误删除。删除命令不能撤回,所以在删除前先执行db命令查看下当前所在的库。 一旦误删除后,恢复时注意以下几点: 根据历史备份文件,进行备份和恢复。 如果有备份实例,从备份实例中,通过导入和导出恢复。误删除后,恢复过程如果有新的数据写入,需要业务端考虑数据的一致性问题,即是否应该执行恢复。 实例最后的备份时间点至当前误删除时间点的数据,无法进行恢复。 删除命令,如果执行成功,则表示成功。如果执行失败,此时可能已经删除了部分数据了。所以不要继续使用删除的库表。建议继续下发删除命令,直到删除成功为止。
  • 注意事项 查询的结果,返回的是一个Currsor。Cursor使用完毕后要及时关闭,否则会产生内存堆积。 根据查询条件创建必要的索引,索引设计请参见索引设计规范。 避免COLLSCAN全表扫描。 查询条件和索引字段匹配有顺序性。 对于集群实例,根据业务对表进行合理地分片,分片设计请参见分片设计规范。 对于分片表,查询条件要基于shardKey进行,避免出现scatter-gather等不必要的查询。详情请参见Distributed Queries。 查询可以指定readConcern级别,详情请参见Read Concern。 查询可以指定readPerference参数,详情请参见Read Preference。
  • 自定义角色 用户自定义角色是用户通过命令创建的定制化的角色,只包含CRUD操作的一种或多种,或者内置角色的一种或多种。可以通过命令针对不同的资源、不同的操作进行自定义,除了预置角色无法被修改以外,其他应用方式是相同的。 创建、修改和删除角色 要创建角色前,需使用具有权限的用户(可使用rwuser)连接到数据库实例。详情请参见连接数据库。 通过createRole创建自定义角色,可以针对不同db,不同的collection进行权限控制,也可以从其他角色上继承。 角色创建完成后如需调整权限可通过grantPrivilegesToRole,grantRolesToRole,revokeRolesFromRole或revokePrivilegesFromRole命令获取或者回收回权限。详情请参见创建并管理角色。 父主题: 角色管理
  • 预置角色 预置角色是系统自动生成的角色信息,客户端可用的预置角色名称有read,readWrite。 mongodb使用角色来管理数据库的,所以创建一个用户时就需要赋予一个角色。角色除了内置之外,也可以自定义角色。 表1 常见内置角色 角色 权限描述 包含的操作命令 read read角色包含读取所有非系统集合数据和订阅部分系统集合(system.indexes、system.js、system.namespaces)的权限。 changeStream、collStats、dbHash、dbStats、find、killCursors、listIndexes、listCollections readWrite readWrite角色包含read角色的权限同时增加了对非系统集合数据的修改权限,但只对系统集合system.js有修改权限。 collStats、convertToCapped、createCollection、dbHash、dbStats、dropCollection、createIndex、dropIndex、find、insert、killCursors、listIndexes、listCollections、remove、renameCollectionSameDB、update readAnyDatabase readAnyDatabase角色包含对除了config和local之外所有数据库的只读权限。同时对于整个集群包含listDatabases命令操作。 在MongoDB3.4版本之前,该角色包含对config和local数据库的读取权限。当前版本如果需要对这两个数据库进行读取,则需要在admin数据库授予用户对这两个数据库的read角色。 readWriteAnyDatabase readWriteAnyDatabase角色包含对除了config和local之外所有数据库的读写权限。同时对于整个集群包含listDatabases命令操作。 在MongoDB3.4版本之前,该角色包含对config和local数据库的读写权限。当前版本如果需要对这两个数据库进行读写,则需要在admin数据库授予用户对这两个数据库的readWrite角色。 dbAdmin dbAdmin角色包含执行某些管理任务(与schema相关、索引、收集统计信息)的权限,该角色不包含用户和角色管理的权限。 对于系统集合(system.indexes、system.namespaces、system.profile)包含命令操作:collStats、dbHash、dbStats、find、killCursors、listIndexes、listCollections、dropCollection and createCollection(仅适用system.profile) 对于非系统集合包含命令操作:bypassDocumentValidation、collMod、collStats、compact、convertToCapped、createCollection、createIndex、dbStats、dropCollection、dropDatabase、dropIndex、enableProfiler、reIndex、renameCollectionSameDB、repairDatabase、storageDetails、validate dbAdminAnyDatabase dbAdminAnyDatabase角色包含类似于dbAdmin角色对于所有数据库管理权限,除了config数据库和local数据库。同时对于整个集群包含listDatabases命令操作。 在MongoDB3.4版本之前,该角色包含对config和local数据库的管理权限。当前版本如果需要对这两个数据库进行管理,则需要在admin数据库授予用户对这两个数据库的dbAdmin角色。 clusterAdmin clusterAdmin角色包含MongoDB集群管理最高的操作权限。 clusterManager、clusterMonitor和hostManager三个角色的所有权限,并且还拥有dropDatabase操作命令的权限。 userAdmin userAdmin角色包含对当前数据库创建和修改角色和用户的权限。该角色允许向其它任何用户(包括自身)授予任何权限,所以这个角色也提供间接对超级用户(root)的访问权限,如果限定在admin数据中,也包括集群管理的权限。 changeCustomData、changePassword、createRole、createUser、dropRole、dropUser、grantRole、revokeRole、setAuthenticationRestriction、viewRole、viewUser userAdminAnyDatabase userAdminAnyDatabase角色包含类似于userAdmin角色对于所有数据库的用户管理权限,除了config数据库和local数据库。 对于集群包含命令操作:authSchemaUpgrade、invalidateUserCache、listDatabases 对于系统集合admin.system.users和admin.system.roles包含命令操作:collStats、dbHash、dbStats、find、killCursors、planCacheRead、createIndex、dropIndex 父主题: 角色管理
  • 示例 更新用户信息 products数据库中的用户appClient01,其信息如下: { "_id" : "products.appClient01", "token" : NumberLong("8424642624807814713"), "user" : "appClient01", "db" : "products", "customData" : { "empID" : "12345", "badge" : "9156" }, "roles" : [ { "role" : "readWrite", "db" : "products" }, { "role" : "read", "db" : "inventory" } ], "mechanisms" : [ "SC RAM -SHA-1", "SCRAM-SHA-256" ] } 下面操作会替换用户的自定义数据和角色数据: use products db.updateUser( "appClient01", { customData : { employeeId : "0x3039" }, roles : [ { role : "read", db : "assets" } ] } ) products数据库中的用户appClient01,经过更新后信息如下: { "_id" : "products.appClient01", "token" : NumberLong("8424642624807814713"), "user" : "appClient01", "db" : "products", "customData" : { "employeeId" : "0x3039" }, "roles" : [ { "role" : "read", "db" : "assets" } ], "mechanisms" : [ "SCRAM-SHA-1", "SCRAM-SHA-256" ] } 更新用户以仅使用SCRAM-SHA-256凭证 reporting数据库中的用户reportUser256,其信息如下: { "_id" : "reporting.reportUser256", "token" : NumberLong("2827251846225877395"), "user" : "reportUser256", "db" : "reporting", "roles" : [ ], "mechanisms" : [ "SCRAM-SHA-1", "SCRAM-SHA-256" ] } 以下操作会将当前同时拥有 SCRAM-SHA-256 和 SCRAM-SHA-1 全权证书的用户更新为只拥有 SCRAM-SHA-256 全权证书的用户。 如果密码未与mechanisms一起指定,则只能将mechanisms更新为用户当前SCRAM机制的子集。 如果密码与mechanisms一起指定,则可以指定任何受支持的SCRAM机制。 对于SCRAM-SHA-256,passwordDigestor必须是默认值 "server"。 db.updateUser( "reportUser256", { mechanisms: [ "SCRAM-SHA-256" ] } ) reporting数据库中的用户reportUser256,经过更新后信息如下: { "_id" : "reporting.reportUser256", "token" : NumberLong("2827251846225877395"), "user" : "reportUser256", "db" : "reporting", "roles" : [ ], "mechanisms" : [ "SCRAM-SHA-256" ] }
  • 示例 创建用户时不同数据库赋予不同角色 使用db.createUser()在products数据库中创建accountAdmin01用户。 use products db.createUser( { user: "accountAdmin01", pwd: "Changeme_123", customData: { employeeId: 12345 }, roles: [ { role: "clusterAdmin", db: "admin" }, { role: "readAnyDatabase", db: "admin" }, "readWrite"] }, { w: "majority" , wtimeout: 5000 } ) 以上操作赋予用户accountAdmin01以下角色: 在admin数据库中角色为clusterAdmin和readAnyDatabase。 在products数据库中角色为readWrite。 创建用户时同一数据库赋予多个角色 以下操作创建一个在products数据库中角色为readWrite和dbAdmin的用户,用户名为accountUser。 use products db.createUser( { user: "accountUser", pwd: "Changeme_123", roles: [ "readWrite", "dbAdmin" ] } ) 创建用户时不赋予角色 以下操作在admin数据库中创建一个用户名为reportsUser的用户,但是没有赋予用户角色。 use admin db.createUser( { user: "reportsUser", pwd: "Chagneme_123", roles: [ ] } ) 创建管理员用户并赋予角色 下面的操作将在admin 数据库中创建名为appAdmin的用户,并赋予该用户对config数据库的读写访问权限,使用户可以更改分片群集的某些设置,如分片均衡器设置。 use admin db.createUser( { user: "appAdmin", pwd: "Changeme_123", roles: [ { role: "readWrite", db: "config" }, "clusterAdmin" ] } ) 创建有身份验证限制的用户 以下操作将在管理员数据库中创建一个名为restricted的用户。该用户只能从IP地址192.0.2.0连接到IP地址198.51.100.0时才能进行身份验证。 use admin db.createUser( { user: "restricted", pwd: "Changeme_123", roles: [ { role: "readWrite", db: "reporting" } ], authenticationRestrictions: [ { clientSource: ["192.0.2.0"], serverAddress: ["198.51.100.0"] } ] } ) 仅使用SCRAM-SHA-256证书创建用户 下面的操作将创建一个只有SCRAM-SHA-256凭据的用户。 use reporting db.createUser( { user: "reportUser256", pwd: "Changeme_123", roles: [ { role: "readWrite", db: "reporting" } ], mechanisms: [ "SCRAM-SHA-256" ] } ) 如果设置了authenticationMechanisms参数,mechanisms字段只能包含authenticationMechanisms参数中指定的值。
  • 操作须知 下面所有操作都对权限要求,默认rwuser用户具备所需权限,如果通过客户自定义用户进行管理,则需要关注是否具备操作权限。 使用具备权限的用户(可使用rwuser)连接到数据库实例。 通过createUser创建所需的用户,通过设置合适的角色来控制对应用户的权限。其中需要注意的是"passwordDigestor" 参数必须是 "server",否则命令会执行失败,增加这个约束是为了避免安全隐患。
  • 用户管理 DDS上用户的权限都是基于角色管理,通过给用户赋予不同的角色来进行差异化的权限控制。 为了给文档数据库实例提供管理服务,您在创建数据库实例时,文档数据库服务会自动为实例创建admin、monitor和backup账户。如果试图删掉、重命名、修改这些账户的密码和权限,会导致出错。 对于数据库管理员账户rwuser,以及您所创建的账户,允许修改账户的密码。 创建用户 更新用户 删除用户 父主题: 管理数据库权限
  • 完整示例 #!/usr/bin/python import pymongo import random import os # 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放、使用时解密),确保安全 # 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)EXAMPLE_USERNAME_ENV和EXAMPLE_PASSWORD_ENV username = os.getenv('EXAMPLE_USERNAME_ENV') password = os.getenv('EXAMPLE_PASSWORD_ENV') mongodbUri = 'mongodb://%s:%s@10.66.187.127:27017/admin' client = pymongo.MongoClient(mongodbUri % (username, password )) db = client.somedb db.user.drop() element_num=10 for id in range(element_num): name = random.choice(['R9','cat','owen','lee','J']) sex = random.choice(['male','female']) db.user.insert_one({'id':id, 'name':name, 'sex':sex}) content = db.user.find() for i in content: print i 更多PyMongo接口请参考官方文档。 父主题: 基于Python开发