凤凰架构-数据管理与存储

数据库选型策略

数据模型

数据库类型数据模型典型场景代表产品
关系型数据库(RDBMS) 表格结构,强Schema约束 事务处理(OLTP)、复杂查询 MySQL、PostgreSQL、Oracle
文档数据库 JSON/BSON文档,弱Schema 灵活模式、半结构化数据存储 MongoDB、Couchbase
键值数据库 Key-Value存储 高速缓存、会话管理 Redis、DynamoDB
列式数据库 按列存储,压缩率高 数据分析(OLAP)、大规模聚合 Cassandra、HBase、ClickHouse
图数据库 节点与关系存储 社交网络、推荐系统、欺诈检测 Neo4j、ArangoDB
时序数据库 时间序列数据优化 物联网监控、日志存储、指标分析 InfluxDB、TimescaleDB
搜索引擎数据库 全文检索、相关性排序 商品搜索、日志分析 Elasticsearch、Solr

业务场景

  • OLTP(联机事务处理)

    • 特点:高并发短事务,强一致性,频繁增删改。
    • 选型:关系型数据库(如MySQL)、NewSQL(如TiDB)。
  • OLAP(联机分析处理)

    • 特点:复杂查询,大数据量聚合,读多写少。
    • 选型:列式数据库(如ClickHouse)、MPP数据库(如Snowflake)。
  • HTAP(混合事务与分析处理)

    • 特点:兼顾事务与分析需求。
    • 选型:NewSQL(如TiDB)、云原生数据库(如Google Spanner)。

技术特性

  • 一致性

    • 强一致性(CP):金融交易(如MySQL ACID)。
    • 最终一致性(AP):社交网络评论(如Cassandra)。
  • 扩展性

    • 垂直扩展(Scale-Up):单机性能强(如Oracle)。
    • 水平扩展(Scale-Out):分片与多副本(如MongoDB)。
  • 事务支持

    • 单机事务:MySQL、PostgreSQL。
    • 分布式事务:TiDB(Percolator协议)、CockroachDB(Spanner协议)。

选型决策框架

  • 数据规模

    • 小数据量(<1TB):单机RDBMS(如PostgreSQL)。
    • 大数据量(>1TB):分布式数据库(如Cassandra、TiDB)。
  • 读写比例

    • 写密集型:LSM-Tree结构数据库(如HBase)。
    • 读密集型:内存数据库(如Redis)或列式存储(如ClickHouse)。
  • 延迟要求

    • 毫秒级响应:内存数据库(如Redis)、OLTP数据库(如MySQL)。
    • 亚秒级响应:OLAP优化数据库(如BigQuery)。

分库分表实践

垂直拆分

  • 垂直分库:按业务模块划分数据库(如用户库、订单库、商品库)。

    • 优点:业务解耦,降低单库压力。
    • 缺点:跨库事务复杂,需通过分布式事务(如Seata)解决。
  • 垂直分表:将大表按列拆分(如用户表拆分为基础信息表、扩展信息表)。

    • 场景:包含大量不常用字段(如用户备注、历史日志)。

水平拆分

  • 水平分库:将同一业务数据按分片键分布到多个数据库(如订单库1、订单库2)。
  • 水平分表:将同一表数据按分片键分布到多个子表(如order_00order_01)。

缓存策略优化

缓存读写策略

策略流程适用场景优缺点
Cache-Aside(旁路缓存) 1. 读:先查缓存,未命中读DB并回填。 2. 写:直接写DB,删除缓存。 通用场景(如用户信息) 实现简单,但存在缓存不一致风险(需结合延迟双删)。
Read-Through 缓存作为代理,读请求由缓存处理,未命中时缓存自动从DB加载并返回。 缓存与DB强绑定(如ORM集成) 简化业务逻辑,但缓存层需感知DB结构。
Write-Through 写请求同时更新缓存和DB,由缓存层保证原子性。 对一致性要求极高的场景(如金融余额) 写延迟高,需事务支持。
Write-Behind 写请求先更新缓存,异步批量写DB(如定时刷新)。 写密集型场景(如日志、计数器) 吞吐量高,但存在数据丢失风险(缓存宕机)。

