Skip to content

大规模高性能分布式存储系统(2月26日)

lirui edited this page Mar 1, 2021 · 1 revision

MongoDB

架构设计:MongoDB Server 数据存储节点,一个实例上面可以存储好多个数据库,数据库下面可以存储很多表,表里面又可以存储很多document这个东西

数据逻辑结构,从视图的角度

体系结构:

数据逻辑关系:文档(document)、集合(colection)、数据库(database)

层级关系图:

MongoDB与RDBMS数据逻辑结构对比:

MongoDB RDBMS(关系型数据库)

文档(Document) 行(Row)

集合(Collection) 表(Table)

数据库(Database) 数据库(Database)

系统结构

数据存储 默认存储路径 /data/db(数据) /data/log(日志) 数据库数据组成 数据库名.ns (元数据存储) 数据库名.0 数据库名.1 ... 数据库名.n

MongoDB生态系统:微观的生态系统;pas

MongoDB集群构成:数据服务节点(Mongod);路由节点(mongos);配置节点(mongod)->config server;投票节点/表决节点(mongod)->arbiter pasos协议

MongoDB部署实践:

Replic Set+Sharding:Shard Server(Replica Set)(n)、Config Server(n)、Route Server(n)、Arbiter Server(n)、增加Shard Server、RS内部增减、读写分离、故障转移、库级sharding(move primary)、表级手动sharding、auto-sharding(指定时间段凌晨)

HBase:Hadoop database,hadoop数据库;面向列的开源数据库;分布式、高可靠、高性能、高伸缩性、基于HDFS作为文件存储系统

适用场景:半结构化或者结构化数据(数据结构字段不够确定);记录非常稀疏(RDBMS列固定、NULL列浪费、NULL Column不会被存储、节省空间、提高读性能);多版本数据;超大数据量(分库分表、HBase自动水平切分)

系统架构:HClient(客户端)、HMaster(元数据节点)、HRegionServer(数据存储节点)、Zookeeper(协调)

HClient:基于Hbase的RPC机制与HMaster和HRegionServer通信

管理类操作:HClient与HMasterRPC

数据读写类操作:HClient与HRegionServer RPC

HMaster:没有单点概念,可以启动多个HMaster,基于ZooKeeper的Master Election机制保障一个Master运行;负责Table和Region的管理工作;管理用户对Table的CURD;管理HRegionServer的负载均衡,调整Region分布;在Region分裂后,负责新的Region分配;在HRegionServer停机后,负责此机器上Regions的数据迁移

HRegionServer:负责响应用户IO请求;向HDFS文件系统中读写数据;是HBase中最核心的模块;管理一系列HRegion对象;每个HRegion对应了table中的一个Region;HRegion中有多个HStore组成;每个HStore对应了Table中的一个Column Family存储;Column Family是一个集中的存储单元;具备IO特性的Column放在一个Column Family中,最高效

Zookeeper:存储-ROOT-表地址;存储HMaster地址;HRegionServer会注册到Zookeeper中;HMaster可以随时感知各个HRegionServer的健康状态;zk避免了HMaster的单点问题

第四讲:大规模高性能分布式存储系统之一致性篇

什么是一致性:通常是指关联数据是否完整和正确;分布式系统;多个数据中心数据一致;每个访问用户看到的数据具有一致性

原子性:一个事务中的所有操作;要么全部完成,要么全部不完成;不会结束在中间某个状态;事务在执行过程中发生错误,会被回滚到事务开始前的状态

原子性和一致性的区别以及联系:是事务ACID四个特性中的2个特性;保证原子性,一致性必要满足;一致性保证,不要求必须满足原子性;充分条件,非必要条件;2PC 原子性问题;Paxos 一致性问题;两者结合使用

一致性的几个等级

----强一致性(严格一致性)任何时间任何地点都要保证一致性

读出的数据始终为最新写入的数据,这种一致性只有全局始终存在时才能可能,分布式系统不可能实现

----弱一致性(最终一致性)

当没有新更新的情况下,更新最终会通过网络传播到所有副本点,所有副本点最终会一致,也就是说使用者在最终某个时间点前的中间过程中无法保证看到的是新写入的数据

采用最终一致性模型一个关键要求

读出脏数据是可以接受的

分布式系统基本都是这种一致性模型

MongoDB

注重用户访问和性能

……

----顺序一致性

----因果一致性

----释放一致性

----其他一致性模型

分布式存储系统如何做到一致性

----分布式锁

