分布式数据库查询算法
‘壹’ 关于软考中数据库系统工程师
数据库系统工程师级考试大纲
一、考试说明
1.考试要求
(1)掌握计算机体系结构以及各主要部件的性能和基本工作原理;
(2)掌握操作系统、程序设计语言的基础知识,了解编译程序的基本知识;
(3)熟练掌握常用数据结构和常用算法;
(4)熟悉软件工程和软件开发项目管理的基础知识;
(5)熟悉计算机网络的原理和技术;
(6)掌握数据库原理及基本理论;
(7)掌握常用的大型数据库管理系统的应用技术;
(8)掌握数据库应用系统的设计方法和开发过程;
(9)熟悉数据库系统的管理和维护方法,了解相关的安全技术;
(10)了解数据库发展趋势与新技术;
(11)掌握常用信息技术标准、安全性,以及有关法律、法规的基本知识;
(12)了解信息化、计算机应用的基础知识;
(13)正确阅读和理解计算机领域的英文资料。
2. 通过本考试的合格人员能参与应用信息系统的规划、设计、构建、运行和管理,能按照用户需求,设计、建立、运行、维护高质量的数据库和数据仓库;作为数据管理员管理信息系统中的数据资源,作为数据库管理员建立和维护核心数据库;担任数据库系统有关的技术支持,同时具备一定的网络结构设计及组网能力;具有工程师的实际工作能力和业务水平,能指导计算机技术与软件专业助理工程师(或技术员)工作。
3. 本考试设置的科目包括
(1)信息系统知识,考试时间为150分钟,笔试;
(2)数据库系统设计与管理,考试时间为150分钟,笔试。
二、考试范围
考试科目1:信息系统知识
1. 计算机系统知识
1.1 硬件知识
1.1.1 计算机体系结构和主要部件的基本工作原理
•CPU和存储器的组成、性能、基本工作原理
•常用I/O设备、通信设备的性能,以及基本工作原理
•I/O接口的功能、类型和特点
•CISC/RISC,流水线操作,多处理机,并行处理
1.1.2 存储系统
•虚拟存储器基本工作原理,多级存储体系
•RAID类型和特性
1.1.3 安全性、可靠性与系统性能评测基础知识
•诊断与容错
•系统可靠性分析评价
• 计算机系统性能评测方法
1.2 数据结构与算法
1.2.1 常用数据结构
•数组(静态数组、动态数组)
•线性表、链表(单向链表、双向链表、循环链表)
•栈和队列
•树(二叉树、查找树、平衡树、遍历树、堆)、图、集合的定义、存储和操作
•Hash(存储位置计算、碰撞处理)
1.2.2 常用算法
•排序算法、查找算法、数值计算、字符串处理、数据压缩算法、递归算法、图的相关算法
•算法与数据结构的关系,算法效率,算法设计,算法描述(流程图、伪代码、决策表),算法的复杂性
1.3 软件知识
1.3.1 操作系统知识
•操作系统的类型、特征、地位、内核(中断控制)、进程、线程概念
•处理机管理(状态转换、同步与互斥、信号灯、分时轮转、抢占、死锁)
•存储管理(主存保护、动态连接分配、分段、分页、虚存)
•设备管理(I/O控制、假脱机、磁盘调度)
•文件管理(文件目录、文件的结构和组织、存取方法、存取控制、恢复处理、共享和安全)
•作业管理(作业调度、作业控制语言(JCL)、多道程序设计)
•汉字处理,多媒体处理,人机界面
•网络操作系统和嵌入式操作系统基础知识
•操作系统的配置
1.3.2 程序设计语言和语言处理程序的知识
• 汇编、编译、解释系统的基础知识和基本工作原理
• 程序设计语言的基本成分:数据、运算、控制和传输,程序调用的实现机制
• 各类程序设计语言的主要特点和适用情况
1.4 计算机网络知识
•网络体系结构(网络拓扑、OSI/RM、基本的网络协议)
•传输介质,传输技术,传输方法,传输控制
•常用网络设备和各类通信设备
•Client/Server结构、Browser/Server结构、Browser/Web/Datebase结构
•LAN拓扑,存取控制,LAN的组网,LAN间连接,LAN-WAN连接
•因特网基础知识及应用
•网络软件
•网络管理
•网络性能分析
•网络有关的法律、法规
2. 数据库技术
2.1 数据库技术基础
2.1.1 数据库模型
•数据库系统的三级模式(概念模式、外模式、内模式),两级映像(概念模式/外模式、外模式/内模式)
•数据库模型:数据模型的组成要素,概念数据模型ER图(实体、属性、关系),逻辑数据模型(关系模型、层次模型、网络模型)
2.1.2 数据库管理系统的功能和特征
•主要功能(数据库定义、数据库操作、数据库控制、事务管理、用户视图)
•特征(确保数据独立性、数据库存取、同时执行过程、排它控制、故障恢复、安全性、完整性)
•RDB(关系数据库),OODB(面向对象数据库),ORDB(对象关系数据库),NDB(网状数据库)
•几种常用Web数据库的特点
2.1.3 数据库系统体系结构
• 集中式数据库系统
• Client/Server数据库系统
• 并行数据库系统
• 分布式数据库系统
• 对象关系数据库系统
2.2 数据操作
2.2.1 关系运算
•关系代数运算(并、交、差、笛卡儿积、选择、投影、连接、除)
•元组演算
•完整性约束
2.2.2 关系数据库标准语言(sql)
•SQL的功能与特点
•用SQL进行数据定义(表、视图、索引、约束)
•用SQL进行数据操作(数据检索、数据插入/删除/更新、触发控制)
•安全性和授权
•程序中的API,嵌入SQL
2.3 数据库的控制功能
•数据库事务管理(ACID属性)
•数据库备份与恢复技术(UNDO、REDO)
•并发控制
2.4 数据库设计基础理论
2.4.1 关系数据库设计
•函数依赖
•规范化(第一范式、第二范式、第三范式、BC范式、第四范式、第五范式)
•模式分解及分解应遵循的原则
2.4.2 对象关系数据库设计
•嵌套关系、 复杂类型,继承与引用类型
•与复杂类型有关的查询
•SQL中的函数与过程
•对象关系
2.5 数据挖掘和数据仓库基础知识
•数据挖掘应用和分类
•关联规则、聚类
•数据仓库的成分
•数据仓库的模式
2.6 多媒体基本知识
2.6.1 多媒体技术基本概念
•多媒体系统基础知识
•常用多媒体文件格式
2.6.2 多媒体压缩编码技术
•多媒体压缩编码技术
•统计编码
•预测编码
•编码的国际标准
2.6.3多媒体技术应用
•简单图形的绘制,图像文件的处理方法
•音频和视频信息的应用
•多媒体应用开发过程
2.7 系统性能知识
•性能计算(响应时间、吞吐量、周转时间)
•性能指标和性能设计
•性能测试和性能评估
2.8 计算机应用基础知识
•信息管理、数据处理、辅助设计、科学计算,人工智能等基础知识
•远程通信服务及相关通信协议基础知识
3. 系统开发和运行维护知识
3.1 软件工程、软件过程改进和软件开发项目管理知识
•软件工程知识
•软件开发生命周期阶段目标和任务
•软件开发项目基础知识(时间管理、成本管理、质量管理、人力资源管理、风险管理等)及其常用管理工具
•主要的软件开发方法(生命周期法、原型法、面向对象法、CASE)
•软件开发工具与环境知识
•软件质量管理基础知识
•软件过程改进基础知识
•软件开发过程评估、软件能力成熟度评估的基础知识
3.2 系统分析基础知识
•系统分析的目的和任务
•结构化分析方法(数据流图(DFD)和数据字典(DD),实体关系图(ERD),描述加工处理的结构化语言)
•统一建模语言(UML)
•系统规格说明书
3.3 系统设计知识
•系统设计的目的和任务
•结构化设计方法和工具(系统流程图、HIPO图、控制流程图)
•系统总体结构设计(总体布局,设计原则,模块结构设计,数据存取设计,系统配置方案)
•系统详细设计(代码设计、数据库设计、用户界面设计、处理过程设计)
•系统设计说明书
3.4 系统实施知识
•系统实施的主要任务
•结构化程序设计、面向对象程序设计、可视化程序设计
•程序设计语言的选择、程序设计风格
•系统测试的目的、类型,系统测试方法(黑盒测试、白盒测试、灰盒测试)
•测试设计和管理(错误曲线、错误排除、收敛、注入故障、测试试用例设计、系统测试报告)
•系统转换基础知识
3.5 系统运行和维护知识
•系统运行管理知识
•系统维护知识
•系统评价知识
4. 安全性知识
•安全性基本概念(网络安全、操作系统安全、数据库安全)
•计算机病毒的防治,计算机犯罪的防范,容灾
•访问控制、防闯入、安全管理措施
•加密与解密机制
•风险分析、风险类型、抗风险措施和内部控制
5.标准化知识
•标准化意识,标准化的发展,标准出台过程
•国际标准、国家标准、行业标准、企业标准基本知识
•代码标准、文件格式标准、安全标准软件开发规范和文档标准
•标准化机构
6.信息化基础知识
•信息化意识
•全球信息化趋势、国家信息化战略、企业信息化战略和策略
•有关的法律、法规
•远程教育、电子商务、电子政务等基础知识
•企业信息资源管理基础知识
7.计算机专业英语
•掌握计算机技术的基本词汇
•能正确阅读和理解计算机领域的英文资料
考试科目2:数据库系统设计与管理
1.数据库设计
1.1理解系统需求说明
•了解用户需求、确定系统范围
•确定应用系统数据库的各种关系
•现有环境与新系统环境的关系
•新系统中的数据项、数据字典、数据流
1.2 系统开发的准备
•选择开发方法,准备开发环境,制订开发计划
1.3 设计系统功能
•选择系统机构,设计各子系统的功能和接口,设计安全性策略、需求和实现方法,制定详细的工作流和数据流
1.4 数据库设计
1.4.1 设计数据模型
•概念结构设计(设计ER模型)
•逻辑结构设计(转换成DBMS所能接收的数据模型)
•评审设计
1.4.2 物理结构设计
•设计方法与内容
•存取方法的选择
•评审设计与性能预测
1.4.3 数据库实施与维护
•数据加载与应用程序调试
•数据库试运行
•数据库运行与维护
1.4.4 数据库的保护
•数据库的备份与恢复
•数据库的安全性
•数据库的完整性
•数据库的并发控制
1.5 编写外部设计文档
•编写系统说明书(系统配置图、各子系统关系图、系统流程图,系统功能说明、输入输出规格说明、数据规格说明、用户手册框架)
•设计系统测试要求
1.6 设计评审
2. 数据库应用系统设计
2.1 设计数据库应用系统结构
•信息系统的架构(如Client/Server)与DBMS
•多用户数据库环境(文件服务器体系结构、Client/Server体系结构)
•大规模数据库和并行计算机体系结构(SMP、MPP)
•中间件角色和相关工具
•按构件分解,确定构件功能规格以及构件之间的接口
2.2 设计输入输出
•屏幕界面设计,设计输入输出检查方法和检查信息
•数据库交互与连接(掌握C程序设计语言,以及java、Visual Basic、Visual C++、PowerBuilder、Delphi中任一种开发工具与数据库互连的方法(如何与数据库服务器沟通))
2.3 设计物理数据
•分析事务在数据库上运行的频率和性能要求,确定逻辑数据组织方式、存储介质,设计索引结构和处理方式
•将逻辑数据结构变换成物理数据结构,计算容量(空间代价),确定存取方法(时间效率)、系统配置(维护代价)并进行优化
2.4 设计安全体系
•明确安全等级
•数据库的登录方式
•数据库访问
•许可(对象许可、命令许可、授权许可的方法)
2.5 应用程序开发
2.5.1 应用程序开发
•选择应用程序开发平台
•系统实施顺序
•框架开发
•基础小组的程序开发
•源代码控制
•版本控制
2.5.2 模块划分(原则、方法、标准)
2.5.3 编写程序设计文档
•模块规格说明书(功能和接口说明、程序处理逻辑的描述、输入输出数据格式的描述)
•测试要求说明书(测试类型和目标,测试用例,测试方法)
2.5.4 程序设计评审
2.6 编写应用系统设计文档
•系统配置说明、构件划分图、构件间的接口、构件处理说明、屏幕设计文档、报表设计文档、程序设计文档、文件设计文档、数据库设计文档
2.7 设计评审
3. 数据库应用系统实施
3.1 整个系统的配置与管理
3.2 常用数据库管理系统的应用(SQL Server、Oracle、Sybase、DB2、Access或Visual Foxpro)
•创建数据库
•创建表、创建索引、创建视图、创建约束、创建UDDT(用户自定义类型)
•创建和管理触发器
•建立安全体系
3.3 数据库应用系统安装
•拟定系统安装计划(考虑费用、客户关系、雇员关系、后勤关系和风险等因素)
•拟定人力资源使用计划(组织机构安排的合理性)
•直接安装(安装新系统并使系统快速进入运行状态)
•并行安装(新旧系统并行运行一段时间)
•阶段安装(经过一系列的步骤和阶段使新系统各部分逐步投入运行)
3.4 数据库应用系统测试
•拟定测试目标、计划、方法与步骤
•数据加载,准备测试数据
•指导应用程序员进行模块测试进行验收
•准备系统集成测试环境测试工具
•写出数据库运行测试报告
3.5 培训与用户支持
4.数据库系统的运行和管理
4.1 数据库系统的运行计划
•运行策略的确定
•确定数据库系统报警对象和报警方式
•数据库系统的管理计划(执行,故障/恢复,安全性,完整性,用户培训和维护)
4.2 数据库系统的运行和维护
•新旧系统的转换
•收集和分析报警数据(执行报警、故障报警、安全报警)
•连续稳定的运行
•数据库维护(数据库重构、安全视图的评价和验证、文档维护)
•数据库系统的运行统计(收集、分析、提出改进措施)
•关于运行标准和标准改进一致性的建议
•数据库系统的审计
4.3 数据库管理
•数据字典和数据仓库的管理
•数据完整性维护和管理(实体完整性、参照完整性)
•数据库物理结构的管理(保证数据不推迟访问)
•数据库空间及碎片管理
•备份和恢复(顺序、日志(审计痕迹)、检查点)
•死锁管理(集中式、分布式)
•并发控制(可串行性、锁机制、时间戳、优化)
•数据安全性管理(加密、安全、访问控制、视图、有效性确认规则)
•数据库管理员(DBA)职责
4.4 性能调整
•SQL语句的编码检验
•表设计的评价
•索引的改进
•物理分配的改进
•设备增强
•数据库性能优化
4.5 用户支持
•用户培训
•售后服务
5. SQL
5.1 数据库语言
•数据库语言的要素
•数据库语言的使用方式(交互式和嵌入式)
5.2 SQL概述
•SQL语句的特征
•SQL语句的基本成分
5.3 数据库定义
•创建数据库(Create Datebase)、创建表(Create Table)
•定义数据完整性
•修改表(Alter Table)、删除表(Drop Table)
•定义索引(Create Index)、删除索引(Drop Index)
•定义视图(Create View)、删除视图(Drop View)、更新视图
5.4 数据操作
•Select语句的基本机构
•简单查询
•SQL中的选择、投影
•字符串比较,涉及空值的比较
•日期时间,布尔值,输出排序
•多表查询
•避免属性歧义
•SQL中的连接、并、交、差
•SQL中的元组变量
•子查询
5.5 完整性控制与安全机制
•主键(Primary Key)约束
•外键(Foreign Key)约束
•属性值上的约束(Null、Check、Create Domain)
•全局约束(Create Assertions)
•权限、授权(Grant)、销权(Revoke)
5.6 创建触发器(Create Trigger)
5.7 SQL使用方式
•交互式SQL
•嵌入式SQL
•SQL与宿主语言接口(Declare、共享变量、游标、卷游标)
•动态SQL
•API
5.8 SQL 标准化
6. 网络环境下的数据库
6.1 分布式数据库
6.1.1 分布式数据库的概念
•分布式数据库的特点与目标
6.1.2 分布式数据库的体系结构
•分布式数据库的模式结构
•数据分布的策略(数据分片、分布透明性)
•分布式数据库管理系统
6.1.3 分布式查询处理和优化
6.1.4 分布式事务管理
•分布式数据库的恢复(故障、恢复、2段提交、3段提交)
•分布式数据库的透明性(局部、分裂、复制、处理、并发、执行)
6.1.5 分布式数据库系统的应用
6.2 网络环境下数据库系统的设计与实施
•数据的分布设计
•负载均衡设计
•数据库互连技术
6.3 面向Web的DBMS技术
•三层体系结构
•动态Web网页
•ASP、JSP、XML的应用
7.数据库的安全性
7.1 安全性策略的理解
•数据库视图的安全性策略
•数据的安全级别(最重要的、重要的、注意、选择)
7.2 数据库安全测量
•用户访问控制(采用口令等)
•程序访问控制(包含在程序中的SQL命令限制)
•表的访问控制(视图机制)
•控制访问的函数和操作
•外部存储数据的加密与解密
8. 数据库发展趋势与新技术
8.1 面向对象数据库(OODBMS)
8.1.1 OODBMS的特征
8.1.2 面向对象数据模型
•对象结构、对象类、继承与多重继承、对象标识、对象包含、对象嵌套
8.1.3 面向对象数据库语言
8.1.4 对象关系数据库系统(ORDBMS)
•嵌套关系
•复杂类型
•继承、引用类型
•与复杂类型有关的查询
•函数与过程
•面向对象与对象关系
•ORDBMS应用领域
8.2 企业资源计划(ERP)和数据库
8.2.1 ERP概述
•基本MRP(制造资源计划)、闭环MRP、ERP
•基本原理、发展趋势
•ERP设计的总体思路(一个中心、两类业务、三条干线)
8.2.2 ERP与数据库
•运行数据库与ERP数据模型之间的关系
•运行数据库与ERP数据库之间的关系
8.2.3 案例分析
8.3 决策支持系统的建立
•决策支持系统的概念
•数据仓库设计
•数据转移技术
•联机分析处理(OLAP)技术
•企业决策支持解决方案
•联机事务处理(OLTP)
‘贰’ php的memcached分布式hash算法,如何解决分布不均crc32这个算法没办法把key值均匀的分布出去
memcached的总结和分布式一致性hash
当前很多大型的web系统为了减轻数据库服务器负载,会采用memchached作为缓存系统以提高响应速度。
目录: (http://hounwang.com/lesson.html)
memchached简介
hash
取模
一致性hash
虚拟节点
源码解析
参考资料
1. memchached简介
memcached是一个开源的高性能分布式内存对象缓存系统。
其实思想还是比较简单的,实现包括server端(memcached开源项目一般只单指server端)和client端两部分:
server端本质是一个in-memory key-value store,通过在内存中维护一个大的hashmap用来存储小块的任意数据,对外通过统一的简单接口(memcached protocol)来提供操作。
client端是一个library,负责处理memcached protocol的网络通信细节,与memcached server通信,针对各种语言的不同实现分装了易用的API实现了与不同语言平台的集成。
web系统则通过client库来使用memcached进行对象缓存。
2. hash
memcached的分布式主要体现在client端,对于server端,仅仅是部署多个memcached server组成集群,每个server独自维护自己的数据(互相之间没有任何通信),通过daemon监听端口等待client端的请求。
而在client端,通过一致的hash算法,将要存储的数据分布到某个特定的server上进行存储,后续读取查询使用同样的hash算法即可定位。
client端可以采用各种hash算法来定位server:
取模
最简单的hash算法
targetServer = serverList[hash(key) % serverList.size]
直接用key的hash值(计算key的hash值的方法可以自由选择,比如算法CRC32、MD5,甚至本地hash系统,如java的hashcode)模上server总数来定位目标server。这种算法不仅简单,而且具有不错的随机分布特性。
但是问题也很明显,server总数不能轻易变化。因为如果增加/减少memcached server的数量,对原先存储的所有key的后续查询都将定位到别的server上,导致所有的cache都不能被命中而失效。
一致性hash
为了解决这个问题,需要采用一致性hash算法(consistent hash)
相对于取模的算法,一致性hash算法除了计算key的hash值外,还会计算每个server对应的hash值,然后将这些hash值映射到一个有限的值域上(比如0~2^32)。通过寻找hash值大于hash(key)的最小server作为存储该key数据的目标server。如果找不到,则直接把具有最小hash值的server作为目标server。
为了方便理解,可以把这个有限值域理解成一个环,值顺时针递增。
如上图所示,集群中一共有5个memcached server,已通过server的hash值分布到环中。
如果现在有一个写入cache的请求,首先计算x=hash(key),映射到环中,然后从x顺时针查找,把找到的第一个server作为目标server来存储cache,如果超过了2^32仍然找不到,则命中第一个server。比如x的值介于A~B之间,那么命中的server节点应该是B节点
可以看到,通过这种算法,对于同一个key,存储和后续的查询都会定位到同一个memcached server上。
那么它是怎么解决增/删server导致的cache不能命中的问题呢?
假设,现在增加一个server F,如下图
此时,cache不能命中的问题仍然存在,但是只存在于B~F之间的位置(由C变成了F),其他位置(包括F~C)的cache的命中不受影响(删除server的情况类似)。尽管仍然有cache不能命中的存在,但是相对于取模的方式已经大幅减少了不能命中的cache数量。
虚拟节点
但是,这种算法相对于取模方式也有一个缺陷:当server数量很少时,很可能他们在环中的分布不是特别均匀,进而导致cache不能均匀分布到所有的server上。
如图,一共有3台server – 1,2,4。命中4的几率远远高于1和2。
为解决这个问题,需要使用虚拟节点的思想:为每个物理节点(server)在环上分配100~200个点,这样环上的节点较多,就能抑制分布不均匀。
当为cache定位目标server时,如果定位到虚拟节点上,就表示cache真正的存储位置是在该虚拟节点代表的实际物理server上。
另外,如果每个实际server的负载能力不同,可以赋予不同的权重,根据权重分配不同数量的虚拟节点。
// 采用有序map来模拟环
this.consistentBuckets = new TreeMap();
MessageDigest md5 = MD5.get();//用MD5来计算key和server的hash值
// 计算总权重
if ( this.totalWeight for ( int i = 0; i < this.weights.length; i++ )
this.totalWeight += ( this.weights[i] == null ) ? 1 : this.weights[i];
} else if ( this.weights == null ) {
this.totalWeight = this.servers.length;
}
// 为每个server分配虚拟节点
for ( int i = 0; i < servers.length; i++ ) {
// 计算当前server的权重
int thisWeight = 1;
if ( this.weights != null && this.weights[i] != null )
thisWeight = this.weights[i];
// factor用来控制每个server分配的虚拟节点数量
// 权重都相同时,factor=40
// 权重不同时,factor=40*server总数*该server权重所占的百分比
// 总的来说,权重越大,factor越大,可以分配越多的虚拟节点
double factor = Math.floor( ((double)(40 * this.servers.length * thisWeight)) / (double)this.totalWeight );
for ( long j = 0; j < factor; j++ ) {
// 每个server有factor个hash值
// 使用server的域名或IP加上编号来计算hash值
// 比如server - "172.45.155.25:11111"就有factor个数据用来生成hash值:
// 172.45.155.25:11111-1, 172.45.155.25:11111-2, ..., 172.45.155.25:11111-factor
byte[] d = md5.digest( ( servers[i] + "-" + j ).getBytes() );
// 每个hash值生成4个虚拟节点
for ( int h = 0 ; h < 4; h++ ) {
Long k =
((long)(d[3+h*4]&0xFF) << 24)
| ((long)(d[2+h*4]&0xFF) << 16)
| ((long)(d[1+h*4]&0xFF) << 8 )
| ((long)(d[0+h*4]&0xFF));
// 在环上保存节点
consistentBuckets.put( k, servers[i] );
}
}
// 每个server一共分配4*factor个虚拟节点
}
// 采用有序map来模拟环
this.consistentBuckets = new TreeMap();
MessageDigest md5 = MD5.get();//用MD5来计算key和server的hash值
// 计算总权重
if ( this.totalWeight for ( int i = 0; i < this.weights.length; i++ )
this.totalWeight += ( this.weights[i] == null ) ? 1 : this.weights[i];
} else if ( this.weights == null ) {
this.totalWeight = this.servers.length;
}
// 为每个server分配虚拟节点
for ( int i = 0; i < servers.length; i++ ) {
// 计算当前server的权重
int thisWeight = 1;
if ( this.weights != null && this.weights[i] != null )
thisWeight = this.weights[i];
// factor用来控制每个server分配的虚拟节点数量
// 权重都相同时,factor=40
// 权重不同时,factor=40*server总数*该server权重所占的百分比
// 总的来说,权重越大,factor越大,可以分配越多的虚拟节点
double factor = Math.floor( ((double)(40 * this.servers.length * thisWeight)) / (double)this.totalWeight );
for ( long j = 0; j < factor; j++ ) {
// 每个server有factor个hash值
// 使用server的域名或IP加上编号来计算hash值
// 比如server - "172.45.155.25:11111"就有factor个数据用来生成hash值:
// 172.45.155.25:11111-1, 172.45.155.25:11111-2, ..., 172.45.155.25:11111-factor
byte[] d = md5.digest( ( servers[i] + "-" + j ).getBytes() );
// 每个hash值生成4个虚拟节点
for ( int h = 0 ; h < 4; h++ ) {
Long k =
((long)(d[3+h*4]&0xFF) << 24)
| ((long)(d[2+h*4]&0xFF) << 16)
| ((long)(d[1+h*4]&0xFF) << 8 )
| ((long)(d[0+h*4]&0xFF));
// 在环上保存节点
consistentBuckets.put( k, servers[i] );
}
}
// 每个server一共分配4*factor个虚拟节点
}
// 用MD5来计算key的hash值
MessageDigest md5 = MD5.get();
md5.reset();
md5.update( key.getBytes() );
byte[] bKey = md5.digest();
// 取MD5值的低32位作为key的hash值
long hv = ((long)(bKey[3]&0xFF) << 24) | ((long)(bKey[2]&0xFF) << 16) | ((long)(bKey[1]&0xFF) << 8 ) | (long)(bKey[0]&0xFF);
// hv的tailMap的第一个虚拟节点对应的即是目标server
SortedMap tmap = this.consistentBuckets.tailMap( hv );
return ( tmap.isEmpty() ) ? this.consistentBuckets.firstKey() : tmap.firstKey();
更多问题到问题求助专区(http://bbs.hounwang.com/)
‘叁’ 分布式数据库:2PL满足可串行化吗2PL和乐观算法的根本差别是什么
1 满足,2PL和乐观算法的思想不同,2PL的目的在于在事先预防冲突的发生,而乐观算法是在冲突发生之后再来进行弥补。
R*穷举出所有可能的JN序列和全部可能的JN方法.只传输需要的元组,一次一个元组,每次传输都需要交换信息,无需临时存储器,适合高速网络
‘肆’ 它用分布式数据库替代Oracle、SAS,让银行告别西方软件“霸凌”
WPS成功上市代表了信息化企业软件国产化的趋势。在雷涛看来,WPS不是简单复制后替代Windows office,而是找到了下一代产品需求。
以往无论是运营商还是银行核心系统,大架构都垄断在西方的 IOE(IBM、Oracle、EMC)这三座大山里。直到2008年阿里提出去“IOE”运动,开始助推信息化软件国产化浪潮。
天云数据就是其中最早一批入场者。2010年为了建立中国完整的云计算产业链,中国宽带之父田溯宁投资建设云基地昌燃,天云数据便由此孵化,初备雏形。
2015年,雷涛带领创始团队们正式成立天云数据,率先切入金融领域。天云提供了国内领先的国产HTAP数据库Hubble,完成了“去IOE”中最困难的部分,替代金融A类核心系统惯用的西方IOE架构,在银行的联机事务中解决A类核心系统减负问题。此外,为了降低AI使用门槛,天云数据还推出AI PaaS平台MaximAI,逐步将数据价值逐渐扩展到能源、医药、军事等其它行业。
目前天云数据有70多家行业内大企业客户,单笔合同200-500万,纯软件年营收过亿。
融资方面,天云数据2018年曾获得曦域资本、华映资本B轮1亿人民币投资。
作为行业老兵,雷涛在北美跨国公司有20多年的技术管理经验, 2005年便入席SNIA存储游槐工业协会中国区技术委员会联合主席,CCF中国计算机学会大数据专委会委员。
2011年在云基地时期,雷涛和创始团队通过BDP大数据平台负责了众多运营商业务,如联通的数据魔方、移动总部、南方基地等,2015年天云数据正式独立后,雷涛为了避免同业竞争,选择先聚焦在金融领域。
“天云数据的目标是替代 Oracle 和 SAS ”。云基地时期的积累让天云数据一开始就有高起点,首单就接下了光大银行的核心系统——OLTP线交易系统。比如银行能在全国所有营业厅实时实现OOTD交易,实时查询存钱取钱数额,整个环节涉及的技术都是天云数据早期对Oracle的一些替代。
但之后在多次的项目操作过程中雷涛发现,在几百万条交易规格的强一致性下,数据的移动性、计算框架的变化、联机事务同时要做大规模并行计算,这对计算场景的神迅友通用性、即时性和全量数据要求极高,传统 Oracle架构根本无法适应。
“在Oracle架构之上,还需要升级满足新需求”。
于是天云数据自主研发HTAP国产分布式数据库Hubble。与传统 IT 架构处理失误需要联机分析和分开处理不同,HTAP 数据库能够在一份数据上同时支撑业务系统运行并做 OLAP 场景,避免在线与离线数据库之间大量的数据交互,为系统减负。
HTAP国产分布式数据库Hubble替代了Oracle一体机,核心表2000余张80T左右、400亿条交易数据、提供56只服务应用交易、满足500个用户并发、500ms交易服务响应、每天在线交易量超200万、占整个银行核心交易量的10%,让银行面向柜面系统可提供7*8小时A类实时核心交易,面向手机网银系统可提供7*24小时A类实时核心交易。
从集中式Oracle切换到分布式HTAP,也解决了数据库扩展性的问题。比如天云数据让光大银行解决了 历史 数据查询问题,以往 历史 查询只能查到2年前,但在分布式技术上线后,可以查询15年前所有交易数据,同时让银行柜面系统以及手机APP可以无数人同时查询。
而在BI逐步转向AI的过程中,复杂的商业流程经算法重构。过去要把数据拿到SAS平台先分析,一层一层地把数据提出来搭建。但现在通过分布式技术,流程趋于扁平化,可以实现毫秒级的服务响应。
天云数据一开始就撬动的是行业头部资源。目前天云数据有光大银行、兴业银行、中信银行、中泰证券、中国石油、国家统计局等70余家行业内大企业客户,分布在金融、能源、医药、政府军事等领域,单笔合同级别超百万
针对每个垂直行业,天云数据都会成立一个子公司来专注赛道。目前天云数据有160人,技术人员超六成。
在雷涛看来,如果一年600个项目,全是5万、15万等碎片化的订单,公司总是重复满足初级客户的简单需求,技术很难沉淀和深入。“在当下成长阶段,打造产品需要在用户想要什么和你想做什么中找到平衡”。
对于雷涛而言,专注头部大B发展有两大发展潜力。一方面,大B拥有机器学习的普遍能力和实验室,更容易接受新产品。另一方面,天云数据交付产品和交付服务的同时也在转移大B客户的数据价值。
“AI本身是一个知识生产过程,它能把大型企业规则、流程的经验价值快速地抽样出来进行复制,赋能行业内其它客户甚至类似的其它行业。”
但在头部客户更定制化、个性化的情况下,天云数据是否失去了很强的复制能力?
雷涛解释到,虽然每个企业要求不尽相同,但都在不大的池子里找数据库。企业从海量数据中对数据进行迁徙、清洗、去重,可以去找合适的AI方法让它产生业务的价值,此过程具有通用性。
谈到核心壁垒,雷涛认为天云数据壁垒就是数据的复制价值。
壁垒的构建可分为两个阶段。第一个阶段是前沿 科技 本身的壁垒,比的是效率和产品核心价值,谁能够扎得深和更好的交付,谁就能拔得头筹。而作为国内最早研发大数据和人工智能的团队,天云数据有一定的技术先发优势。
第二个阶段是推理端的服务。数据资源的价值需要通过机器学习进行提炼,形成知识,进而封装成推理服务服务于行业。比如某保险公司20年长周期发生的重疾赔付定价上学习出来的特征和内容能够快速地移植到保险行业,而头部大企业客户给天云数据带来很优质的训练数据库。
未来AI将引爆万亿级大市场,但目前渗透率不到1%,这给各企业留有众多机会和想象空间。但无论哪种圈地方式,最终比的是速度、服务的稳定性以及产品化的能力。
‘伍’ mysql如何做成分布式
MySQL做分布式需要通过ndb的Cluster来实现。 MySQLCluster是MySQL适合于分布式计算环境的高实用、高冗余版本。 实现的步骤比较复杂,网络云案例:《MySQLCluster(MySQL集群)分布式》 下载地址:
‘陆’ 数据库分库分表(二)Twitter-Snowflake(64位分布式ID算法)分析与JAVA实现
Twitter-Snowflake算法产生的背景相当简单,为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的id,这些id还需要一些大致的顺序(方便客户端排序),并灶核且在掘顷分布式系统中不同机器产生的id必须不同。各种主键ID生成策略对比,见 常见分布式主键ID生成策略
把 41位的时间前缀 , 10位的节点标识 , 12位的sequence 组合在一起。
除了最高位bit标记为不可用以外,其余三组bit占位均可浮动,看具体的业务需求而定。 默认情况下41bit的时间戳,1970年算起可以支持该算法使用到2038年,10bit的工作机器id可以支持1024台机器,序列号支持1毫秒产生4096个自增序列id 。
Snowflake是Twitter在2010年用Scala语言写的一套主键生成策略,用Thrift对外发布主键生成服务,其中依赖了Twitter内部的Infrastructure,后来Twitter用 Twitter-server 代替了Snowflake,自2012年起就未更新。见 Twitter-Snowflake项目地址(Tags:snowflake-2010)
之前写了一个Java的实现,改自网上一个版本: Twitter的分布式自增ID算法Snowflake实现分析及其Java、Php和Python版 。后来看到当当网的 Sharding-JDBC 分库分表中间件已实现了此算法。就直接在其中添隐散掘加了一些新特性,已merge。( 具体实现 , 说明文档 )
添加3种IdGenerator实现。
用笔记本(i7-3632QM 2.2GHz 四核八线程)测试了下,每秒生成409万(理论上的峰值),CPU占用率18.5%。
‘柒’ 分布式存储中,怎样使用paxos算法保证数据的一致性
在分布式系统中,我们经常遇到多数据副本保持一致的问题,在我们所能找到的资料中该问题讲的很笼统,模模糊糊的,把多个问题或分类糅合在一起,难以理解。在思考和翻阅资料后,通俗地把一致性的问题可分解为2个问题:
1、任何一次修改保证数据一致性。
2、多次数据修改的一致性。
在弱一致性的算法,不要求每次修改的内容在修改后多副本的内容是一致的,对问题1的解决比较宽松,更多解决问题2,该类算法追求每次修改的高度并发性,减少多副本之间修改的关联性,以获得更好的并发性能。例如最终一致性,无所谓每次用户修改后的多副本的一致性及格过,只要求在单调的时间方向上,数据最终保持一致,如此获得了修改极大的并发性能。
在强一致性的算法中,强调单次修改后结果的一致,需要保证了对问题1和问题2要求的实现,牺牲了并发性能。本文是讨论对解决问题1实现算法,这些算法往往在强一致性要求的应用中使用。
解决问题1的方法,通常有两阶段提交算法、采用分布式锁服务和采用乐观锁原理实现的同步方式,下面分别介绍这几种算法的实现原理。
两阶段提交算法
在两阶段提交协议中,系统一般包含两类机器(或节点):一类为协调者(coordinator),通常一个系统中只有一个;另一类为事务参与者(participants,cohorts或workers),一般包含多个,在数据存储系统中可以理解为数据副本的个数。两阶段提交协议由两个阶段组成,在正常的执行下,这两个阶段的执行过程如下所述:
阶段1:请求阶段(commit-request phase,或称表决阶段,voting phase)。
在请求阶段,协调者将通知事务参与者准备提交或取消事务,然后进入表决过程。在表决过程中,参与者将告知协调者自己的决策:同意(事务参与者本地作业执行成功)或取消(本地作业执行故障)。
阶段2:提交阶段(commit phase)。
在该阶段,协调者将基于第一个阶段的投票结果进行决策:提交或取消。当且仅当所有的参与者同意提交事务协调者才通知所有的参与者提交事务,否则协调者将通知所有的参与者取消事务。参与者在接收到协调者发来的消息后将执行响应的操作。
举个例子:A组织B、C和D三个人去爬长城:如果所有人都同意去爬长城,那么活动将举行;如果有一人不同意去爬长城,那么活动将取消。用2PC算法解决该问题的过程如下:
首先A将成为该活动的协调者,B、C和D将成为该活动的参与者。
阶段1:A发邮件给B、C和D,提出下周三去爬山,问是否同意。那么此时A需要等待B、C和D的邮件。B、C和D分别查看自己的日程安排表。B、C发现自己在当日没有活动安排,则发邮件告诉A它们同意下周三去爬长城。由于某种原因,D白天没有查看邮件。那么此时A、B和C均需要等待。到晚上的时候,D发现了A的邮件,然后查看日程安排,发现周三当天已经有别的安排,那么D回复A说活动取消吧。
阶段2:此时A收到了所有活动参与者的邮件,并且A发现D下周三不能去爬山。那么A将发邮件通知B、C和D,下周三爬长城活动取消。此时B、C回复A“太可惜了”,D回复A“不好意思”。至此该事务终止。
两阶段提交算法在分布式系统结合,可实现单用户对文件(对象)多个副本的修改,多副本数据的同步。其结合的原理如下:
1、客户端(协调者)向所有的数据副本的存储主机(参与者)发送:修改具体的文件名、偏移量、数据和长度信息,请求修改数据,该消息是1阶段的请求消息。
2、存储主机接收到请求后,备份修改前的数据以备回滚,修改文件数据后,向客户端回应修改成功的消息。 如果存储主机由于某些原因(磁盘损坏、空间不足等)不能修改数据,回应修改失败的消息。
3、客户端接收发送出去的每一个消息回应,如果存储主机全部回应都修改成功,向每存储主机发送确认修改的提交消息;如果存在存储主机回应修改失败,或者超时未回应,客户端向所有存储主机发送取消修改的提交消息。该消息是2阶段的提交消息。
4、存储主机接收到客户端的提交消息,如果是确认修改,则直接回应该提交OK消息;如果是取消修改,则将修改数据还原为修改前,然后回应取消修改OK的消息。
5、 客户端接收全部存储主机的回应,整个操作成功。
在该过程中可能存在通信失败,例如网络中断、主机宕机等诸多的原因,对于未在算法中定义的其它异常,都认为是提交失败,都需要回滚,这是该算法基于确定的通信回复实现的,在参与者的确定回复(无论是回复失败还是回复成功)之上执行逻辑处理,符合确定性的条件当然能够获得确定性的结果哲学原理。
分布式锁服务
分布式锁是对数据被外界修改持保守态度,在整个数据处理过程中将数据处于锁定状态,在用户修改数据的同时,其它用户不允许修改。
采用分布式锁服务实现数据一致性,是在操作目标之前先获取操作许可,然后再执行操作,如果其他用户同时尝试操作该目标将被阻止,直到前一个用户释放许可后,其他用户才能够操作目标。分析这个过程,如果只有一个用户操作目标,没有多个用户并发冲突,也申请了操作许可,造成了由于申请操作许可所带来的资源使用消耗,浪费网络通信和增加了延时。
采用分布式锁实现多副本内容修改的一致性问题, 选择控制内容颗粒度实现申请锁服务。例如我们要保证一个文件的多个副本修改一致, 可以对整个文件修改设置一把锁,修改时申请锁,修改这个文件的多个副本,确保多个副本修改的一致,修改完成后释放锁;也可以对文件分段,或者是文件中的单个字节设置锁, 实现更细颗粒度的锁操作,减少冲突。
常用的锁实现算法有Lamport bakery algorithm (俗称面包店算法), 还有Paxos算法。下面对其原理做简单概述。
Lamport面包店算法
是解决多个线程并发访问一个共享的单用户资源的互斥问题的算法。 由Leslie Lamport(英语:Leslie Lamport)发明。
Lamport把这个并发控制算法可以非常直观地类比为顾客去面包店采购。面包店只能接待一位顾客的采购。已知有n位顾客要进入面包店采购,安排他们按照次序在前台登记一个签到号码。该签到号码逐次加1。根据签到号码的由小到大的顺序依次入店购货。完成购买的顾客在前台把其签到号码归0. 如果完成购买的顾客要再次进店购买,就必须重新排队。
这个类比中的顾客就相当于线程,而入店购货就是进入临界区独占访问该共享资源。由于计算机实现的特点,存在两个线程获得相同的签到号码的情况,这是因为两个线程几乎同时申请排队的签到号码,读取已经发出去的签到号码情况,这两个线程读到的数据是完全一样的,然后各自在读到的数据上找到最大值,再加1作为自己的排队签到号码。为此,该算法规定如果两个线程的排队签到号码相等,则线程id号较小的具有优先权。
把该算法原理与分布式系统相结合,即可实现分步锁。
Paxos算法
该算法比较热门,参见WIKI,http://zh.wikipedia.org/wiki/Paxos%E7%AE%97%E6%B3%95
Paxos算法解决的问题是一个分布式系统如何就某个值(决议)达成一致。一个典型的场景是,在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态。为保证每个节点执行相同的命令序列,需要在每一条指令上执行一个“一致性算法”以保证每个节点看到的指令一致。一个通用的一致性算法可以应用在许多场景中,是分布式计算中的重要问题。节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing)。Paxos算法就是一种基于消息传递模型的一致性算法。BigTable使用一个分布式数据锁服务Chubby,而Chubby使用Paxos算法来保证备份的一致性。
采用乐观锁原理实现的同步
我们举个例子说明该算法的实现原理。如一个金融系统,当某个操作员读取用户的数据,并在读出的用户数据的基础上进行修改时(如更改用户帐户余额),如果采用前面的分布式锁服务机制,也就意味着整个操作过程中(从操作员读出数据、开始修改直至提交修改结果的全过程,甚至还包括操作员中途去煮咖啡的时间),数据库记录始终处于加锁状态,可以想见,如果面对几百上千个并发,这样的情况将导致怎样的后果。
乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
对于上面修改用户帐户信息的例子而言,假设数据库中帐户信息表中有一个 version 字段,当前值为 1 ;而当前帐户余额字段( balance )为 $100 。
操作员 A 此时将其读出(version=1 ),并从其帐户余额中扣除 $50($100-$50 )。
在操作员 A 操作的过程中,操作员B也读入此用户信息( version=1 ),并从其帐户余额中扣除 $20 ( $100-$20 )。
操作员 A 完成了修改工作,将数据版本号加一( version=2 ),连同帐户扣除后余额( balance=$50 ),提交至数据库更新,此时由于提交数据版本大于数据库记录当前版本,数据被更新,数据库记录 version 更新为 2 。
操作员 B 完成了操作,也将版本号加一( version=2 )试图向数据库提交数据( balance=$80 ),但此时比对数据库记录版本时发现,操作员 B 提交的数据版本号为 2 ,数据库记录当前版本也为 2 ,不满足 “ 提交版本必须大于记录当前版本才能执行更新 “ 的乐观锁策略,因此,操作员 B 的提交被驳回。这样,就避免了操作员 B 用基于 version=1 的旧数据修改的结果覆盖操作员A 的操作结果的可能。
乐观锁机制与分布式系统相结合上, 我整理了伪代码如下:
obj 操作的目标
vlaue 修改的值
atom_update_ver 每个目标上的版本,每次修改该值递增
set( obj, value)
{
//从每个节点上取出修改前的对象版本
get original_ver = obj.atom_update_ver from each node;
//将值赋到每个节点的obj目标
set obj = value from each node;
//条件修改每个节点的obj版本,目标版本加一
//比较和修改操作是原子操作
result = (set obj.atom_update_ver = original_ver + 1
where original_ver + 1 > obj.atom_update_ver
for each node);
if(result == ok)
return set_ok;
else
return set(obj, value);//不成功递归修改
该算法未考虑节点下线、失效等问题,在后续我将分析采用乐观锁原理实现一致性算法,解决问题2、节点失效、通信失败等问题。