缓存淘汰策略

策略原理适用场景
LRU 淘汰最近最少使用的数据(基于时间局部性原理)。 热点数据分布不均的长尾场景。
LFU 淘汰访问频率最低的数据(基于计数统计)。 数据访问模式稳定的场景(如配置项)。
FIFO 淘汰最早进入缓存的数据。 数据冷热无明显差异的流水场景。
TTL 为每个Key设置过期时间,到期自动失效。 临时数据(如验证码、会话信息)。
Random 随机淘汰数据。 极端场景下的兜底策略。

多级缓存架构

  • 本地缓存 + 分布式缓存

    • 本地缓存(L1) :使用Guava、Caffeine,缓存热点数据(毫秒级响应)。
    • 分布式缓存(L2) :使用Redis、Memcached,共享全量数据(避免单机缓存穿透)。
  • 同步机制

    • 主动推送:DB变更时,通过消息队列(如Kafka)通知各节点失效本地缓存。
    • 被动失效:设置本地缓存短TTL(如5秒),依赖L2缓存兜底。
  • 浏览器缓存 + CDN + 服务端缓存

    • 浏览器缓存:通过Cache-ControlETag控制静态资源缓存(减少服务端请求)。
    • CDN缓存:缓存图片、视频等静态资源,按区域就近分发。
    • 服务端缓存:缓存动态数据(如API响应),通过Nginx或网关层实现。

缓存穿透(Cache Penetration)

  • 问题:大量请求查询不存在的数据(如不合法ID),绕过缓存直接冲击DB。

  • 解决方案

    • 布隆过滤器(Bloom Filter) :在缓存层前置过滤器,拦截无效请求。
    • 空值缓存:将查询结果为空的Key也缓存(设置短TTL,如30秒)。

缓存雪崩(Cache Avalanche)

  • 问题:大量缓存同时过期,导致请求集中访问DB。

  • 解决方案

    • 随机化过期时间:基础TTL + 随机值(如TTL = 300 + rand(0, 60)秒)。
    • 永不过期 + 异步刷新:缓存不设TTL,后台线程定期更新(需处理脏读)。

缓存击穿(Cache Breakdown)

  • 问题:某热点Key失效的瞬间,高并发请求直接击穿到DB。

  • 解决方案

    • 互斥锁(Mutex Lock) :第一个请求加锁查DB,后续请求等待锁释放后读取缓存。
    • 逻辑过期:缓存Value中存储过期时间,业务判断是否需要异步更新。

数据一致性保障

强一致性(Strong Consistency)

  • 定义:任何读操作都能读到最新写入的数据,所有节点数据实时一致。

  • 实现方式

    • 同步复制:写入操作需所有副本确认后才返回成功(如ZooKeeper的ZAB协议)。
    • 分布式锁:通过锁机制保证同一时刻仅一个客户端修改数据(如Redis RedLock)。
  • 适用场景:金融交易、库存扣减等不允许数据不一致的场景。

最终一致性(Eventual Consistency)

  • 定义:数据副本经过一段时间后达到一致,期间允许短暂不一致。

  • 实现方式

    • 异步复制:写入主节点后异步同步到从节点(如MySQL主从架构)。
    • 冲突解决:通过版本号(Vector Clock)或业务逻辑合并冲突(如购物车合并)。
  • 适用场景:社交网络点赞、评论等容忍短暂不一致的场景。

其他一致性模型

模型特点案例
因果一致性 有因果关系的操作按顺序可见,无因果关系的操作允许乱序。 聊天消息的顺序保证。
会话一致性 同一会话内的操作保证顺序一致性,跨会话允许延迟。 用户登录后的操作连贯性。
单调读一致性 用户读取的数据版本不会回退(如不会读到比之前更旧的值)。 新闻Feed流的分页
全部评论

