前言
项目上使用MongoDB存储数据,导致我生产上存储数据时,报错,频繁的出现这个bug问题,复盘感觉还是自己掌握的知识有限,👇分享一下相关技术点,我们先看Redis的知识
MySQL数据库和Redis缓存一致性的更新策略
在MySQL数据库和Redis缓存之间保持数据一致性,有几种常用的策略:
- 读数据库写缓存+定期同步:这个是最常用的策略。应用读取数据从数据库查询,更新数据先写缓存,然后定期将缓存的数据同步到数据库。这可以最大限度利用缓存的性能,但是存在一定时间窗口的数据不一致。
- 读缓存写数据库+定期同步:应用读取数据从缓存读取,更新数据直接写数据库,然后定期从数据库同步更新到缓存。这可以保证数据的一致性,但是无法充分利用缓存。
- 源生态更新:应用更新数据同时更新数据库和缓存。这保证了一致性,但是每次更新都要访问数据库和缓存,性能较差。
- 先更新数据库再删除缓存:应用更新数据先更新数据库,然后删除对应缓存键, enforced 读取数据库刷新缓存。这也可以保证一致性,需要应用在读取数据时检查缓存,如果缓存不存在从数据库加载。
- 事务更新:使用数据库事务来更新数据库和缓存,要么全部成功要么全部失败。这保证了强一致性,但是性能较差,并且事务可能包含较长时间,在此期间数据不一致。
所以总体来说,读数据库写缓存+定期同步是一种比较平衡的策略,可以在保证一定水平一致性的同时,也可以较好的发挥缓存的性能。其他策略可以根据具体业务场景选择。
MongoDB作为一个NoSQL数据库,它的一些特征和理念与传统的关系型数据库有些不同。
一次线上事故可能让你突然领悟到MongoDB的一些精髓: - MongoDB注重业务及应用的需求。它的schema-less(无模式)特征可以快速迭代业务需求。所以在线上事故的时候,可以快速调整数据模型来适应新的需求,修复问题。
- MongoDB注重大数据量及高性能。它的存储格式和索引方式都有利于处理大数据和高并发。所以即使在线上有大流量冲击,MongoDB也可以保持较高性能和稳定性。
- MongoDB提供高可用性和自动故障转移功能。通过Replica Set和Sharding可以实现无单点故障和 transparent failover。所以当个别机器或节点发生问题时,也不会影响整体服务。
- MongoDB的高扩展性。你可以简单通过添加更多的Shard和Replica成员来扩展存储空间和读取能力。所以随着业务规模的增长,MongoDB可以轻松扩展,不会成为瓶颈。
- MongoDB注重开发体验。它简单易学,基于文档模型,API友好。这使得开发人员可以更快速和高效的使用和运维MongoDB。所以在线上出现问题时,也可以迅速定位和修复。
所以通过一次线上事故的处理,你可能会更加理解和认识到MongoDB的这些设计理念和产品精髓,这也是MongoDB作为一个NoSQL数据库产品,受欢迎和流行的重要原因。
MongoDB高可用与分片
MongoDB提供了两种方式来实现高可用性和扩展性:
- 副本集(Replica Set):这是MongoDB的高可用性解决方案。一个副本集由3-7个节点组成,这些节点具有相同的数据,当主节点不可用时可以自动进行故障转移。副本集可以保证数据的高可用性,并提供读写分离能力。
- 分片(Sharding):这是MongoDB的扩展性解决方案。分片可以将数据在集群的不同节点之间进行切分,从而扩展存储空间和读取能力。需要使用分片的时候,可以指定一个副本集来充当配置服务器,存储集群的元数据和路由信息。
所以基于MongoDB,可以搭建一个高可扩展的系统架构:- 副本集: 保证系统的高可用性,可以有主从切换等功能
- 配置服务器(也是一个副本集): 存储集群的路由表和元数据信息
- 分片集合: 将集合中的数据分布在不同的Shard上,实现水平扩展
- Shard: 实际存储数据和处理请求的节点,可以是副本集构成
这样一个系统架构可以同时具有: - 高可用性: 通过副本集实现
- 灵活可扩展:可以轻松添加更多Shard来扩展
- 读写分离: 副本集的从节点可以用于读取,分散主节点压力
- 数据分布: 通过Sharding将数据分布在不同节点,避免数据热点
- 无中心化: 副本集和分片都可以实现自动故障转移,无单点故障
MongoDB 4.0支持事务了,还有多少人想用MySQL呢?
MongoDB 4.0版本新增了对事务的支持,这无疑是一个非常重要的功能增强。但是,这不意味着MongoDB可以完全替代MySQL这样的关系型数据库。两者在很多场景下仍然各有优势,开发人员需要根据具体需求选择合适的数据库:
MySQL优势:
- 成熟性高。MySQL已经发展了20多年,社区活跃, penetrated深入各个行业。
- 事务支持完备。MySQL对事务有着全面和深入的支持,包括隔离级别、回滚段等。
- 约束及其延迟检查。MySQL的各种约束条件可以确保数据完整性,也支持延迟检查。
- 复杂关系支持。MySQL可以方便的管理表之间的各种关系,支持复杂的多表join查询。
MongoDB优势: - 高性能及水平扩展性。MongoDB专注大数据场景,具有高性能及伸缩性的存储引擎。
- 功能丰富的聚合框架。MongoDB的聚合管道可以实现复杂的数据处理及分析。
- 高availability。MongoDB的副本集可以提供高可用性,无单点故障。
- 架构灵活。MongoDB是schema-less的,数据模型灵活,更易于快速迭代。
综上,MongoDB 4.0引入的全面事务支持,确实让很多人看好它可以替代传统的关系型数据库。但从成熟度、复杂查询及约束支持度来看,MySQL目前仍然有较大优势。所以对很多而言,MySQL仍将是关键业务的首选数据库,而MongoDB更适用于一些数据灵活,高扩展性的需求。两种数据库的选择,还需要根据具体业务场景和需求来判断。技术瓶颈?如何解决MongoDB超大块数据问题?
MongoDB在处理超大块数据方面,确实存在一些技术瓶颈:
- 文档大小限制。MongoDB单个文档最大为16MB,超过此大小的文档无法存储。虽然可以使用嵌套文档和数组来组合更大的逻辑文档,但这会带来复杂性。
- 分片键选择难度。对超大数据集进行分片,选择一个合适的分片键至关重要,但这往往比较困难,特别是数据集无固定模式的情况下。
- 复杂聚合性能。对超大数据集进行聚合操作,特别是多阶段的聚合管道,很容易由于数据量过大而导致性能及超时问题。
- 备份及恢复难度。超大数据集的备份和恢复,会产生和数据量liner相关的巨大开销,这使得备份策略和恢复流程的选择变得非常困难。
关于这些技术瓶颈,可以从以下几个方面来解决: - 选择更大块的存储引擎。使用WiredTiger或分段的MongoDB存储引擎,可以支持更大的文档和集合。
- 善于利用数组和嵌套文档。通过嵌套文档和数组,可以构建更大且灵活的逻辑文档。但要在易于查询和更新的同时,控制复杂性。
- 选择合适的分片键。分片键的选择需要综合考虑数据集的访问模式和可能的查询过滤器,这需要深入理解业务场景。
- 使用分段以优化聚合。将聚合操作分解到分片级进行,然后在应用层汇总结果,可以优化超大数据集的聚合性能。
- 增量备份和重要数据选择备份。使用增量备份和选择只备份重要或频繁访问的数据集等策略,可以最大限度的降低备份超大数据带来的难度与开销。
- 从业务角度优化数据模型。在一些情况下,也需要从业务及应用层面来优化数据模型,减少在MongoDB中的存储冗余或提高查询效率。这需要不同业务方面的人员配合与协作。
MongoDB数据库性能监控详解
MongoDB数据库的性能监控主要包括以下几个方面:
- 数据库连接数:可以通过db.serverStatus()查看当前的数据库连接数,确认是否达到了最大连接数限制。如果连接数过高,需要考虑连接池等解决方案。
- 查询次数:要定期监控数据库的总查询次数,特别要关注慢查询的次数情况。可以使用mongodb-slow-queries工具来收集慢日志,进而分析和优化。
- 索引使用情况:要定期监控查询是否正在利用索引,没有利用的查询很可能会造成性能问题。可以使用explain()分析查询计划,确认索引是否被正确使用。
- 存储使用量:需要监控数据库的数据文件和日志文件的使用量,确认是否有足够的存储空间。使用db.stats()可以获取数据库的总存储空间和已用存储空间。
- 内存使用情况:要定期监控mongod服务所占用的内存大小,可以使用top命令查看。如果内存消耗过大,会严重影响mongod的性能。
- 磁盘I/O:要关注磁盘的读写次数(iops)和读取写出的流量(吞吐量)。可以使用iostat等工具来查看mongodb操作系统磁盘I/O的指标。过高的I/O直接影响查询和写入性能。
- CPU使用率:要定期检查mongodb进程和系统总体的CPU使用率,可以使用top等命令。CPU使用率过高会严重制约系统性能。
- 网络流量:要监控mongod实例的网络流入流出流量,过高的网络流量可能导致请求延迟增加和性能降低。可以使用iftop或netstat等工具进行检测。
- 并发量:要关注mongod服务的并发连接数和操作数,可以使用db.serverStatus()中的connections和opcounters来查看。过高的并发可能导致服务出现性能问题或不可用。
- 复制集状态:要定期检查复制集的健康状态和同步延迟,确保秒级以内的同步延迟。可以使用rs.status()来查看复制集运行状态。
综上,要全面监控MongoDB的性能,需要关注数据库连接、查询、索引、存储、内存、I/O、CPU、网络等方方面面,并作定期检测与报警,这可以最大限度的保证服务的高性能、稳定性和可用性。MongoDB的基本概念与基本数据类型
MongoDB是一种NoSQL数据库,它的一些基本概念和数据类型如下:
基本概念: - 数据库:可以包含多个集合,类似于关系型数据库中的库。
- 集合:文档的组合,类似于关系型数据库中的表。集合没有固定的模式,文档结构可以是动态的。
- 文档:一条记录,由字段和值对组成,类似于关系型数据库中的行。文档的结构是由JSON格式定义的。
- 字段:文档中的属性,类似于关系型数据库中的列。
- 索引:用于查询效率和约束的特殊数据结构。MongoDB支持多种索引类型。
- 聚合框架:用于数据处理的强大框架,可以实现复杂的多阶段聚合操作。
- 副本集:实现高可用性的解决方案,一个副本集由多个复制的mongod实例组成。
- 分片:实现伸缩性的解决方案,可以在多台机器间分区数据。
基本数据类型: - String: 可以存储字符或字符串,对应JSON的字符串类型。
- Integer: 存储整数,对应JSON的数值类型。
- Boolean: 存储真或假,对应JSON的布尔类型。
- Double: 存储浮点数,对应JSON的数值类型。
- Min/Max keys: 用于在索引中存储最小和最大值。
- Array: 用于存储数组或列表,对应JSON的数组类型。
- Timestamp: 时间戳类型,存储时间戳。
- Object: 用于内嵌文档,对应JSON的文档类型。
- Null: 存储空值,对应JSON的null类型。
- Binary data: 用于存储二进制数据,对应JSON的二进制类型。
- Object ID: MongoDB文档的Id字段对应的数据类型,用于唯一标识一个文档。
- Date: 存储当前日期或时间,对应JSON的日期类型。
MongoDB查询与游标,彻底玩转分布式文件存储
MongoDB的查询和游标机制如下:
查询: - find(): 根据查询过滤器进行查询,可以返回所有匹配的文档。过滤器可以使用各种操作符如$gt,$lt,$eq等。
- findOne(): 返回一个匹配的文档,只返回第一个匹配的文档。
- count(): 返回查询结果的总数,一般用来进行计数统计。
- sort(): 对查询结果进行排序,使用1和-1来指定升序和降序。
- skip()和limit(): 用于分页,skip用于跳过指定个数的结果,limit用于限制返回结果的个数。
- projection: 用于选择返回哪些字段,可以使用{field1:1,field2:1}形式包含字段或{field1:0}形式排除字段。
游标:
MongoDB的查询会返回一个游标(cursor)对象。这个对象本身不包含查询结果数据,而是可以用于遍历获取数据。游标主要有以下特点: - 游标是懒加载的,只有调用next()方法时才会返回数据。这可以降低内存占用,处理超大结果集。
- 游标可以用于迭代循环 Getting 数据,使用while循环调用next()来 iterate。
- 游标可以用于推迟计数。如果只关心总数count,可以循环调用next()直到结束来完成计数。
- 游标在一定时间内有效,超过这个时间会自动关闭。这个时间值可以在查询中通过timeout来设置。
- 游标可以在任意时刻明确关闭,使用close()方法。关闭后再调用next()会引发错误。
- 游标的生命周期和客户端连接绑定。如果客户端断开,服务器会自动关闭对应的游标。
- 游标可以用于实现更精细的结果分页控制,通过设置skip值来跳过指定数量的数据。
所以,MongoDB的查询和游标机制,使它可以灵活的实现超大数据集的分页与处理,而不需要把所有数据直接加载到内存中,这也是MongoDB作为一个分布式文件存储系统,性能卓越的重要原因之一。
分布式文件存储的两个主要挑战在于: - 如何灵活高效的对海量文件进行搜索、过滤和排序。这需要借助MongoDB强大的查询功能,利用多种索引来提高查询效率。
- 如何对超大结果集进行分页和处理。这需要依靠MongoDB的游标机制来实现数据的懒加载和分段处理,避免内存耗尽的问题。
所以,MongoDB作为一个分布式文件存储系统,它出色的查询和游标机制使它可以完美解决上述两个关键技术挑战。与MySQL索引有何不同?
MongoDB和MySQL的索引机制有以下主要区别:
- 索引类型不同。MongoDB支持多种索引类型,如单字段索引、复合索引、TTL索引、文本索引、地理空间索引等。MySQL的索引类型较为单一,主要是B+树索引和全文索引。
- 索引字段灵活性。MongoDB的索引可以在嵌套文档和数组字段上创建,MySQL的索引只能在表的顶层字段上创建。
- 索引通配符。MongoDB支持在索引字段上使用通配符,如在address.zip字段上创建索引,可以匹配address.zip或address.zip_code等。MySQL不支持这种通配索引。
- 索引后再增加字段。MongoDB可以在已有大量数据的集合上增加索引,此时会后台构建索引,不影响写入和读取操作。MySQL添加索引会阻塞写入操作,并需要重建整个索引,无法在线添加。
- 索引一致性。MongoDB的索引是最终一致的,数据写入后异步更新到索引。MySQL的索引更新是同步的,数据写入时立即更新索引。
- 索引压缩。MongoDB的索引支持压缩,可以减少索引空间占用。MySQL的索引不支持压缩。
- 过期数据索引。MongoDB的TTL索引可以自动删除过期文档的数据。MySQL不支持基于过期时间自动删除索引。
- 索引存储引擎。MongoDB的索引是独立的存储引擎,即WiredTiger。MySQL的索引和表数据共用一个存储引擎。
- 部分索引。MongoDB支持对文档的子集字段创建索引,这些字段可以不连续。MySQL的索引列必须是连续的。
总体来说,MongoDB的索引比MySQL更加灵活和强大。它支持更丰富的索引类型,可以在更复杂的数据结构上创建索引,并有更优化的索引存储和管理机制。这也使得MongoDB可以更好的处理一些非结构化或半结构化的数据。
但MongoDB的索引也面临一定限制,如单个索引字段长度不能超过1024字节,索引名长度不能超过255字节,且MongoDB的每个集合最大只能有64个索引。在数据模式较为固定和关系较为复杂的框架下,MySQL的索引机制也有明显优势。
所以,两种数据库的索引各有特点,开发人员需要根据实际应用场景选择更加合适的数据库引擎。
一次线上事故,我顿悟了MongoDB的精髓