云服务器内容精选

  • 分片设计规范 对于使用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
  • 数据库连接 PostgreSQL是进程架构,每个客户端连接都对应一个后端服务进程。 根据业务的复杂度,合理配置“max_connections”,例如,参考pgtune: WEB应用:“max_connections ”配置为 200 OLTP应用:“max_connections”配置为 300 数据仓库 :“max_connections”配置为 40 桌面应用:“max_connections”配置为 20 混合应用:“max_connections”配置为 100 根据业务需要限制单个用户的最大连接数。 ALTER ROLE xxx CONNECTION LIMIT xxx; 保持合理的活跃连接数,建议活跃连接数为CPU数量的2~3倍。 避免长事务,长事务会阻塞autovacuum等,导致出现性能问题。 避免空闲长连接,长连接的缓存可能较大,导致内存不足,建议通过配置idle_session_timeout和idle_in_transaction_session_timeout参数等方式,定期释放长连接。 检查应用程序框架,避免应用程序自动begin事务,但不做任何操作。
  • 可靠性、可用性 生产数据库的实例类型务必选择主备类型。 生产数据库的CPU、内存、磁盘要有一定的冗余,正常使用保持在85%以下,防止出现OOM、磁盘满等异常问题。 将主、备机部署在不同可用区内,增加可用性。 将周期性备份设置到业务低峰期,并且不要关闭全量备份。 建议将主备的复制模式设置为“异步”,防止备机故障阻塞主机业务。 业务上需要关注临时文件大小与生成速率指标。若临时文件生成过多,会对性能产生影响,并且会拖慢数据库启动,造成业务不可用。 业务上应避免在单个实例创建大量对象。一般而言单个实例表个数不宜超过2万,单个数据库中表个数不宜超过4千。防止在数据库启动时,由于扫描表文件耗时过久,导致业务不可用。
  • 数据库年龄 数据库年龄的概念: 数据库年龄是PostgreSQL特有的概念,指的是数据库中最旧和最新两个事务ID的差值。 由于PostgreSQL的MVCC机制,数据库年龄最大为20亿,当年龄耗尽,数据库会强制关闭,只能联系技术支持来执行清理操作。 可以通过以下SQL查看当前数据库年龄: select datname, age(datfrozenxid) from pg_database; 建议通过“db_max_age” CES 指标来监控数据库年龄,告警阈值设置为10亿。
  • 稳定性 对于两阶段提交的事务,要及时提交或回滚,防止导致数据库膨胀。 选择业务低峰期变更表结构,如添加字段,索引操作。 业务高峰期创建索引时,建议使用CONCURRENTLY语法,并行创建索引,不堵塞表的DML。 业务高峰期修改表结构,要提前进行测试,防止表的REWRITE。 DDL操作需要设置锁等待超时时间,防止阻塞相关表的操作。 单个数据库库容量超过2T,需要考虑分库。 频繁访问的表,单表记录过2000万,或超过10GB,需要考虑分表或创建分区。 PostgreSQL的备库、只读库单进程回放WAL日志,最大回放速度为50 MB/s~70 MB/s,因此需要控制主库数据写入压力在50 MB/s以下,避免备机、只读复制异常。
  • 逻辑复制 创建的逻辑复制槽名需要在40个字节长度以下,否则可能导致全量备份失败。 使用逻辑复制时,注意删除不再使用的复制槽,防止数据库膨胀。 使用普通逻辑复制槽时,注意主备倒换(规格变更、小版本升级或主机故障等场景可能发生主备倒换)后复制槽会丢失,需要再次创建复制槽。 PostgreSQL 12.6及以上的小版本、13和14的所有小版本使用具备故障转移功能复制槽,避免主备倒换或数据库重启后复制槽丢失。 使用逻辑复制时,业务尽量避免长事务,废弃的两阶段事务需要及时提交,防止WAL日志积压,占用过高磁盘空间。 使用逻辑复制时,尽量避免大量使用子事务(事务内使用savepoint、exception等),防止造成过高的内存占用。 使用DRS等服务进行数据同步、迁移时,对于长期无业务的库,建议删除其中包含的逻辑复制槽,或添加心跳表来定期推进复制槽位点,避免WAL日志积压。
  • 日常运维 在实例管理界面下载慢SQL,及时关注并解决性能问题。 定期关注数据库的资源使用情况,若业务压力存在较大波动,建议配置资源告警,必要时扩充规格。业务写入压力过大会导致数据库重启恢复过程缓慢,影响业务可用性。 删除和修改记录时,需要先执行SELECT,确认无误才能提交执行。 大批量数据删除、更新后,应对被操作表执行VACUUM。 关注可用复制槽数以及创建的复制槽,请始终保持至少有一个空余的复制槽可供数据库备份使用,否则数据库备份会失败。 及时清理不再使用的复制槽,防止复制槽阻塞日志回收。 不要使用不记录日志的表(UN LOG GED TABLE),因为该表的数据会在数据库异常(如OOM、底层故障等)或发生主备倒换后丢失。 尽量避免对系统表做vacuum full操作,若有必要建议使用vacuum;否则执行vacuum full,并重启数据库后,可能导致数据库长时间无法连接。
  • 数据库连接 使用DDS时,可能会遇到因为Mongod/dds mongos的连接数满了,导致客户端无法连接的问题。在Mongod/dds mongos的服务端,收到一个新的连接由一个单独的线程来处理,每个线程配置了1MB的栈空间,当网络连接数太多时,过多的线程会导致上下文切换开销变大,同时内存开销也会上涨。 客户端连接数据库的时候,要计算业务一共有多少个客户端,每个客户端配置的连接池大小是多少,总的连接数不要超过当前实例能承受的最大连接数的80%。 客户端与数据库的连接应尽量保持相对稳定的状态,每秒新增连接数建议保持在10以下。 建议客户端的连接超时时间至少设置为最大业务执行时长的3倍。 对于副本集实例,客户端需要同时配置主备节点的IP地址;对于集群实例,至少配置两个dds mongos的IP地址。 DDS默认提供rwuser用户,使用rwuser用户登录时认证库必须是admin。
  • 性能相关 规范 业务程序禁止执行全表扫描的查询。 执行查询时,只选择需要返回的字段,不需要的字段不要返回。从而减少网络和进程处理的负载,修改数据时,只修改变化需要修改的字段,不要整个对象直接存储全部修改。 避免使用$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 使用索引计数
  • TaurusDB库表设计规范 所有创建的MySQL表必须为InnoDB引擎,适配MySQL的其它引擎不支持事务。 小数类型建议使用DECIMAL,禁止使用FLOAT和DOUBLE。 FLOAT和DOUBLE在存储的时候,存在精度损失的问题,很可能在值比较的时候得到的结果有误。如果存储的数据范围超过DECIMAL的范围,建议将数据拆成整数和小数分开存储。 禁用保留字,如DESC、RANGE、MATCH、DELAYED等。 社区MySQL 8.0的保留字与关键字请参见关键字和保留字。 TaurusDB的保留关键字在兼容社区MySQL8.0的基础上,新增了部分保留关键字,需要在业务使用中避免使用保留关键字来命名。 TaurusDB新增的关键字和保留字如表1所示。 表1 TaurusDB新增的保留关键字 保留字 相关场景 EXTRA_HEALTH 高可用 PBS 备份恢复 REDO 主从复制 SLICEID 共享存储 SLOWIO 共享存储 SPACEUSAGE 共享存储 RDS_INSTANT 回收站 RECYCLE_BIN 回收站 RDS_RECYCLE 回收站 RDS_TAC 回收站 RDS_GDB_CTRL RegionlessDB 数据表必须有主键,可以使用业务相关,有序且具有唯一性的字段作为主键,也可以使用业务无关的自增长字段作为主键。 表字段必须有默认值加NOT NULL,数字类型默认值推荐给0,VARCHAR等字符类型默认值推荐空字符串''。 无主键不仅容易导致主库执行速度慢和复制延迟问题。 避免使用分区表,如有需要,可以使用多个独立的表代替。 分区表的缺点: DDL操作需要锁定所有分区,导致所有分区上操作都被阻塞。 当表数据量较大时,对分区表进行DDL或其他运维操作难度大风险高。 分区表使用较少,存在未知风险。 当单台服务器性能无法满足时,对分区表进行分拆的成本较高。 当分区表操作不当导致访问所有分区时,会导致严重的性能问题。 建议表包含两个字段:CREATE_TIME,UPDATE_TIME, 且均为DATETIME类型。 数据仓库拖取数据时可以利用这两个统一字段无需询问业务。 在数据库出现意外时可以判断数据进入数据库和修改的时间,在极端情况可以帮助数据恢复的判断。 VARCHAR是可变长字符串,不预先分配存储空间,长度不要超过2048。 如果存储长度大于此值,定义字段类型为TEXT,或者独立出来一张表,用主键来对应,避免影响其他字段索引效率。 表单行行内长度不得超过1024字节。 控制单表字段数量,字段上限50个。 如果存储的字符串长度几乎相等,使用CHAR定长字符串类型。 字段允许适当跨表冗余,以避免关联查询,提高查询性能,但必须考虑数据一致。 冗余字段应遵循: 不是频繁修改的字段。 不是VARCHAR超长字段和TEXT字段。 合适的存储长度(不建议使用LONG TEXT, BLOB等长类型字段),不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。 所有的字符存储与表示,均以UTF-8或者utf8mb4编码,表和字段需要有注释信息。 尽量避免使用大事务。 如果在一个事务里进行多个SELECT或UPDATE语句,如果是高频事务,会严重影响MySQL并发能力,因为事务持有的锁等资源只在事务ROLLBACK/COMMIT时才能释放。但同时也要评估数据写入的一致性。 由于全文索引局限性较多,不建议使用全文索引功能。 对于超大表,还需要遵循以下规范。 尽量使用TINYINT、SMALLINT、MEDIUM_INT作为整数类型而非INT,如果非负则加上UNSIGNED,总体来看就是,在满足业务演进的前提下,字段类型尽量短。 VARCHAR的长度只分配真正需要的空间。 示例: CREATE TABLE T1 (A VARCHAR(255)); 优化为: CREATE TABLE T1 (A VARCHAR(满足业务的长度)); 使用枚举或整数代替字符串类型。 尽量使用TIMESTAMP而非DATETIME。 单表不要有太多字段,建议在20以内。 尽量不用UNIQUE,由程序保证约束。 用整型来存IP。 对序列性比较强的的字段进行分区,查询时加上范围条件效率会非常高; 对于有有明显的热点的数据,而且除了这部分数据,其他数据很少被访问到,那么可以将热点数据单独放在一个分区。 建议使用数据库代理连接数据库,对于一致性要求不高的场景下,将读业务分流到只读节点。对于查询量比较大情况下,可以通过弹性扩展,增加只读节点数量,提升查询性能。 父主题: 使用规范