相关推荐

18岁你把高考志愿填成&quot;Java开发工程师&quot;,因为贴吧里说&quot;永不失业的铁饭碗&quot;。录取通知书和《Thinking&nbsp;in&nbsp;Java》同天抵达,父亲用Excel表格给你列了三年学习计划,最后一行备注:加班餐补要记账。22岁你在互联网大厂实习,对着IDEA里报错的Spring&nbsp;Boot项目抓耳挠腮。带教师傅敲键盘的声音像暴雨打在屋顶,突然抽走你手里的咖啡杯:&quot;年轻人,这个@RequestBody注解该加泛型了。&quot;你盯着控制台闪烁的GC日志,恍惚看见自己正在被JVM回收。25岁你独自守着凌晨三点的服务器监控。K8s集群的告警面板像生日蜡烛此起彼伏,当第17个Docker容器崩溃时,你突然想起大学时用Eclipse调试整夜的痛苦。运维群突然炸出红色警报,你对着CPU&nbsp;100%的Tomcat线程,听见心脏和磁盘阵列发出同样的啸叫。30岁婚礼上,前同事醉醺醺地说:&quot;新郎可是能写出单线程百万QPS的代码侠!&quot;你默默关掉手机里未读的32个JIRA工单,西装口袋里还躺着没来得及吃的布洛芬——上周重构微服务时落下的腰椎劳损,比爱情更早侵蚀了身体。35岁女儿指着你电脑问:&quot;爸爸在和计算机下象棋吗?&quot;你展示着刚完成的分布式锁方案:&quot;看,这些代码在帮外卖小哥抢饭盒呢。&quot;她撅嘴:&quot;可是小明爸爸在造太空飞船。&quot;你点开git&nbsp;blame,发现三年前写的脏代码正在吞噬整个项目,就像当年自己吞噬了她的生日会。40岁架构师会议上,实习生兴奋展示Go语言实现的高性能网关。你摩挲着用烂的Eclipse快捷键贴纸,突然想起2013年那个用Struts2写爆款APP的夏天。当云原生PPT翻到第27页时,你发现自己的Spring&nbsp;Session还在用着过期的Redis集群。45岁同学会散场时,做区块链的发小搂着你肩膀:&quot;兄弟要不要搞个智能合约项目?&quot;你看着他手机里闪动的ETH行情,想起去年双十一扛住亿级流量的那个凌晨。酒杯碰撞声里,你默默把MySQL&nbsp;8.0的升级计划又往后拖了三个月。50岁部门转云原生那天,你正调试着某个遗留的MyBatis&nbsp;XML。新来的CTO说:&quot;传统单体架构就像恐龙骨架,该进博物馆了。&quot;你看着IDEA里3000+行的Service层代码,突然想起2008年那个用JSP+Servlet搭建论坛的自己,此刻正在某个垃圾回收区等待被GC。55岁收拾工位时,机械硬盘还在循环播放《Java核心技术卷1》的有声书。年轻同事好奇地问:&quot;张叔,为什么不用SSD啊?&quot;你笑着指向机箱上2015年的贴纸:&quot;这盘里存着整个城市的外卖订单,还有我女儿的百日照。&quot;注销账号时,GitHub头像弹出最后一条消息:您参与的Spring&nbsp;Cloud项目已被归档。60岁小孙子举着手机哭闹:&quot;爷爷,我的游戏币又被偷了!&quot;你戴上老花镜打开Postman,突然发现那些被遗忘的SHA-1签名漏洞,此刻正透过孙子的瞳孔向你招手。当找回密码的提示音响起时,窗外的5G基站正闪烁着熟悉的Spring&nbsp;Boot启动日志——你终于读懂了,那些年在代码里埋藏的,从来不只是技术债务。
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务