海量数据存储基础
原⽂出处:作者:毕建坤
微博平台研发作为微博的底层数据及业务⽀撑部门,已经经历了5年的发展历程。伴随着从数据及业务暴发式增长,我们在海量数据存储⽅⾯遭遇了诸多挑战,与此同时也伴随着丰富经验的积累。
本次新兵训练营,受众在于应届毕业⽣,⽬的在于让新同学系统化并且有针对性的了解平台的核⼼技术及核⼼业务,以使新同学在新兵训练营结束后,能够对平台的底层架构与业务有⼀定的了解。
本⽂主要⾯向新同学介绍平台的核⼼技术之⼀——海量数据存储,主要介绍在海量数据存储在⼤规模分布式系统下的架构变迁与设计。课程⼤纲:⼀、课程⽬标
1. 了解存储服务概况,以及RDBMS 及NoSQL 的差异
2. 理解MySQL 、Redis 、HBase 基本实现机制、特性、适⽤场景
3. 理解⼏种存储产品的⼤规模分布式服务⽅案
4. 学会使⽤平台的MySQL 、Redis client组件
5. 理解对于MySQL 、Redis 分布式系统设计想要注意的问题
6. 了解平台⼏种典型案例
7. 理解⼏种存储产品在平台的定制修改与名词术语
⼆、存储服务概述
1. 关系型数据库是基于实体关系模型(Entity-Relationship Model)的数据服务,具备以下特点。适合存储结构化数据
查询语⾔SQL ,insert delete update select主流关系型数据库多是持久化存储系统,系统性能与机器性能相关性较⼤
⼏类主流的 关系型数据库MySQL Oracle DB2SQL Server性能局限于服务器性能,与其是磁盘性能局限于数据复杂度
常见的SSD 磁盘服务器,单机读取性能可达万级/s
⼤型互联⽹服务⼤多采⽤MySQL 进⾏作为关系型数据库,微博平台的核⼼业务(如微博内容⽤户微博列表) 也同样如此
本次培训也会着重介绍MySQL 及其分布式架构⽅案。
2. NoSQL(Not only SQL)数据库,泛指⾮关系型的数据库,兴起的契机在于传统关系型数据库应对⼤规模、⾼并发的能⼒有限,⽽NoSQL 的普遍性能优势能够弥补关系型数据库在这⽅⾯的不⾜存储⾮结构化数据、半结构化数据
性能
业界使⽤的NoSQL 多为内存集中型服务,受限于I/O及⽹络,通常请求响应时间在毫秒级别,单机QPS 在10万级别(与数据⼤⼩及存储复杂度相关)
常见的⼏类NoSQL 产品
K-V(Memcached、Redis) ,这类NoSQL 产品在互联⽹业内应⽤范围最⼴。Memcached 提供具备LRU 淘汰策略的K-V 内存存储;⽽Redis 提供⽀持复杂结构(List、Hash 等) 的内存及持久化存储
Column(HBase、Cassandra) ,HBase 是基于列式存储的分布式数据库集群系统Document(MongoDb)
Graph(Neo4J),最庞⼤、最复杂的Graph 模型是⼈的关系,理论上⽤图描述并且⽤Graph 数据库存储最合适不过,不过⽬前的数据规模、系统性能仍然有待优化 web2.0时代,NoSQL 产品在互联⽹⾏业中的重要性随着互联⽹及移动互联⽹的发展⽽与⽇剧增 ⼤型互联⽹应⽤,为应对⼤规模、⾼并发访问,⼤多都引⼊了NoSQL 产品,其中Memcached 、Redis 以其⾼成熟度、⾼性能、⾼稳定性⽽被⼴泛使⽤。微博平台也具备千台规模的NoSQL 集群,微博核⼼的Feed 业务、关系业务也都依赖Memcached 及Redis 提供⾼性能服务
本次培训,会着重介绍Redis 及其分布式架构
三、MySQL 与MySQL 分布式架构设计
微博平台核⼼业务的数据都存储在MySQL 上,⽬前具备千台规模的集群,单个核⼼业务数据突破千亿级,单个核⼼业务QPS 峰值可达10万级每秒,写⼊也是万级每秒。在海量数据并且数据量持续增长的景下,在如何设计满⾜ ⾼并发(w/r)、低延时(10ms级别) 、⾼可⽤性(99.99%) 的分布式MySQL 系统⽅⾯,我们已经具备充⾜的经验并且依然在持续攻坚这⼀问题,⽽我们的课程也会着重介绍海量数据存储之MySQL 。
1. MySQL简介
MySQL 是⼀个关系型数据库系统RDBMS
使⽤SQL 作为查询语⾔开源存储引擎
Innodb ⽀持事务、⾏锁,写⼊性能稍差
MyIsam 不⽀持事务,读写性能略好
满⾜ACID 特性
主键、唯⼀键、外键(⼤规模系统⼀般不⽤)
Transaction ,事务即⼀系列操作,要么完全地执⾏,要么完全地不执⾏
服务、端⼜、实例,都是指 服务端启动的⼀个MySQL 数据库
性能
随着磁盘性能升⾼,读写性能也逐步升⾼,但成本也随之增加
数据库的写⼊性能:写⼊tps 随着并发量增加⽽增加,但上升到⼀定瓶颈,增速放缓⾄并发数临界点后 tps会急剧下滑
思考:如果对性能有更⾼(超出上述三种存储介质并发量级) 的要求怎么办?
定制存储:针对服务特点,定制存储,定制更适合⾃⼰业务场景的存储产品。然⽽⼀般业界成熟产品为考虑通⽤性⽽会牺牲部分性能
引⼊NoSQL
2. 从单机到集群的架构变迁
业务上线初期,web 服务规模较⼩,⼀般具备以下特点
服务原型时期, ⽤户基数⼩, 多种业务公⽤资源, ⽇均写⼊百万级别, 读取千万级别数据规模⼩,单机性能能够满⾜需求
⽤户规模⼩,开发重⼼偏向迭代速度
考虑到上述⼩型业务特点,为节约资源成本及开发成本,可以采⽤多个业务混合部署形式
当⽤户增多,数据量、访问量升⾼(2倍以下) ,数据库压⼒较⼤,怎样在有限程度提⾼MySQL 吞吐量呢?
SQL 优化
硬件升级
压⼒还在有限的范围内增长,通过简单、低成本优化,可以⼀定成都上提⾼有限的服务性能
业务持续发展,读取性能出现瓶颈&&各业务互相影响,多个业务出 现资源抢占,如何快速解决业务抢占问题以提⾼服务性能?
垂直拆分——
按业务进⾏数据拆分
按业务进⾏拆分,以使业务隔离,timeline 的压⼒增加,不会影响content 数据库服务性能;进⾏拆分后,资源增加,服务性能也相应提升。
随着业务的继续发展,读取性能出现瓶颈, 读写互相影响,如何确保读请求量的增加,不要影响写⼊性能?相反写⼊请求量增加如何确保不影响读取性能?(写
⼊性能出现问题会造成数据丢失)
读写分离,写⼊仅写master ,master 与slave ⾃动同步;读取仅以slave
作为来源 读写分离后,slave 仅专注于承担读请求,读取性能得到优化;同⾥独⽴的master 服务的写⼊性能也得到优化。
⼀台/⼀对M-S 服务器性能终归是很有限的,当单实例服务性能⽆法承载线上的请求量时,如何进⾏优化?升级为⼀主多从架构
⼀个master 承载所有写⼊请求,理论上master 性能不变
多个slave 分担读取请求,读取性能提升n
倍随着业务量的增长,服务出现如下变化:数据量增长,意味着原本的存储空间不⾜
写⼊量增长,意味着master 写⼊性能存在瓶颈
读取量增长,意味着slave 读取性能也存在瓶颈,但通过扩充slave 是有限制的:
⼀⽅⾯M-S replication性能有风险;另⼀⽅⾯扩充slave 的成本较⾼如何优化以解决上述问题?
⽔平拆分
业务经历数据量的增长、读写请求量的增长,数据库服务已经演进为分布式架构,⼀个业务的数据,怎样合理的分布到上述复杂的分布式数据库是下⼀个需要解决的问题
3. 如何基于上述演进到最后的架构进⾏数据库设计呢?分布式数据库设计
hash 拆分⽅式,既按hash 规则,将数据读写请求分散到多个实例上,见上述⽔平拆分⽰意图
时间拆分⽅式,基于确定好的时间划分规则,将数据按时间段分散存储再多个实例中
数据分布到⼀个分布式数据库内,⼀个实例存储1/n的数据,⼀个实例只需要⼀个数据库就能够满⾜功能需求。
经历⼏年的发展,数据规模会成倍增长,当需要再次⽔平扩容(4太→8台) ,需要通过程序,将数据⼀分为⼆,数据迁移成本较⾼,需要开发⼈员介⼊。
如果在数据库设计时,⼀个就预先建好2个数据库 ,每个数据库存储1/n/2的数据,需要⽔平扩容时,即可完整迁移⼀个数据库,⽽⽆需开发⼈员⼲预。在⼀个数据库实例上,建⽴的多个数据库,称为逻辑库。逻辑库设计
逻辑库是相对与物理库⽽⾔的概念:物理库只数据库服务的实例;逻辑库指在⼀个数据库实例上创建的多个database
定义逻辑库的⽬的是便于扩容。假如4台数据库服务器,每台上的物理库包含8个逻辑库,当系统出现容量、写⼊量瓶颈时,可以新增⼀倍即4台服务器,直接以同步⽅式同步数据库,⽽不需要单独编写应⽤程序利⽤进⾏导⼊
4. 基于上述分布式数据库下的表拆分设计⽅式
hash 拆分⽅式:按hash 规则将⼀个数据库的数据,分散hash
到多张表中适合数据规模有限的数据集
适合增长速度可控的数据集
结合数据库的hash
模型如图:
根据uid hash到uid 所在到数据库,然后再hash 到数据库_1下的tb_5表按时间拆分⽅式,按时间规则将同⼀时段的数据存储在⼀张表,多个时段时间
存储在多张表。例如按⽉划分,每个⽉表存储⼀个⽉的数据,如果需要获取全
部数据需要跨越多个⽉表适合存储增速较快的数据集
但查询数据需要跨越多个时间段的表
结合数据库的hash
模型如图:
根据uid hash到所在的数据库db_1,然后再查找201507 201506获取两个⽉的数据
思考⼀个问题:如何能够快速定位,⼀个⼈的第1000条到1100条数据呢?⼆级索引快速定位(⼀级) 索引位置描述数据在以及索引中的分布状况
⽤于快速定位/缩⼩查询范围
⼀般情况字段列表:uid, date_time, min_id, count
5. 当⼀台服务器宕机怎么办?
Slave(⼀主多从) 宕机?
剩余健康Slave ⽆风险,则⽆需紧急操作,例⾏修复
切换流量到容灾机房(如果具备容灾机房)
紧急扩容[优先]、重启、替换有损降级部分请求
Master 宕机?
由于master 数据的唯⼀性,致使master
出现异常会直接造成数据写⼊失败
快速下线master
下线⼀台salve 的读服务(如果slave 性能有风险,则同时快速扩容)
提升slave 为master
⽣效新master 与slave 的同步机制
6. 如此复杂的分布式数据库+数据库拆分+数据表拆分,client 端如何便捷操作呢? 多数使⽤分布式数据库服务的团队,都有各⾃实现的数据库Client 组件,微博平台采⽤如下⼏个层级的组建来进⾏分布式数据库操作
获取TableContainer ,获取所有表定义规则通过table name从TableContainer 中获取指定的TableItem TableItem 关联多个JdbcTeplate -DataSource 通过TableItem 结合uid 、id 、date 获取经过hash 计算得到正确的JdbcTemplate 及SQL 使⽤JdbcTemplate 进⾏SQL 操作
7. 注意事项
MySQL 设计应该注意的问题
表字符集选择UTF8
存储引擎使⽤InnoDB
使⽤Varchar/Varbinary存储变长字符串不在数据库中存储图⽚、⽂件等
每张表数据量控制在20000W 以下提前对业务做好垂直拆分
MySQL 查询应该遇到的问题避免使⽤存储过程、触发器、函数等
让数据库做最擅长的事
降低业务耦合度避开服务端BUG
避免使⽤⼤表的JOIN
MySQL 最擅长的是单表的主键/索引查询
JOIN 消耗较多内存, 产⽣临时表避免在数据库中进⾏数学运算
MySQL 不擅长数学运算⽆法使⽤索引减少与数据库的交互次数
select 条件查询要利⽤索引
同⼀字段的条件判定要⽤in ⽽不要⽤or
8. MySQL练习题
设计⼀个每秒2000qps ,1亿条数据的⽤户基本信息存储数据库。完成数据库设计,数据库搭建,web 写⼊查询服务搭建。
定义⽤户信息结构:uid ,name ,age ,
gender
给定2个mysql 实例,每个实例创建2个数据库
每个数据库创建2长表
编写代码,以hash 形式,实现对数据库、表的数据操作
四、Redis 与Redis 分布式架构设计
微博作为web2.0时代具备代表性的SNS 服务,具备庞⼤的⽤户群体和亿级的活跃⽤户,同时也承担着⾼并发、低延迟的服务性能压⼒。
Redis作为NoSQL 系列的⼀个典型应⽤,以其⾼成熟度、⾼可⽤性、⾼性能⽽被⽤来解决web2.0时代关系型数据库性能瓶颈问题。例如微博的计数服务的请求量以达到百万级/s,数以百计的关系型数据库才能应对如此⾼的QPS ,⽽且请求耗时较⾼且波动较⼤;然⽽使⽤Redis 这种NoSQL 产品,仅仅需要10台级别的集群即可应对,平均请求耗时5ms 以下。
这⼀章节,为⼤家介绍Redis 以及其⼤规模集群架构。
1. Redis简介
Redis 是⼀个⽀持内存存储及持久化存储的K-V 存储系统
⽀持复杂数据结构,相⽐与Memcached 仅⽀持简单的key-value 存储,Redis 原⽣⽀持⼏类常⽤的存储结构,例如
hash :存储哈希结构数据
list :存储列表数据单线程⾼性能,避免过多考虑并发、锁、上下⽂切换
数据⼀致性好,例如对⼀个计数的并发操作,不会有‘读者写者’问题单线程⽆法利⽤多核,单可以通过启动多个实例⽅式,充分利⽤多核
原⽣⽀持Master-Slave 过期机制
被动过期——client访问key 时,判断过期时间选择是否过期
主动过期——默认使⽤valatile-lru
volatile-lru :从已设置过期时间的数据集中挑选最近最少使⽤的数据淘汰
volatile-ttl :从已设置过期时间的数据集中挑选将要过期的数据淘汰
volatile-random :从已设置过期时间的数据集中任意选择数据淘汰
allkeys-lru :从全部数据集中挑选最近最少使⽤的数据淘汰
allkeys-random :从全部数据集中任意选择数据淘汰no-enviction (驱逐):禁⽌驱逐数据
Redis 的字典表结构
Key 字典表hash table结构,有hash 结构就意味着需要按需进⾏rehash ,rehash 的时间段内,对内存是有成倍开销的
Value 结构,存储Key 对应的value
Expire 表结构,存储key 的过期时间
额外开销60B+持久化⽅式AOF
Snapshot——RDB⽂件快照
与MC
的差异
平台的定制CounterService
修改hash table为,增量扩展式的hash tables,例如每1亿个key 存储在⼀个table 中,数据超过1亿(或者⼀个临界⽐例) 则开辟下⼀个1亿空间的table
废弃expire ,Redis 的主动过期策略⽆法像MC 的LRU 策略确保热数据留存在内存中,冷数据从缓存剔除,我们多数场景需要控制Redis 中的数据量不突破内存限制
2. Redis的主要数据结构
String (key-value)
Hash (key-field -value)
List(key-values)
Set(key-members)
SortedSet(key-member -score)
3. Redis的分布式部署⽅案是怎样的?与MySQL 有什么异同
Reids 由于其M-S 特性与MySQL 类似,因此分布式部署⽅案同MySQL 相当
单实例——⼩型业务 or 业务初期
主从——HA、读写分离
⼀主多从——读取性能出现瓶颈
数据⽔平拆分——容量不⾜|写⼊性能瓶颈
常⽤的分布式部署⽅案
4. 分布式Redis 架构如何实现⾼可⽤(HA)?
采⽤M-S ⾼可⽤⽅案,原因也式由于其Master-Slave 的特性
服务域名化是必要的,⽬前⼤型的Redis 集群应⽤⼤多采⽤域名⽅式
5. 基本容量规划
空间=key 数量*单条占⽤(K-V占⽤+额外空间) ⽤户空间=5亿⽤户*200B(平均) =100G 微博计数器=(500亿+预期2年新增300亿) *10B =800G
访问量=服务访问量*单次访问对资源的hit 量 微博计数器Feed 访问量=10000/s* 20 = 20万/s
6. CounterService
微博具备庞⼤的数据基数,因此所需要存储的数据量级也极其庞⼤
例如微博计数器,具有百亿条纪录,全部存储在Redis 中,需要T 级别的空间,成本过⾼
因此我们对Redis 进⾏定制化改造,以使其适合多数数据⼩,⼤⼩有固定限制的数据优化存储空间
采⽤分段哈希桶的形式,进⾏存储,避免rehash (分段存储要求key 为递增序
) 空间占⽤优化效果
key :8B
value :⾃定义
7. 如何⽀持上述分布式架构下的client 访问?(redis3.0+⽀持Redis Cluster)
Reids 具有多个开源的client ⽀持,我们所使⽤的是Jedis
Jedis 除了提供client 外,还提供了操作封装以及M-S 组件
我们所使⽤的Redis 系列组件如下:
8. Redis练习题
使⽤Redis ,实现⽤户受到的赞列表及赞计数功能
使⽤测试环境,启动两个Redis 实例
使⽤Redis 存储⽤户受到的赞列表[{uid, time}..]及赞计数uid-count
完成赞操作业务逻辑,包括赞、取消赞、查看赞列表、查看赞计数
五、思考与讨论
1. Memcache当容量到达瓶颈会 截取LRU 链以释放空间。上⽂介绍过Redis 的key 过期机制,思考以下⼏个问题:
Redis 满了会发⽣什么?如何避免发⽣上述问题呢?
为什么我们的定制Redis 会废弃expire 表?
2. MySQL与Redis 各⾃适合什么样的场景?数据冷热?数据⼤⼩?数据量级?数据增长速度?是否持久化?
访问量(read/write)?
请求性能要求?
新兵训练营简介
微博平台新兵训练营活动是微博平台内部组织的针对新⼊职同学的团队融⼊培训课程,⽬标是团队融⼊,包括⼈的融⼊,氛围融⼊,技术融⼊。当前已经进⾏4期活动,很多学员迅速成长为平台技术⾻⼲。
微博平台是⾮常注重团队成员融⼊与成长的团队,在这⾥有⼈帮你融⼊,有⼈和你⼀起成长,也欢迎⼩伙伴们加⼊微博平台,欢迎私信咨询。
讲师简介
毕建坤, 微博平台及⼤数据部——平台研发系统研发⼯程师,2012年7⽉毕业于哈尔滨理⼯⼤学,校招⼊职微博⼯作⾄今,先后负责微博Feed 、赞、评论等底层服务研发以及⽅案评审等⼯作。聚焦⼤规模系统的架构设计与优化,以及⼤规模系统下的服务稳定性保障。新兵训练营第⼀期学员。
W3Cschool (www.w3cschool.cn )最⼤的技术知识分享与学习平台此篇内容来⾃于w3cschool.cn ⽹站⽤户上传并发布。
海量数据存储基础
原⽂出处:作者:毕建坤
微博平台研发作为微博的底层数据及业务⽀撑部门,已经经历了5年的发展历程。伴随着从数据及业务暴发式增长,我们在海量数据存储⽅⾯遭遇了诸多挑战,与此同时也伴随着丰富经验的积累。
本次新兵训练营,受众在于应届毕业⽣,⽬的在于让新同学系统化并且有针对性的了解平台的核⼼技术及核⼼业务,以使新同学在新兵训练营结束后,能够对平台的底层架构与业务有⼀定的了解。
本⽂主要⾯向新同学介绍平台的核⼼技术之⼀——海量数据存储,主要介绍在海量数据存储在⼤规模分布式系统下的架构变迁与设计。课程⼤纲:⼀、课程⽬标
1. 了解存储服务概况,以及RDBMS 及NoSQL 的差异
2. 理解MySQL 、Redis 、HBase 基本实现机制、特性、适⽤场景
3. 理解⼏种存储产品的⼤规模分布式服务⽅案
4. 学会使⽤平台的MySQL 、Redis client组件
5. 理解对于MySQL 、Redis 分布式系统设计想要注意的问题
6. 了解平台⼏种典型案例
7. 理解⼏种存储产品在平台的定制修改与名词术语
⼆、存储服务概述
1. 关系型数据库是基于实体关系模型(Entity-Relationship Model)的数据服务,具备以下特点。适合存储结构化数据
查询语⾔SQL ,insert delete update select主流关系型数据库多是持久化存储系统,系统性能与机器性能相关性较⼤
⼏类主流的 关系型数据库MySQL Oracle DB2SQL Server性能局限于服务器性能,与其是磁盘性能局限于数据复杂度
常见的SSD 磁盘服务器,单机读取性能可达万级/s
⼤型互联⽹服务⼤多采⽤MySQL 进⾏作为关系型数据库,微博平台的核⼼业务(如微博内容⽤户微博列表) 也同样如此
本次培训也会着重介绍MySQL 及其分布式架构⽅案。
2. NoSQL(Not only SQL)数据库,泛指⾮关系型的数据库,兴起的契机在于传统关系型数据库应对⼤规模、⾼并发的能⼒有限,⽽NoSQL 的普遍性能优势能够弥补关系型数据库在这⽅⾯的不⾜存储⾮结构化数据、半结构化数据
性能
业界使⽤的NoSQL 多为内存集中型服务,受限于I/O及⽹络,通常请求响应时间在毫秒级别,单机QPS 在10万级别(与数据⼤⼩及存储复杂度相关)
常见的⼏类NoSQL 产品
K-V(Memcached、Redis) ,这类NoSQL 产品在互联⽹业内应⽤范围最⼴。Memcached 提供具备LRU 淘汰策略的K-V 内存存储;⽽Redis 提供⽀持复杂结构(List、Hash 等) 的内存及持久化存储
Column(HBase、Cassandra) ,HBase 是基于列式存储的分布式数据库集群系统Document(MongoDb)
Graph(Neo4J),最庞⼤、最复杂的Graph 模型是⼈的关系,理论上⽤图描述并且⽤Graph 数据库存储最合适不过,不过⽬前的数据规模、系统性能仍然有待优化 web2.0时代,NoSQL 产品在互联⽹⾏业中的重要性随着互联⽹及移动互联⽹的发展⽽与⽇剧增 ⼤型互联⽹应⽤,为应对⼤规模、⾼并发访问,⼤多都引⼊了NoSQL 产品,其中Memcached 、Redis 以其⾼成熟度、⾼性能、⾼稳定性⽽被⼴泛使⽤。微博平台也具备千台规模的NoSQL 集群,微博核⼼的Feed 业务、关系业务也都依赖Memcached 及Redis 提供⾼性能服务
本次培训,会着重介绍Redis 及其分布式架构
三、MySQL 与MySQL 分布式架构设计
微博平台核⼼业务的数据都存储在MySQL 上,⽬前具备千台规模的集群,单个核⼼业务数据突破千亿级,单个核⼼业务QPS 峰值可达10万级每秒,写⼊也是万级每秒。在海量数据并且数据量持续增长的景下,在如何设计满⾜ ⾼并发(w/r)、低延时(10ms级别) 、⾼可⽤性(99.99%) 的分布式MySQL 系统⽅⾯,我们已经具备充⾜的经验并且依然在持续攻坚这⼀问题,⽽我们的课程也会着重介绍海量数据存储之MySQL 。
1. MySQL简介
MySQL 是⼀个关系型数据库系统RDBMS
使⽤SQL 作为查询语⾔开源存储引擎
Innodb ⽀持事务、⾏锁,写⼊性能稍差
MyIsam 不⽀持事务,读写性能略好
满⾜ACID 特性
主键、唯⼀键、外键(⼤规模系统⼀般不⽤)
Transaction ,事务即⼀系列操作,要么完全地执⾏,要么完全地不执⾏
服务、端⼜、实例,都是指 服务端启动的⼀个MySQL 数据库
性能
随着磁盘性能升⾼,读写性能也逐步升⾼,但成本也随之增加
数据库的写⼊性能:写⼊tps 随着并发量增加⽽增加,但上升到⼀定瓶颈,增速放缓⾄并发数临界点后 tps会急剧下滑
思考:如果对性能有更⾼(超出上述三种存储介质并发量级) 的要求怎么办?
定制存储:针对服务特点,定制存储,定制更适合⾃⼰业务场景的存储产品。然⽽⼀般业界成熟产品为考虑通⽤性⽽会牺牲部分性能
引⼊NoSQL
2. 从单机到集群的架构变迁
业务上线初期,web 服务规模较⼩,⼀般具备以下特点
服务原型时期, ⽤户基数⼩, 多种业务公⽤资源, ⽇均写⼊百万级别, 读取千万级别数据规模⼩,单机性能能够满⾜需求
⽤户规模⼩,开发重⼼偏向迭代速度
考虑到上述⼩型业务特点,为节约资源成本及开发成本,可以采⽤多个业务混合部署形式
当⽤户增多,数据量、访问量升⾼(2倍以下) ,数据库压⼒较⼤,怎样在有限程度提⾼MySQL 吞吐量呢?
SQL 优化
硬件升级
压⼒还在有限的范围内增长,通过简单、低成本优化,可以⼀定成都上提⾼有限的服务性能
业务持续发展,读取性能出现瓶颈&&各业务互相影响,多个业务出 现资源抢占,如何快速解决业务抢占问题以提⾼服务性能?
垂直拆分——
按业务进⾏数据拆分
按业务进⾏拆分,以使业务隔离,timeline 的压⼒增加,不会影响content 数据库服务性能;进⾏拆分后,资源增加,服务性能也相应提升。
随着业务的继续发展,读取性能出现瓶颈, 读写互相影响,如何确保读请求量的增加,不要影响写⼊性能?相反写⼊请求量增加如何确保不影响读取性能?(写
⼊性能出现问题会造成数据丢失)
读写分离,写⼊仅写master ,master 与slave ⾃动同步;读取仅以slave
作为来源 读写分离后,slave 仅专注于承担读请求,读取性能得到优化;同⾥独⽴的master 服务的写⼊性能也得到优化。
⼀台/⼀对M-S 服务器性能终归是很有限的,当单实例服务性能⽆法承载线上的请求量时,如何进⾏优化?升级为⼀主多从架构
⼀个master 承载所有写⼊请求,理论上master 性能不变
多个slave 分担读取请求,读取性能提升n
倍随着业务量的增长,服务出现如下变化:数据量增长,意味着原本的存储空间不⾜
写⼊量增长,意味着master 写⼊性能存在瓶颈
读取量增长,意味着slave 读取性能也存在瓶颈,但通过扩充slave 是有限制的:
⼀⽅⾯M-S replication性能有风险;另⼀⽅⾯扩充slave 的成本较⾼如何优化以解决上述问题?
⽔平拆分
业务经历数据量的增长、读写请求量的增长,数据库服务已经演进为分布式架构,⼀个业务的数据,怎样合理的分布到上述复杂的分布式数据库是下⼀个需要解决的问题
3. 如何基于上述演进到最后的架构进⾏数据库设计呢?分布式数据库设计
hash 拆分⽅式,既按hash 规则,将数据读写请求分散到多个实例上,见上述⽔平拆分⽰意图
时间拆分⽅式,基于确定好的时间划分规则,将数据按时间段分散存储再多个实例中
数据分布到⼀个分布式数据库内,⼀个实例存储1/n的数据,⼀个实例只需要⼀个数据库就能够满⾜功能需求。
经历⼏年的发展,数据规模会成倍增长,当需要再次⽔平扩容(4太→8台) ,需要通过程序,将数据⼀分为⼆,数据迁移成本较⾼,需要开发⼈员介⼊。
如果在数据库设计时,⼀个就预先建好2个数据库 ,每个数据库存储1/n/2的数据,需要⽔平扩容时,即可完整迁移⼀个数据库,⽽⽆需开发⼈员⼲预。在⼀个数据库实例上,建⽴的多个数据库,称为逻辑库。逻辑库设计
逻辑库是相对与物理库⽽⾔的概念:物理库只数据库服务的实例;逻辑库指在⼀个数据库实例上创建的多个database
定义逻辑库的⽬的是便于扩容。假如4台数据库服务器,每台上的物理库包含8个逻辑库,当系统出现容量、写⼊量瓶颈时,可以新增⼀倍即4台服务器,直接以同步⽅式同步数据库,⽽不需要单独编写应⽤程序利⽤进⾏导⼊
4. 基于上述分布式数据库下的表拆分设计⽅式
hash 拆分⽅式:按hash 规则将⼀个数据库的数据,分散hash
到多张表中适合数据规模有限的数据集
适合增长速度可控的数据集
结合数据库的hash
模型如图:
根据uid hash到uid 所在到数据库,然后再hash 到数据库_1下的tb_5表按时间拆分⽅式,按时间规则将同⼀时段的数据存储在⼀张表,多个时段时间
存储在多张表。例如按⽉划分,每个⽉表存储⼀个⽉的数据,如果需要获取全
部数据需要跨越多个⽉表适合存储增速较快的数据集
但查询数据需要跨越多个时间段的表
结合数据库的hash
模型如图:
根据uid hash到所在的数据库db_1,然后再查找201507 201506获取两个⽉的数据
思考⼀个问题:如何能够快速定位,⼀个⼈的第1000条到1100条数据呢?⼆级索引快速定位(⼀级) 索引位置描述数据在以及索引中的分布状况
⽤于快速定位/缩⼩查询范围
⼀般情况字段列表:uid, date_time, min_id, count
5. 当⼀台服务器宕机怎么办?
Slave(⼀主多从) 宕机?
剩余健康Slave ⽆风险,则⽆需紧急操作,例⾏修复
切换流量到容灾机房(如果具备容灾机房)
紧急扩容[优先]、重启、替换有损降级部分请求
Master 宕机?
由于master 数据的唯⼀性,致使master
出现异常会直接造成数据写⼊失败
快速下线master
下线⼀台salve 的读服务(如果slave 性能有风险,则同时快速扩容)
提升slave 为master
⽣效新master 与slave 的同步机制
6. 如此复杂的分布式数据库+数据库拆分+数据表拆分,client 端如何便捷操作呢? 多数使⽤分布式数据库服务的团队,都有各⾃实现的数据库Client 组件,微博平台采⽤如下⼏个层级的组建来进⾏分布式数据库操作
获取TableContainer ,获取所有表定义规则通过table name从TableContainer 中获取指定的TableItem TableItem 关联多个JdbcTeplate -DataSource 通过TableItem 结合uid 、id 、date 获取经过hash 计算得到正确的JdbcTemplate 及SQL 使⽤JdbcTemplate 进⾏SQL 操作
7. 注意事项
MySQL 设计应该注意的问题
表字符集选择UTF8
存储引擎使⽤InnoDB
使⽤Varchar/Varbinary存储变长字符串不在数据库中存储图⽚、⽂件等
每张表数据量控制在20000W 以下提前对业务做好垂直拆分
MySQL 查询应该遇到的问题避免使⽤存储过程、触发器、函数等
让数据库做最擅长的事
降低业务耦合度避开服务端BUG
避免使⽤⼤表的JOIN
MySQL 最擅长的是单表的主键/索引查询
JOIN 消耗较多内存, 产⽣临时表避免在数据库中进⾏数学运算
MySQL 不擅长数学运算⽆法使⽤索引减少与数据库的交互次数
select 条件查询要利⽤索引
同⼀字段的条件判定要⽤in ⽽不要⽤or
8. MySQL练习题
设计⼀个每秒2000qps ,1亿条数据的⽤户基本信息存储数据库。完成数据库设计,数据库搭建,web 写⼊查询服务搭建。
定义⽤户信息结构:uid ,name ,age ,
gender
给定2个mysql 实例,每个实例创建2个数据库
每个数据库创建2长表
编写代码,以hash 形式,实现对数据库、表的数据操作
四、Redis 与Redis 分布式架构设计
微博作为web2.0时代具备代表性的SNS 服务,具备庞⼤的⽤户群体和亿级的活跃⽤户,同时也承担着⾼并发、低延迟的服务性能压⼒。
Redis作为NoSQL 系列的⼀个典型应⽤,以其⾼成熟度、⾼可⽤性、⾼性能⽽被⽤来解决web2.0时代关系型数据库性能瓶颈问题。例如微博的计数服务的请求量以达到百万级/s,数以百计的关系型数据库才能应对如此⾼的QPS ,⽽且请求耗时较⾼且波动较⼤;然⽽使⽤Redis 这种NoSQL 产品,仅仅需要10台级别的集群即可应对,平均请求耗时5ms 以下。
这⼀章节,为⼤家介绍Redis 以及其⼤规模集群架构。
1. Redis简介
Redis 是⼀个⽀持内存存储及持久化存储的K-V 存储系统
⽀持复杂数据结构,相⽐与Memcached 仅⽀持简单的key-value 存储,Redis 原⽣⽀持⼏类常⽤的存储结构,例如
hash :存储哈希结构数据
list :存储列表数据单线程⾼性能,避免过多考虑并发、锁、上下⽂切换
数据⼀致性好,例如对⼀个计数的并发操作,不会有‘读者写者’问题单线程⽆法利⽤多核,单可以通过启动多个实例⽅式,充分利⽤多核
原⽣⽀持Master-Slave 过期机制
被动过期——client访问key 时,判断过期时间选择是否过期
主动过期——默认使⽤valatile-lru
volatile-lru :从已设置过期时间的数据集中挑选最近最少使⽤的数据淘汰
volatile-ttl :从已设置过期时间的数据集中挑选将要过期的数据淘汰
volatile-random :从已设置过期时间的数据集中任意选择数据淘汰
allkeys-lru :从全部数据集中挑选最近最少使⽤的数据淘汰
allkeys-random :从全部数据集中任意选择数据淘汰no-enviction (驱逐):禁⽌驱逐数据
Redis 的字典表结构
Key 字典表hash table结构,有hash 结构就意味着需要按需进⾏rehash ,rehash 的时间段内,对内存是有成倍开销的
Value 结构,存储Key 对应的value
Expire 表结构,存储key 的过期时间
额外开销60B+持久化⽅式AOF
Snapshot——RDB⽂件快照
与MC
的差异
平台的定制CounterService
修改hash table为,增量扩展式的hash tables,例如每1亿个key 存储在⼀个table 中,数据超过1亿(或者⼀个临界⽐例) 则开辟下⼀个1亿空间的table
废弃expire ,Redis 的主动过期策略⽆法像MC 的LRU 策略确保热数据留存在内存中,冷数据从缓存剔除,我们多数场景需要控制Redis 中的数据量不突破内存限制
2. Redis的主要数据结构
String (key-value)
Hash (key-field -value)
List(key-values)
Set(key-members)
SortedSet(key-member -score)
3. Redis的分布式部署⽅案是怎样的?与MySQL 有什么异同
Reids 由于其M-S 特性与MySQL 类似,因此分布式部署⽅案同MySQL 相当
单实例——⼩型业务 or 业务初期
主从——HA、读写分离
⼀主多从——读取性能出现瓶颈
数据⽔平拆分——容量不⾜|写⼊性能瓶颈
常⽤的分布式部署⽅案
4. 分布式Redis 架构如何实现⾼可⽤(HA)?
采⽤M-S ⾼可⽤⽅案,原因也式由于其Master-Slave 的特性
服务域名化是必要的,⽬前⼤型的Redis 集群应⽤⼤多采⽤域名⽅式
5. 基本容量规划
空间=key 数量*单条占⽤(K-V占⽤+额外空间) ⽤户空间=5亿⽤户*200B(平均) =100G 微博计数器=(500亿+预期2年新增300亿) *10B =800G
访问量=服务访问量*单次访问对资源的hit 量 微博计数器Feed 访问量=10000/s* 20 = 20万/s
6. CounterService
微博具备庞⼤的数据基数,因此所需要存储的数据量级也极其庞⼤
例如微博计数器,具有百亿条纪录,全部存储在Redis 中,需要T 级别的空间,成本过⾼
因此我们对Redis 进⾏定制化改造,以使其适合多数数据⼩,⼤⼩有固定限制的数据优化存储空间
采⽤分段哈希桶的形式,进⾏存储,避免rehash (分段存储要求key 为递增序
) 空间占⽤优化效果
key :8B
value :⾃定义
7. 如何⽀持上述分布式架构下的client 访问?(redis3.0+⽀持Redis Cluster)
Reids 具有多个开源的client ⽀持,我们所使⽤的是Jedis
Jedis 除了提供client 外,还提供了操作封装以及M-S 组件
我们所使⽤的Redis 系列组件如下:
8. Redis练习题
使⽤Redis ,实现⽤户受到的赞列表及赞计数功能
使⽤测试环境,启动两个Redis 实例
使⽤Redis 存储⽤户受到的赞列表[{uid, time}..]及赞计数uid-count
完成赞操作业务逻辑,包括赞、取消赞、查看赞列表、查看赞计数
五、思考与讨论
1. Memcache当容量到达瓶颈会 截取LRU 链以释放空间。上⽂介绍过Redis 的key 过期机制,思考以下⼏个问题:
Redis 满了会发⽣什么?如何避免发⽣上述问题呢?
为什么我们的定制Redis 会废弃expire 表?
2. MySQL与Redis 各⾃适合什么样的场景?数据冷热?数据⼤⼩?数据量级?数据增长速度?是否持久化?
访问量(read/write)?
请求性能要求?
新兵训练营简介
微博平台新兵训练营活动是微博平台内部组织的针对新⼊职同学的团队融⼊培训课程,⽬标是团队融⼊,包括⼈的融⼊,氛围融⼊,技术融⼊。当前已经进⾏4期活动,很多学员迅速成长为平台技术⾻⼲。
微博平台是⾮常注重团队成员融⼊与成长的团队,在这⾥有⼈帮你融⼊,有⼈和你⼀起成长,也欢迎⼩伙伴们加⼊微博平台,欢迎私信咨询。
讲师简介
毕建坤, 微博平台及⼤数据部——平台研发系统研发⼯程师,2012年7⽉毕业于哈尔滨理⼯⼤学,校招⼊职微博⼯作⾄今,先后负责微博Feed 、赞、评论等底层服务研发以及⽅案评审等⼯作。聚焦⼤规模系统的架构设计与优化,以及⼤规模系统下的服务稳定性保障。新兵训练营第⼀期学员。
W3Cschool (www.w3cschool.cn )最⼤的技术知识分享与学习平台此篇内容来⾃于w3cschool.cn ⽹站⽤户上传并发布。