控制分布式系统中同步访问共享资源的一种方式;不同的系统、模块需要访问共享资源的时候,需要互斥来防止彼此干扰,从而来保证一致性;在这种情况下,便需要使用到分布式锁;

应用场景:在很多互联网产品应用中,需要分布式加锁处理;秒杀,全局递增ID,商品下订单、抢红包等等

实现方式:基于DB实现,基于Redis的实现方式(单进程单线程模式、采用队列模式将并发访问变成串行访问、多客户端对Redis的连接并不存在竞争关系)

基于Redis实现方式:

实现分布式锁的四个命令:

----SETNX命令(SET if Not eXists)

 语法:

 SETNX key value

 功能:

 当且仅当key不存在,将key值设为value,并返回1;若给定的key已经存在,则SETNX不做任何动作,并返回0

----GETSET

  语法:

  GETSET key value

  功能:

   将给定key的值设为value,并返回key的旧值,当key不存在的时候,返回nil

----GET命令

  语法:

  GET key

  功能:

  返回key所对应的字符串值,如果key不存在,则返回nil

----DEL命令

  语法:

  DEL key [KEY …]

  功能:

  删除给定的一个或多个key,不存在的key会被忽略,返回成功删除的数量

第一步加锁,SETNX加锁实现,调用SETNX foo.lock [current unix time],返回为1获取到锁,返回为0没有获取到锁;

第二部解锁,完成操作后,释放锁,DELfoo.lock

操作不是原子性的,是分布式的,所以可能在第二步出现错误,一旦出现错误,就会变成死锁

死锁的情况:加锁进程崩溃;加锁进程释放锁没有成功(网络异常等);死锁

怎么办:需要检查锁的时效性;一段时间后,锁失效了;在大并发情况,如果同时检测锁失效,如果检测到锁失效,就简单粗暴地删除死锁,再通过SETNX上锁,但是这种情况,可能会导致竞争条件的产生,即多个客户端同时获取锁

示例:

锁竞争情况:

----C1获取锁,并崩溃

----C2和C3调用SETNX上锁返回0后,获得foo.lock的时间戳,通过比对时间戳,发现锁超时

----C2向foo.lock发送DEL命令

----C2向foo.lock发送SETNX获取锁

----C3向foo.lock发送DEL命令,此时C3发送DEL时,其实DEL掉的是C2的锁

----C3向foo.lock发送SETNX获取锁

----此时C2和C3都获取了锁,产生了锁竞争情况

如何做?----GETSET派上用场

基于GETSET消除锁竞争情况:

----假设另外一个客户端C4,我们使用GETSET方式,避免锁竞争

----C1获取锁,并崩溃

----C4调用SETNX上锁返回0后,调用GET命令获得foo.lock的时间戳T1,通过比对时间戳,发现锁超时

----C4向foo.lock发送GETSET命令

----GETSET foo.lock

----并得到foo.lock中老的时间戳T2

----如果T1=T2,说明C4获得锁

----如果T1!=T2,说明C4之前有另外一个客户端通过调用GETSET方式获取了锁,C4未获得锁。sleep,进入下次循环中

异常处理:

----Get 返回nil,循环走setnx逻辑

----------C1客户端获取锁,并且处理完后,DEL掉锁,在DEL锁之前,C2通过SETNX向foo.lock设置时间戳T0发现有客户端获取锁,进入GET操作

----------C2向foo.lock发送GET命令,获取返回值T1(nil)

----------C2循环,进入下一次SETNX逻辑

----GETSET返回nil

-----------C1和C2客户端调用GET接口,C1返回T1,此时C3网络情况更好,快速进入获取锁,并执行DEL删除锁,C2返回T2(nil),C1和C2都进入超时处理逻辑

-----------C1向foo.lock发送GETSET命令,获取返回值T11(nil)

-----------C1比对T1和T11发现两者不同,处理逻辑认为未获取锁

-----------C2向foo.lock发送GETSET命令,获取返回值T22(C1写入的时间戳)

-----------C2比对C2和C22发现两者不同,处理逻辑认为未获取锁

-----------C1nil处理,实际上已经获取到锁

分布式锁:

1、超时机制:避免死锁

2、多客户端的时间戳不能保证严格意义的一致性,有可能存在锁竞争的情况,要适度的机制,可以承受小概率的事件产生

3、只对关键处理节点加锁,加锁,获取连接;释放锁;减少加锁时间

4、Double check机制。严重依赖锁的状态,在最关键步骤中做锁的check检查机制

5、Sleep机制,减少对Redis的压力

Clone this wiki locally