基本需求
- 可扩展
Memcached和DB可以动态添加,不需要修改程序和重启任何服务
- 可监控
系统可以监控集群中某个节点是否异常,资源占用情况,缓存命中率如何,系统当前压力,且当压力到达一个阀值时提供异常报警机制,有详细的错误日志,便于排查问题
- 可维护
维护人员可以对系统进行修改,测试,部署
- 可定制
集群系统可以根据应用需求定制分布式策略
- 高可用(高可读,高可写)
集群系统中单个节点出故障,不影响整个系统的使用
- 容错
系统出现错误,系统可以自动恢复
在Dynamo系统中通过三个参数(N,R,W)来实现可用性和容错性的平衡。对于数据存储系统来说,Dynamo的节点采用冗余存储是保证容错性的必要手段,N就代表一份数据将会在系统多少个节点存储。R表示在读取某一存储的数据时,最少参与节点数,也就是最少需要有多少个节点返回存储的信息才算是成功读取了该数据内容。W表示在存储某一个数据时,最少参与节点数,也就是最少要有多少个节点表示存储成功才算是成功存储了该数据
对于读操作十分密集写相对来说较少的情况来说,配置R=1,W=N,则可以实现高读引擎,系统只要还有一个节点可以读取数据就可以读到数据
对于写比较频繁的情况来说,那么可以配置R=N,W=1实现高写引擎,系统只要还有一个节点可以写入,就可以保证业务写入的正常,不过读取数据进行冲突解决会比较复杂一些
- 容灾
当出现灾难时,可由异地系统迅速接替本地系统而保证业务的连续性
应用需求
分布式数据库
问题
1. 数据存储的能否平均每台机器上?
>> 渠道号是手动干预的,数据存储的分配是不均的
>> 按hash值分配是系统控制的,数据存储分配是比较平均的
2. 数据访问控制能否平均到各个负载的机器上?
>> 通过权值来控制,每个机器上都有一个权重,权重大的访问数量大,权重低的访问数量小
3. 渠道号01,用户管理的用户量达到某个级别时能否再扩展?
>> 可以再扩展,按照HiPi号自动生成的区段来分
4. Consistent Hashing算法的优缺点?
>> 环状结构。虚拟节点来替换实体节点被分配到环状某一位置上(根据处理能力不同可以将一个实体节点映射到多个虚拟节点上)。主键为key的节点position = hash(key),在环上按照顺时针查找value大于position的第一个虚拟节点,由它对应的实体节点处理
5. 余数计算分散的优缺点
>> 余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。那就是当添加或移除服务器时,
>> 缓存重组的代价相当巨大。添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,
>> 从而影响缓存的命中率。
6. 动态添加机器时是否可以重启服务?
>> 不可以
7. 节点离开系统的时候
>> 比如宕机,这个节点上存储的信息需要继续备份到其它节点上,虽然节点离开了系统,但是因为备份的存在,我们通过其他节点可以恢复出本节点的所有信息,备份节点上的信息(离开的节点的信息)也要备份
8. 节点加入系统
>> 从其他节点恢复数据后,其他节点也需要相应减少备份数而一个节点如果只是暂时性的不可达,也就是一个很短的时间内失效(这种情况是最常发生的),那么需要其他节点暂时接管这个节点的工作,在其可用的时候,把数据增量传送回该节点
问题 | 技术 | 优点 |
---|---|---|
分布 | Consistent Hashing | 节点可扩展 |
高可写性 | 版本锁 | 与更新率解耦 |
临时错误处理 | 延迟处理和hinted handoff | 提供了高可用和某些负载节点不可用时可持续性提高服务 |
永久性数据错误的恢复 | Merkle tree(Hash tree) | 后台同步不同的备份,比rsync高效 |
节点和故障检测 | Gossip-based协议(p2p) | 避免了由中心节点提供服务 |
垂直划分
应用名 | 渠道号 | 数据库id |
---|---|---|
用户管理 | 01 | DB1(3),DB4(2) |
权限管理 | 01 | DB2 |
支付管理 | 01 | DB3 |
DB1(3):DB1 - 数据库1 , (3)- 权重
DB1和DB4要做同步操作 - rsync
放弃rsync,使用开源解决方案:
1. Mysql-Proxy - 稳定
2. Amoeba - 中文文档丰富
Amoeba是一个类似MySQL Proxy 的分布式数据库中间代理层软件,是由陈思儒开发的一个开源的java项目。其主要功能包括读写分离,垂直分库,水平分库等.
两者同样都有Master的单点问题
能否修改Amoeba代码,实现Master宕机后,随机选出一个Slave当作Master,或所有的Slave选举出一个Master。
另外,Mysql 5.1以上支持分区功能,可以解决水平分库问题。
水平划分
第一种按渠道号划分
应用名 | 渠道号 | 数据库id |
---|---|---|
用户管理 | 01 | DB1 |
用户管理 | 02 | DB2 |
用户管理 | 03 | DB3 |
第二种按Hash值来划分(Hash的第一个字母)
数据库id | 范围 |
---|---|
DB1 | 0-9 |
DB2 | a-j |
DB3 | k-t |
DB4 | n-z |
资源名 | URL | Hash值 | 数据库id |
---|---|---|---|
城市风云儿1 _09 | ebook.hipidata.cn/story/csfy/1_09.jpg | edsfdflaodfdldfdsf | DB2 |
城市风云儿1 _07 | ebook.hipidata.cn/story/csfy/1_07.jpg | odsfdflaodfdlskfds | DB3 |
城市风云儿1 _08 | ebook.hipidata.cn/story/csfy/1_08.jpg | ytrodrlaodfdlsdfsf | DB4 |
垂直,水平混合划分
应用名 | 渠道号 | 数据库id |
---|---|---|
用户管理 | 01 | DB1(3),DB6(4) |
权限管理 | 01 | DB2 |
用户管理 | 02 | DB3 |
权限管理 | 02 | DB4 |
支付管理 | 01,02 | DB5 |
DB1和DB6要做同步操作
分布式缓存
缓存策略
渠道号 | 缓存id |
---|---|
01 | M1(3),M2(2) |
02 | M4(4),M3(1) |
M1(3):M1 - 缓存机器1 (3)- 权重
Xmemcached client可以设置权重
但是 M1,M2之间的数据同步还不知道怎么处理的?
>> M1 down -> M2 up(M2为热备)
这种双写方案,会有成本问题?需要2陪的内存,更多的CPU
方案有:
重新计算Key的分布->节点故障问题会引起部分用户数据丢失(有的数据可能没有关系,但是像用户登陆的session)
建议方案:
登陆的session及重要数据采用:一致性哈希+双写方案 -> 内存是不安全的,如果两台机器都挂了(以google的1000台每天有一台挂的概率算)那么每天同时挂的概率是10万分之一,但是如果发生将是严重事件所有用户都不能使用服务。
>>两台机器都写成功算成功
其他非影响用户使用的数据采用:一致性哈希(consistent hashing)
用户登陆的session值如果大小为1k,那么1g的内存大概可以放10万用户的数据,一台普通的台式机4g的内存大概可以放30万用户左右,如果我们采用一致性哈希+双写方案,只要有四台机器就可以在Consistent hashing上产生两个节点,故障率可以降低到100万分之一,用户数可以容60万到70万的人数同时在线。
4台普通台式机的总价也就在1w-1.5w之间(以每台2k-3k算)
操作流程
动作 | 步骤 |
---|---|
取数据 | 先取缓存,再取数据库,最后存缓存 |
更新数据 | a.缓存有数据 - 更新缓存,返回,更新数据库(异步) b. 缓存没数据 - 从数据库取数据,更新数据并放入缓存,更新数据库(异步) |
插入数据 | 插入缓存,返回,插入数据库(异步) |
删除数据 | a.缓存有数据 - 删除缓存数据,返回,删除数据库(异步) |
内存不足时,脏数据问题
异步更新数据库引擎(第二阶段实现)
序号 | case | 操作 |
---|---|---|
1 | 同一条数据,有两次或多次update | 合并所有更新操作为一条再更新数据库 |
2 | 同一条数据,一次update一次delete | 数据库操作为delete操作 |
3 | 同一条数据,一次create一次delete | 不操作数据库 |
4 | 同一条数据,一次create一次update | 合并执行create操作 |
5 | 同一条数据,一次create一次delete一次create | 执行后一次create操作 |
6 | 同一条数据,一次delete一次create | 不操作数据库 |
7 | 同一条数据,一次delete一次create一次delete | 执行delete |