Contenu connexe Similaire à 20120613联动优势数据访问层DAL架构和实践4(刘胜)最新特性 (20) 20120613联动优势数据访问层DAL架构和实践4(刘胜)最新特性2. 2
*版本历史
V1.20091123 基本概念,设计目标,关键技术,参考实现
V1.20091124 关键技术:编程语言,序列化,结果集
V1.20091125 关键技术:客户端接口,负载均衡,权衡
V1.20091203 关键技术:结果集序列化(测试比较)
V1.20091208 服务端存储方式,客户端访问接口,编程语言
V1.20091208 HA-JDBC,负载均衡
V1.20091209 +分布式存储引擎
V1.20091222 调整:概念/理念/方案/参考/实践
V1.20091222 +TCSQL,DbCached
V1.20091224 +客户端代码(PHP)。调整结构,去掉参考部分。
V1.20091224 【数据访问层DAL概念和实践1(刘胜)】
考:架构经验(淘宝,eBay)
V2.20100112 +参考:DB2复制,Tungsten Replicator
V2.20100114 *DAL设计目标,DB分片
V2.20100301 【(刘胜)NoSQL数据库知识图.mm】
V2.20100325 删除部分内容,突出DAL实现方面。
V2.20100330 【数据访问层DAL概念和实践2(刘胜).ppt】
V2.20100408 *中间层编程语言,TODO, CAP原则和NoSQL系统
V3.20100419 +概念:CAP原则和NoSQL分类;
V3.20100419 *概念:What and Why?;*设计0:DAL初步路线图*设计4
:服务的组织风格/传输协议
V3.20100419 *思考:初步架构设想2;*思考:淘宝经验(Session和CAP
优先)
V3.20100421 *实践:配置;客户端代码(+local);+读写分离;+预编
译;
V3.20100423 +参考MysqlProxy,BeansDB
V3.20100423 【数据访问层DAL架构和实践3(刘胜).ppt 】
V3.20100510 *实践:配置:vrdb/ds特定参数,DalServer/jmx等。。
。其他问题。
V3.20100510 +容错:Byzantine将军问题,BFT容错协议
V3.20100526 +实践:客户端(生成PO,自动注入)
专利:一种面向资源的分布式数据访问服务装置-专利交底
书-UMPay刘胜-v1.1批注.doc
专利:一种面向资源的分布式数据访问服务装置-专利申请
书-UMPay刘胜-v3.1(TD1007146F)-请发明人审核.doc
专利:一种面向资源的分布式数据访问服务装置-专利申请
书-UMPay刘胜-v3.7(TD1007146F)-LX-9.21.doc
-----------
V3.20100719 +版本持续改进
V3.20100806 +JMX管理功能,+性能测试和功能测试,*SOA
组织风格,+ROA和REST实践,+数据集分页技术
V3.20100816 +访问MemCached,*软件架构主题,。
V3.20110105 *设计4:DAL中间层编程语言
V3.20110301 +实践:新的认证方式
V3.20110617 +概念:NoSQL分类(按实现机制)
-----------
V4.20120301 +新特性:依赖注入,SQL注入、
V4.20120301 +新特性:日志时间分离、连接数控制
V4.20120613 【数据访问层DAL架构和实践4(刘胜)】
V4.20120613 +思考题,新特性
-----------
3. 3
*概念:软件架构主题
2009年软件架构主题!
架构模式:3&4层New
服务架构:SOA WOA
存储方式:RDB NoSQL
编程语言:编译型动态语言
应用类型:普通社会化
处理方式:集中式P2P
架构方式:封闭架构开放服务链
2010年软件架构主题?
架构模式:云计算五层架构
The Hardware Layer
The Virtualization Layer
The IaaS Layer
The PaaS Layer
The SaaS Layer
服务架构:ROA
存储方式:NOSQL
【一家之言】
NoSQL Non-Relational DB
NOSQL Not-Only RDB
4. 4
*概念:什么是DAL
概念:数据访问层DAL 【Layer=Services】
【维基百科】A Data Access Layer (DAL) is a layer of a computer program which provides simplified access to
data stored in persistent storage of some kind, such as an entity-relational database. This data access layer is
used in turn by other program modules to access and manipulate the data within the data store without having to
deal with the complexities inherent in this access.
DAL是一系列服务的集合,是DAO在大型系统中的自然延伸,是SOA的具体实现。
好处:
简化客户端接口,规范数据操作【透明性分片】
保持客户端接口,动态升级服务端实现【SOA】
支持对巨量数据的访问【缓存;读写分离;分片(分库/分表)】
服务的治理【认证/管理/权限/监控/分析/优化/…】
功能需求:
访问代理【Proxy】
读写分离【RAIDb-1镜像,每个库都是全库。写库是单点】
数据分片【RAIDb-0分区,每个库都是子库。】
高可用性【支持Quorum-NWR模型——多个写库】
特性需求:
平台中立【DAL服务器,可部署在多种平台上】
语言中立【DAL客户端,支持Java、C/C++、PHP、Flex等多种语言。】
数据库中立【1)多种数据库类型;2)多个数据库版本?】
资源共享【1) 共享DataSource连接池; 2)共享Cache。】
访问日志【1)提供SqlLog可用于性能瓶颈分析;2)提供BackLog可用于数据恢复。】
访问控制【1)用户认证;2)连接管理;3)权限控制。】
读写分离【FullDB】
数据分片【分表,分库】
访问集群【负载均衡:HA-Proxy、JGroup】
5. 5
+概念:大型网站架构演变
数据中心:也是一
种服务,未必使用
DB,也可能是文件
,内存。
DAL:数据访问层
服务,隔离特定的
数据库,屏蔽分库
,分区,分片。
大型网站架构演变:
第一步:物理分离WebServer和数据库
第二步:增加页面缓存
第三步:增加页面片段缓存
第四步:数据缓存
第五步:增加webserver
第六步:分库
• 根据应用逻辑、用户ID 、时间来切分
• 数据库分区(Partition)
• 数据库分片(Sharding)
第七步:分表、DAL、分布式缓存
第八步:增加更多的webserver
第九步:数据读写分离和廉价存储方案
第十步:大型分布式应用、廉价服务器群
• 分布式文件系统:GFS、HadoopDFS
• 分布式存储:BigTable
• 分布式计算:MapReduce、Hadoop
参考:
http://www.blogjava.net/BlueDavy/archive/2008/09
/03/226749.html 大型网站架构演变和知识体系
6. 6
DAL
代理?
+规划:大型数据库架构规划
数据存储规划
根据事务与否:
是:RDBMS集中存储
否:NOSQL分布存储
根据应用分库:
根据数据分片:
横向拆分:根据ID拆分用户表
纵向拆分:根据时间拆分交易表
根据读写类型:读写分离
根据业务类型:
OLTP——行式数据库(在线库)
OLAP——列式数据库(历史库)
高可用性数据存储架构(适用不同场景)
Share-Storage主备架构:存储是单点
Share-Nothing主从架构:写库是单点
Share-Nothing主主架构:写库非单点
Share-Nothing双主多从:读写可分离
关键技术组件:
数据访问层DAL
协议:CM20长连接/HTTP连接
前端:异步处理,支持大并发
后端:同步调用,无需访问外部
框架:Dalet
数据复制工具(推vs 拉)
单DB2到单DB2(结构完全一致)
单DB2到单DB2(结构不完全一致)
单DB2到多DB2(部署多套即可)
单DB2到多MySQL(异构库)
单DB2到多NoSQL(异构库)
7. 7
负载层
CDN 区域负载
(可选)
F5/LVS
+Nginx/
Haproxy
Web前置集群综合前置FSL
异
步
订阅
同
步
服务层缓存层持久层
综合前置
FSL
SMS,Email,IM,…
通知和反馈
Memcached
+ Membase
二级缓存
应用切分
水平切分
垂直切分
读写分离
双主多从
F5/LVS
+Nginx/
Haproxy
主备机制
JMS
Camel
通过DAL访问
NOSQL
DB
Hadoop / HBase
…
NameNode2
复制
Master DB
(行式)在线交易库
Master / Slave,分片,集群
DataNodes
同NameNode1
步
异
步
页面缓存
Squid
Varnish
OSCache
静态资源
合作机构
银行
移动
商户
分布式服务集群
应用服务:ASL
基础服务:BSL
数据访问:DAL
监控服务定时服务:TSL
集群
+规划:总体技术规划系统视图
…
读
(列式)离线分析库
写
读…
复
制
Slave DB
8. 8
*设计:DAL演化路线图
第一阶段目标:访问代理
平台中立【DAL服务端,基于Java开发,可部署在多个平台上】
语言中立【DAL客户端,支持多种语言访问(JAVA/PHP/FLEX/…)】
厂商中立【支持多个数据库厂商;支持多个数据库版本?支持非RDB存储?】
第二阶段目标:服务治理
资源共享【共享连接池;共享缓存(Memcached/EhCached)】
权限控制【身份认证,连接管理,访问控制】
访问日志【SqlLog或BackLog】
监控优化【性能瓶颈分析和优化】
第三阶段目标:读写分离
读写分离【主从结构,需要额外的DB复制技术】
访问集群【负载均衡】
第四阶段目标:数据分片【针对RDB实现数据切分】
数据库分区(Partition)集中式/不能垮DB/Scale-Up/单点【厂商相关,不推荐】
数据库分片(ShardingP)分布式/垮多个DB/Scale-Out/无单点【厂商中立】
分库【虚拟库,不同表存在不同的实际库中】
分表【虚拟表,将同一库中多张小表虚拟成一个大表】
例:select * from db.A.1, db.A.2, db.A.3 where …
分库+分表【虚拟表,将不同库中多张小表虚拟成一个大表】
例:select * from db1.A,db2.A,db3.A where …
第五阶段目标:非结构化存储【针对NoSQL(RO/CO/KV/DO)的访问】
实现:三备份/NWR/多版本/… 【无需额外的DB复制,使用NWR模型】
9. 9
+背景:已有的中间层技术方案
方案1:Mysql-Proxy@MySQL官方
不支持分库分表,且性能较差。
方案2:Atlas@Qihoo360(王超)
基于mysql-proxy-0.8.2版
方案3:Amoeba@盛大(陈思儒)
for {MySQL | Aladdin | MongoDB}
不支持事务/存储过程/分库分表/输出大结果集。
方案4:Cobar@AliBaBa(贺贤懋)
基于amoeba-0.34版
开源版只支持MySQL,不支持读写分离。
方案5:TDDL@Taobao
复杂度相对较高,文档较少。
只开源动态数据源,不开源分库分表。
方案6:S3@Amazon
基于标准REST和SOAP接口的超级SAN存储
10. 10
设计0:DAL关键技术
关键技术的权衡和选择
1,SOA组织风格: 【ROA和REST】
2,中间层编程语言: 【Java vs C/C++】
3,后端存储方式: 【NO-RDB】
4,前端访问接口: 【NO-JDBC,NO-SQL】
No-JDBC
抛弃复杂的jdbc,服务端更容易解析
抛弃复杂的jdbc,客户端更容易使用
No-SQL 【用sqlid/callid替代sql语句】
抛弃复杂的sql语句,解析更容易,执行更安全。
5,协议(传输协议+数据协议)
数据传输协议【HTTP/TEXT/UM32/UM16/CM16/CM20】
序列化技术【xml/json/phprpc/amf3/java+gz/hessian2+gz】
结果集表示【List<Map<String,Object>>】
6,负载均衡: 【避免单点】
监控管理:
1.监控用户触发请求的成功率
2.监控随着数据量增长,单个请求的响应时间
3.监控分布式系统的单点线程并发数
4.监控分布式系统的点与点之间的报文请求成功率
NO=Not Only
11. 11
*设计1:SOA组织风格
三种SOA的组织风格
WOA【SOAP/XML-RPC/RSS/…】
广义:Web Oriented Architecture
狭义:WebService Oriented Architecture
ROA【RESTful HTTP/RSS/ATOM】
广义:Resource Oriented Architecture
狭义:RESTful-HTTP Oriented Architecture
REST:REpresentational State Transfer
MOA【ESB】
广义:Message Oriented Architecture
其他:Mobile Oriented Architecture
其他:Microsoft Oriented Architecture
几种SOA的组织风格的比较
组织风格WOA ROA/REST MOA/ESB
核心概念(面向动词)远程过程调用(面向名词)远程资源访问(副词)消息传输
标准新标准(SOAP/WSDL/WS-*) 现有标准(HTTP/XML/RSS) N/A
问题域覆盖全部的应用场景覆盖大部分应用场景N/A
内容协商不支持支持N/A
12. 12
*设计1:ROA和REST实践
REST设计准则:
将所有事物抽象为资源,分别对应唯一(不变的)URI; 【类似TDD,针对URI来设计】
将所有资源链接在一起; 【如,表示层HTML链接】
使用标准方法(HTTP)操作资源;
资源有多重表述形式; 【=》内容格式协商:1)根据HTTP头Accept信息;2)根据URI后缀】
强制采用无状态通信方式(stateless)。【参考: 大用户量的Session保持问题(淘宝) 】
RESTful API
Select doList() 【GET /rest2/resource】
Insert doCreate() 【POST /rest2/resource】
Select doSelect() 【GET /rest2/resource/id.xml】
Update doUpdate() 【PUT /rest2/resource/id.xml】
Delete doDelete() 【DELETE /rest2/resource/id.xml】
其他实现:
Restlet/Axis2/Cetia4/sqlREST/REST-art/JRest4Guice/GlassFish-Jersey(基于JAX-RS/JSR-
311)
BS3实现:Rest1【仅支持Servlet容器】
com.bs3.ext.rest.Servlet4Rest 【Servlet容器】
BS3实现:Rest2【仅支持HTTP协议:Servlet容器,或BS3/Mina2】
com.bs3.ext.rest2.RestletEngine4Servlet 【Servlet容器】
com.bs3.ext.rest2.RestletEngine4Mina2 【BS3框架】
BS3实现:Rest3/Dalet【支持多协议多服务:CM20/HTTP/…】
com.bs3.app.dal.engine.DalEngine2Restlet 【BS3框架】
13. 13
*设计2:DAL前端访问接口
你真的需要JDBC吗?
有状态的JDBC? 【ResultSet保持连接】
复杂的交互方式? 【Connection、Statement、ResultSet,事务】
你真的需要SQL吗?
SQL 【关系数据库,标准查询语言】
SQL/JOIN 【JOIN对性能影响很大】
其他选择
HQL 【Hibernate Query Language】
JDOQL 【JDO Query Language】
RESTful-DB 【CUID=Create Update Insert Delete】
NoSQL-DB 【=> 概念:CAP原则和NoSQL分类】
Dynamo@amazon,BigTable@google,Hypertable@baidu,Cassandra@facebook,Voldemort@linkedin,
PNuts@yahoo,TokyoCabinet,Dynomite,Redis,MongoDB,CouchDB/erlang,HBase,Riak,Tin,Flare,
Lightcloud/python,KiokuDB,Scalaris,Kai,ThruDB,......
自定义数据服务层——从DAO到DAL(Data Access Layer=Services)
抛弃复杂的JDBC接口=》Map请求+Object响应【语言中立,服务端易解析,客户端易使用】
抛弃完整的SQL功能=》采用:SQLID+参数【限制访问权限,解析更容易,执行更安全】
参考:
http://robbin.javaeye.com/blog/524977 NoSQL数据库探讨之一
http://journal.uggedal.com/nosql-east-2009---summary-of-day-1
http://www.oschina.net/p/mongodb 分布式文档存储数据库MongoDB/json(非RDB中功能最丰富)
http://www.blogjava.net/xjtuwz/archive/2009/12/20/306711.html NoSQL & MongoDB
http://www.oschina.net/p/couchdb 面向文档的数据库CouchDB/ErLang
http://www.oschina.net/p/monetdb 内存数据库MonetDB
http://www.oschina.net/p/hypertable 一个BitTable的开源实现
http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/ 介绍Cassandra
http://hi.baidu.com/beibeiboo/blog/item/5418ff35533b061b91ef3908.html 分布式存储引擎Dynamo
14. 14
*设计3:DAL后端存储方式
你真的需要RDB吗?
RDB的核心功能?
1,存储【替代——数据中心:RDB,CO,DO,KVS,BFS】
2,事务【替代——?——(无可替代)】
存储模型:
Relational DB(Row-Oriented) 【有模式:适于OLTP的行式数据库,即关系型数据库】
*Column-Oriented DB 【有模式:适于OLAP的列式数据库】 (对比)
Doucument-Oriented DB 【无模式(Schema-Free)】
*Key-Value-Store 【小数据:BDB/Memcachedb/Tokyo Cabinet/…】
*Big-File-Stroe 【大数据:GFS,Hadoop】
存储介质:
Five-Minute Rule for I/O 【Disk is Tape;Flash is Disk;RAM Locality is King. --Jim Gray 2006】
Web2.0时代
新需求:RDB无法满足的需求
High Performance 【对数据库高并发读写】
Huge Storage 【对海量数据的高效存储和访问】
High Scalability & High Availability 【高可扩展性和高可用性】
旧需求:非必须的RDB特性
数据库事务一致性需求;
数据库的写实时性和读实时性需求;
对复杂的SQL查询,特别是多表关联查询的需求
两种弱一致性理论:1)BASE理论;2)Brewer’的CAP理论(一致性,可用性,分布冗余)
参考
http://www.julianbrowne.com/article/viewer/brewers-cap-theorem
http://robbin.javaeye.com/blog/524977 NoSQL数据库探讨之一
http://www.dbanotes.net/arch/five-minute_rule.html 关于I/O 的五分钟法则(Five-Minute Rule)
http://www.dbanotes.net/techmemo/ssd_trend.html SSD 趋势小窥
RDB和CO的对比
?
数据库重构更容易!
16. 16
+概念:NoSQL分类(按CAP原则)
CAP原则
Availability:Each client can always read and write.
Consistency:All clients always have the same view of the data
Partition Tolerance:The System works well despite physical network
partitions.
Data Models
(RO) Relational (comparison) 【适于OLTP】
(CO) Column-Oriented 【适于OLAP】
(KV) Key-Value
(DO) Doucument-Oriented
(GO)Graph-Oriented 【适于SNS】
NoSql实例的分类:
C-A System:
(RO) RDBMs,Aster Data,Greenplum
(CO) Vertica
A-P System:
(KV) Dynamo,Voldemort,Tokyo Cabinet,KAI
(CO) Cassandra,
(DO) SimpleDB,CouchDB,Riak
C-P System:
(CO) BigTable,Hypertable,HBase/Hadoop
(DO) MongoDB,Terrastore
(KV) Scalaris,BerkeleyDB,MemcacheDB,Redis
C-A-P System:
(RO) C-JDBC/Sequoia
参考:
http://www.javabloger.com/article/about-mongodb-pdf-ppt.html mongodb入门介绍
http://nosql-database.org/ 官方网站
Availability
(可用性)
Consistency
(一致性)
Partition tolerance (分布式)
C+A
Pick Two !
C+A+P
17. 17
+概念:NoSQL分类(按实现机制)
1.key-value存储:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB
应用场景:内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统。
数据模型:Key指向Value的键值对,通常用HashTable来实现。
强项:查找速度快。
弱项:数据无结构,通常只被当作字符串或者二进制数据。
2.列式数据库: Cassandra, HBase, Riak
应用场景:分布式的文件系统。
数据模型:以列簇式存储,将同一列数据存在一起。
强项:读性能强;每列都是索引,查找速度快;可扩展性强,更容易进行分布式扩展。
弱项:写性能差,功能相对局限。
3.文档型数据库:CouchDB, MongoDb
应用场景:Web应用(与K-V类似,但Value是半结构化的,数据库了解Value的内容)
数据模型:Key-Value对应的键值对,Value为半结构化数据
强项:数据结构要求不严格,表结构可变,无需要像RDB一样需要预先定义表结构。
弱项:查询性能不高,而且缺乏统一的查询语法。
4.图结构数据库:Neo4J, InfoGrid, Infinite Graph
应用场景:社交网络,推荐系统等。专注于构建关系图谱
数据模型:图结构
强项:利用图结构相关算法。比如最短路径寻址,N度关系查找等
弱项:经常要对整个图做计算才能得出所需信息,该结构不太好做分布式的集群方案。
参考:http://blog.nosqlfan.com/html/1727.html 如何选择最适合你的NoSQL数据库
18. 18
*设计4:DAL中间层编程语言
背景:
Linux2.6引入NPTL,支持内核级多线程
,Java应用服务器的网络处理性能提升
了5倍【Robbin范凯】
Linux下Java6通过libevent库,和
memcached性能相当【许超前】
在Linux2.6中Java6的Selector采用
epoll机制实现【Alan Bateman】
Djava.nio.channels.spi.SelectorProvid
er=sun.nio.ch.EPollSelectorProvider
结论:【Java6】
网络延迟:(10..100)ms
并发连接:~100K
吞吐量:~30K request/s
参考:
http://timyang.net/programming/c-erlang-
java-performance/ 关于
C,Erlang,Java和Go的性能测试【注:已更新
,用Netty替代Mina进行比较,后者实现了更
多的协议栈。】
http://www.javaeye.com/topic/13042
讨论(robbin)
http://blogs.sun.com/alanb/entry/epoll
19. 19
*设计5:数据传输协议
可用协议
文本协议HTTP 【效率较差】=》HTML5/WebSocket
文本协议TEXT 【扩展性差(rn结尾)】
二进制协议:UM16/UM32 【PHP等语言访问不便】
半文本协议:CM20 【语言中立】《=memcached协议(文本|二进制)
自定义协议
VER 4 【=CM20】
FMT 4
请求:= XMAP,PROP,JAVA,H1SP(=hessian),H2SP(=hessian2),BURP(=burlap)
响应:= JAVA,J2GZ
响应:= XS2X,XS2J, BURP,H1SP,H1GZ,H2SP,H2GZ
响应:= GSON,JACK,AMF3,PHPC,
EC 2 【Cipher加密={00|D1|D3|A2}+CBC+Pkcs7Padding】
CS 2 【Charset字符集={GB|U1|U2|B5}】
LEN 8 【报文总长度,文本格式,最大约99M】
BODY ? 【任意数据,长度=(LEN-20)】
20. 20
设计5:序列化方式(比较)
要求:【小,快,多语言】,
实践:【MyStream.java】
XStream2Xml,XStream2Json,Jackson,TStreamAdaptor,
JavaRpc,JavaRpcZip,JavaRpcGz,PhpRpc,AMF3,Hessian,
Hessian2,HessianGz,Hessian2Gz,Burlap,JavaDeflater
结论:
初步比较
xstream/xml使用不同driver时:
xpp<xppdom<stax<dom<jdom
xstream/json比xstream/xml更慢!
phprpc和hprose/AMF3不能处理复杂对象!
其他比较:
Avro@Apache 【Hadoop】
Thrift@Apache 【Facebook】
ProtoBuf@Google 【需要编译】
Caucho:Hessian1/Hessian2和Burlap
json@Jackson 【格式中立】
gson@Google 【格式中立】
bson@mongodb 【C,PHP,Python,Ruby】
AMF3@Adobe 【小而慢】
Java/Serializable与Externalizable
压缩技术:Zip,GZip,Deflater
参考:
http://code.google.com/p/thrift-protobuf-compare/
wiki/Benchmarking 几种序列化机制的性能比较
http://labs.chinamobile.com/mblog/225_30690 大数据
的数据格式Avro
20091102关于RPC和序列化技术
Total Time =
Creating an Object
+ Serializing
+ Deserializing
21. 21
设计5:结果集RowSet
RowSet和ResultSet比较
ResultSet
只能向前滚动和只读的。都是有连接的。
RowSet
都是可滚动的和可更新的。非连接(可离线操作)。
RowSet接口说明
JdbcRowSet
唯一保持连接的RowSet。
CachedRowSet
离线增删改查,串行化,支持事件监听,分页等。
WebRowSet
可以序列化/反序列化到XML文件中。
FilteredRowSet
可通过设置Predicate可提供数据筛选和过滤。
JoinRowSet
提供类似SQLJOIN的功能(目前只支持InnerJoin)
参考:
http://www.ibm.com/developerworks/cn/java/j-lo-java6rowset/
index.html Java 6 RowSet 使用完全剖析
http://tech.it168.com/jd/2008-07-
04/200807040958443.shtml RowSet简单入门
22. 22
设计5:结果集序列化(比较)
示例代码:
DataSource ds = new DbArgs("root", "mysql", "jdbc:mysql://localhost/paydb").injectDsAlias("c3p0");
CachedRowSet crs = MyDB.doQuery4RowSet(ds, sql);
List<Bean> rlist = MyDB.doQuery4List(ds, sql, Bean.class, -1);//call:MyUtil.inject2bean()…
List<?> rlist = MyDB.doQuery4List(ds, sql, -1, null);//null = new RowMapper2Map0()
执行效率:【select name,passwd,regTime from tusers,返回7条记录】
doQuery4RowSet() 耗时29698(us)=44,48,1344,27640,81,64,477 【很慢】
doQuery4List(Bean) 耗时17662(us)=35,29,674,16712,35,30,147 【较慢】
doQuery4List(Map) 耗时2326(us)=19,22,617,1463,38,26,141 【推荐】
效率比较
(Unit=usec)
doQuery4RowSet doQuery4List(Map)
大小序列化时间反序列化时间大小序列化时间反序列化时间
XStream2/xml 9749C 27841 34752 2101C 1271 1973
XStream2/json 4791C 208816 14863 915C 2462 2774
Jackson/json 失败394C 143833 15806
PhpRpc/bin 7328B 19022 13190 643B 1769 672
JavaRpc/bin 6037B 21676 5240 734B 1938 920
Hessian/bin 7389B 42236 14769 656B 518 842
Hessian2/bin 3363B 6393 9438 374B 345 345
Hessian2/gzip 1484B 1654 2884 168B 469 244
AMF3/bin 失败223B 26100 22509
【结论】XStream2/json和Jaskson有时反序列化失败。而PhpRpc只处理java基本类型,AMF3使用ASObject类型
。【建议】采用List<Map<?,?>>保存数据,使用JavaRpc或Hessian2+gz来序列化。
23. 23
设计6:负载均衡
负载均衡:LVS > HA-Proxy > Nginx
内核级静态分发:LVS 【三种模式:NAT,TUN,DR】
应用级静态分发:Nginx 【HTTP层,简单加权轮询】
应用级智能分发:HA-Proxy 【HTTP+TCP层,后端探测,Cookie插入】
参考:
http://hi.baidu.com/zeorliu/blog/item/239eb601eefda20c1c95836c.html
24. 24
*设计6:逻辑架构(设想)
WebApp
+restlet2
+servlet
服务
BS3框架
+restlet2
+dalet
服务
Nginx
Nginx
LVS
基
础
服
务
层
B
S
L
资
源
服
务
分布式存储
memcached
mongodb
hbase、gfs
DB2
MySQL
Nginx分发机制
1,根据path负载均衡
2,根据http头
3,根据path分发
其他服务
+jsp
+asp
+php
中间件或服务
Tuxedo
CICS
ESB
三种LVS实现方式
1,IPVS-NAT
2,IPVS-TUN
3,IPVS-DR 应
用
服
务
层
A
S
L
调
度
服
务
同步
HA
Proxy
同步/异步
HA
Proxy
dalet
同步
负载均衡层LBL 应用服务层ASL 基础服务层BSL
复
制
dalet
dalet
LBL
25. 25
+专利,应用场景
1 应用逻辑层2 数据访问层DAL
Java应用
Php应用
Ruby应用
协议1/序列化1
协议1/序列化2
协议2/序列化3
Asp应用协议2/序列化4
2 数据访问服务
21
NIO
网络
协议
适配
器
22
数
据
服
务
引
擎
23
数
据
服
务
容
器
3 数据资源层
JDBC RDB1
API
……
Method + URI
2 数据访问服务
xxxx应用21 22 23
Dalet
一种面向资源的分布式数据访问服务装置
31 RDB集群
RDB2
RDB3
不同厂商:
db2/mysql/
…
RDB4
不同功用:
读库/写库
在线/离线
32内存数据库集群
33文档数据库集群
34缓存集群
35文件系统
2 数据访问服务
26. 26
+专利,DAL的层次
1 应用逻辑层2 数据访问层DAL
Java应用
Ruby应用
Asp应用
2 数据访问服务
21
NIO
网络
协议
适配
器
22
数
据
服
务
引
擎
23
数
据
服
务
容
器
3 数据资源层
JDBC RDB1
API
……
2 数据访问服务
xxxx应用21 22 23
Dalet
一种面向资源的分布式数据访问服务装置
31 RDB集群
RDB2
RDB3
不同厂商:
db2/mysql/
…
RDB4
不同功用:
读库/写库
在线/离线
32内存数据库集群
33文档数据库集群
34缓存集群
35文件系统
2 数据访问服务
IF1
Method+URI
DAL相关
IF1
Php应用
27. 27
+专利,系统架构图
1 应用逻辑层2 数据访问层(DAL)
1 应用系统(DAL)
2 数据访问服务(1)
21 NIO网络
协议适配器
22 Dalet引
擎
211 消息头
解析器
212 消息体
解析器
221 资源
分发器
222 操作
映射器
23 Dalet容器
● Dalet1
● Dalet2
…
http
11表现层
12逻辑层
13持久层
Method+URI
1应用系统(DAO)
11表现层
12逻辑层
13持久层
http
3 数据资源层
2 数据访问服务(2)
RDB1 RDB2 Cache File
IF2
21 22 23
IF1
IF3
DAO
28. 28
+专利,部署架构(云)
CM20/JSON
LB
2 数据访问
服务
●Dalet1
●Dalet2
…
数据访问层
DB2
MySQL
分布式
内存缓存
Memcached
分布式
文件系统
GFS
LB
HTTP/XML
负载均衡层数据资源层
应用逻辑层
JDBC
API
…
2 数据访问
服务
●Dalet1
●Dalet2
…
2
2
29. 29
-实践:服务端代码单服务(废弃)
服务端主程序
public class DalServer2 {
private static final MyLog _log = MyLog.getLog(DalServer2.class);
public static void main(String[] args) throws Exception {
MyUtil.setJmxIntegration(true);//启用jmx管理,需javassist和ognl库。
DalServer server = new DalServer();
server.setInitVrdb("/com/umpay/v3/dal/dal_vrdb.properties");
server.setInitRest(“/com/umpay/v3/dal/dal_rest.properties");
server.setInitAuth("/com/umpay/v3/dal/dal_auth.properties");
server.setInitUri(“cm20://0:8016”); //或者server.setInitUri(8016);
server.start();
//server.refresh(); //刷新相关配置:{auth,rest,sqlid等}...无法更新vrdb配置
//server.restart(); //重启整个服务:= stop()+start()...可更新vrdb配置
_log.info("服务%s", server.getService());
_log.info("测试%s/%s", server.getURI(), "dal/sqlid/testdb/sql_select.xml");
_log.info("测试%s/%s", server.getURI(), "dal/sqlwr/vdb.testdb/sql_select.xml");
_log.info("测试%s/%s", server.getURI(), "dal/prepareid/testdb/PrepareName1.xml");
}
}
自定义Restlet实现(废弃,改Dalet)
服务端JMX管理:jconsole
30. 30
-实践:服务端主程序多服务(废弃)
服务端主程序
public class DalServers2 extends DalServers {
private static final MyLog _log = MyLog.getLog(DalServers2.class);
public DalServers2(String cfg) throws IOException { super(cfg); }
protected Service4Mina2s createService(URI uri, HP4RpcInf proc) {
Service4Mina2s s = super.createService(uri, proc);
s.setSoLinger(0);//立即释放端口。
s.setReadIdle(61);
return s;
}
public static void main(String[] args) throws Exception {
DalHelper.setJmxIntegration(false);//启用jmx管理,需加入javassist-3.7.ga.jar和mina-ognl-2.7.2.jar库。
//DalHelper.setBioCodecMaxSize("cm20", 999999);//协议解析器最大报文长。
DalHelper.setRowListMax(99); //限制行结果的最大数。
DalHelper.setRowTitleLower(true); //强制行结果的字段名,转为小写后,方便转为Bean对象。
//DalHelper.initConfig(Dalet4Sqlid.class, “com/umpay/v3/dal/dal_psqlid.properties”);//废弃
DalHelper.initConfig(Dalet4PSqlid2.class, "com/umpay/v3/dal/dal_psqlid.properties");
DalHelper.initConfig(Dalet4MCache.class, "com/umpay/v3/dal/dal_mcache.properties");
DalHelper.initConfigAuth("com/umpay/v3/dal/dal_auth.properties");//servers.setInitAuth
DalHelper.initConfigVrdb("com/umpay/v3/dal/dal_vrdb.properties");//servers.setInitVrdb
DalServers servers = new DalServers2("/com/umpay/v3/dal/dal_rest.properties");//使用
servers.start("cm20://0:8020");
servers.start("http://0:8080");
}
}
自定义Restlet实现(废弃,改Dalet)
服务端JMX管理:jconsole
31. 31
+实践:服务端主配置多服务(推荐)
特点:
优点:直接通过配置文件传递参数,修改DalServers不再允许继承,方便版权保护。
缺点:无法修改Service4Mina2s相关参数。【改进:使用IoC配置beans.properties】
服务端主程序
java com.bs3.app.dal.engine.DalServers dal.properties
服务端主配置(dal.properties)
server.0 =cm20://0:8020
server.1 =http://0:8080
#server.2 =SSL.cm20://0:8021
#server.3 =ssl.http://0:8081
#server.4 =ssl2.cm20://0:8023
#server.5 =ssl2.http://0:8082
dal.jmx = 2
dal.row.to.lower=0
dal.row.max.list=990
#dal.bio.max.size=999990
cfg.auth=com/umpay/v3/dal/dal_auth.properties
cfg.vrdb=com/umpay/v3/dal/dal_vrdb.properties
cfg.rest=com/umpay/v3/dal/dal_rest.properties
com.bs3.app.dal.engine.Dalet4PSqlid=com/umpay/v3/dal/dal_psqlid.properties
com.bs3.app.dal.engine.Dalet4MCache=com/umpay/v3/dal/dal_mcache.properties
com.umpay.v3.dal.Dalet4PSqlid2=com/umpay/v3/dal/dal_psqlid.properties
服务端JMX管理:jconsole
32. 32
*实践:服务端配置(vrdb)
dal_vrdb.properties
Quorum容错算法:
数据至少备份N份
写入至少W份
读入至少R份
要求:W+R>N
# vdb.testdb = NWR111,wdb,rdb1,rdb2 # One-Write/Multi-Read 【Read/Write Splitting】
# vdb.testdb = NWR331,db1,db2,db3 # Multi-Write/Multi-Read 【Quorum】
vdb.testdb4HA = NWR331,testdb,testdb1,testdb2,testdb3
vdb.testdb = NWR111,testdb,testdb1,
vdb.crmusr = NWR111,crmusr,crmusr,
########## [bonecp,c3p0,dbcp,proxool,DriverManager,SingleConnection]
rdb.datasource.alias = bonecp # 【配置alias或class之一即可】
#rdb.datasource.class = org.springframework.jdbc.datasource.SingleConnectionDataSource
#rdb.datasource.class = org.springframework.jdbc.datasource.DriverManagerDataSource
#rdb.datasource.class = org.logicalcobwebs.proxool.ProxoolDataSource
#rdb.datasource.class = org.apache.commons.dbcp.BasicDataSource
#rdb.datasource.class = com.mchange.v2.c3p0.ComboPooledDataSource
#rdb.datasource.class = com.jolbox.bonecp.BoneCPDataSource
##########
testdb.jdbc.username=root
testdb.jdbc.password=
testdb.jdbc.url=jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=GBK
#testdb.jdbc.url=jdbc:log4jdbc:mysql://localhost:3306/testdb # 【调试】记录详细日志
#testdb.jdbc.driver=org.gjt.mm.mysql.Driver #【可选】自动识别
{mysql,db2,oracle,mssql,derby,hsqldb,sqlite,h2,sybase,informix,postgresql,odbc,log4jdbc}
testdb.pool.max=20 #
testdb.pool.min=4 #
testdb.pool.wait=5000 # 【单位:毫秒】
testdb.partitionCount = 2 # 【可选】针对bonecp的特殊参数
testdb.maxConnectionsPerPartition=10 # 【可选】针对bonecp的特殊参数(2×10 = 20)
testdb.minConnectionsPerPartition=2 # 【可选】针对bonecp的特殊参数(2×2 = 4)
testdb.releaseHelperThreads = 2 # 【可选】针对bonecp的特殊参数
33. 33
*实践:服务端配置(rest3)
直接SQL模式【直接使用SQL语句,查询或者更新,无法控制权限】
# cm20://localhost:8016/dal/query/testdb
/dal/query.xml= com.bs3.app.dal.Dalet4Cm20Query
/dal/query/{dbname}= com.bs3.app.dal.Dalet4Cm20Query
/dal/update.xml= com.bs3.app.dal.Dalet4Cm20Update
/dal/update/{dbname}= com.bs3.app.dal.Dalet4Cm20Update
间接SQL模式【使用URI参数组成SQL语句,只适应简单查询,已废弃】
# cm20://localhost:8016/dal/select/testdb.xml/tusers/*/1
/dal/select/{dbname}/{tables}/{fields}/{wheres}= com.bs3.app.dal.Dalet4Cm20Select
使用RESTDB模式【把table映射为一个REST资源(未完)】
# cm20://localhost:8016/dal/restdb.xml
/dal/restdb/{dbname} = com.bs3.app.dal.Dalet4Cm20Restdb
/dal/restdb/{dbname}/{table} = com.bs3.app.dal.Dalet4Cm20Restdb
使用SQLID模式【远程方法调用RPC模式(推荐)】
# cm20://localhost:8016/dal/sqlid/testdb/findAll.xml
#/dal/sqlid/{dbname} = com.bs3.app.dal.engine.Dalet4Sqlid
#/dal/sqlid/{dbname}/{sqlid} = com.bs3.app.dal.engine.Dalet4Sqlid
#/dal/sqlrw/{dbname}/{sqlid} = com.bs3.app.dal.engine.Dalet4SqlidRw
#/dal/sqlrww/{dbname}/{sqlid} = com.bs3.app.dal.engine.Dalet4SqlidRww
#/dal/prepareid/{dbname}/{sqlid} = com.bs3.app.dal.engine.Dalet4Prepareid
#/dal/callid/{dbname}/{sqlid} = com.bs3.app.dal.engine.Dalet4PrepareCall
#/dal/sqlidn1/{dbname}/{sqlid} = com.bs3.app.dal.engine.Dalet4SqlidN1
#/dal/sqlidn2/{dbname}/{sqlid} = com.bs3.app.dal.engine.Dalet4SqlidN2
/dal/psqlid/{dbname}/{sqlid} = com.bs3.app.dal.engine.Dalet4PSqlid
/dal/mcache/{keyid} = com.bs3.app.dal.engine.Dalet4MCache
已合并为
DaletPSqlid
34. 34
+实践:服务端配置(auth)
认证方式
1,三步:Connect,Auth,(Request)* 【Poll模式连接池:类似SMPP/CMPP方式】
2,两步:Connect,(Auth & Request)* 【Push模式连接池:类似HTTP-Auth方式】
验证算法
算法【mac = bcd(md5(path|pass|from|nonce) 】
String src = String.format("%s|%s|%s|%s", authPath, authPass, authFrom, nonce);
String md5 = MyUtil.bcd(MyUtil.md5(src.getBytes()));
注:
Nonce 要求:1)不重复;2)递增(非顺序递增) 【建议使用long型时间戳】
authPath 包含了userId信息,如/dal/login/lius.xml。
authFrom 为客户端IP地址,该信息从socket上获取,不在报文中传递。【Ha-Proxy?】
authPath 包含了userId信息,如/dal/login/lius.xml?nonce=1234
认证和授权的配置文件(dal_auth.properties)
# ROLE.right = this.getClass().getSimpleName()+",";
guest.PASS=guest
guest.ROLE=Dalet4Sqlid2,,,,,
lius.PASS=liuspwd
lius.ROLE=Dalet4Sqlid, Dalet4SqlidRw,Dalet4Prepareid,,,
#lius.FROM=127.0.0.1,10.10.41.220 【废弃】
Lius.LIMIT=9 【新增特性】
35. 35
*实践:服务端配置(psqlid)
dal_psqlid.properties
#####################
#PUT.set_charset_ci = SET COLLATION_CONNECTION='utf8_general_ci'
PUT.set_names = SET NAMES {charset}
PUT.set_charset = SET CHARACTER SET {charset}
PUT.set_charset_ci = SET COLLATION_CONNECTION='{charset_ci}'
#####################
# INSERT INTO {tables} ("f1", "f2", ...) VALUES ("v1", "v2", ...)
# UPDATE {tables} SET 'f1'='v1','f2'=v2 WHERE {wheres}
GET.sql_select = SELECT {fields} FROM {tables} WHERE {wheres} {others}
PUT.sql_insert = INSERT INTO {tables} ({fields}) VALUES ({values})
PUT.sql_update = UPDATE {tables} SET {fieled_values} WHERE {wheres}
#####################
GET.users_findAll = select {fields} from tusers
GET.users_findOne = select {fields} from tusers where id='{userid}'
PUT.users_delete = DELETE FROM tusers where id='{userid}'
PUT.users_insert = INSERT INTO `tusers` (`id`, `passwd`, `payPasswd`, `regTime`,
`lastLogTime`, `name`, `sex`, `certType`, `certNum`, `addr`, `zipCode`, `email`, `tel`, `state`,
`tuseraccount_id`) VALUES ('{userid}', '{passwd}', '{payPasswd}', '{regTime}', '{lastLogTime}',
'{name}', '{sex}', '{certType}', '{certNum}', '{addr}', '{zipCode}', '{email}', '{tel}', '{state}',
'{tuseraccount_id}')
dal_callid.properties
id是保留字,最好不要用做参数名,改userid。
GET.psql_test1 = select * from tusers where id={userid.string}
PUT.call_getseq = call mobile.getseq({name.string}, {out.seq.int})
PUT.call_PRiskControl_XE = call
参数名,含类型信息!
参数名,含返回信息。
MOBILE.PRiskControl_XE({busitype.string},{provcode.string},{areacode.string},{consign.int},{rolltyp
e.string},{balsign.int},{balkeep.int},{mobileid.string},{amount.int},{xiaopaysign.int},{merid.string},
{goodsid.string},{merltdsign.int},{condaypayedswitch.int},{maxnum.int},{within.int},{out.grade.int
},{out.ret.int},{OUT.msg.string})
OUT不区分大小写。
36. 36
-实践:PHP客户端(验证测试)
<?php
error_reporting (E_ALL);
$address = '127.0.0.1';
$service_port = 8016;
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket<0){ echo "n<br/>socket_create() failed: reason: " . socket_strerror($socket); }
$result = socket_connect($socket, $address, $service_port);
if ($result<0){ echo "n<br/>socket_connect() failed.nReason: ($result) " . socket_strerror($result);}
$in_xml0 = "<?xml version='1.0' encoding='GB2312'?><request><Accept-Type>PHPC</Accept-
Type><METHOD>GET</METHOD><URI>/dal/select/testdb.xml/tusers/*/1/1/1</URI></request>";
$in_body = formatcontent($in_xml0);
$in_head = "CM20XMAP00GB00000" . (20+strlen($in_body));
socket_write($socket, $in_head, 20);
socket_write($socket, $in_body, strlen($in_body));
while ($out = socket_read($socket, 2048)) { echo $out; }
socket_close($socket);
function formatcontent($text){
$trans = get_html_translation_table(HTML_SPECIALCHARS);
$trans = array_flip($trans);
$text = strtr($text, $trans);
return $text;
}
?>
37. 37
实践:客户端(远程和本地)
测试用例(DalClientsTest2类)
static void main_init() throws Throwable {
//MyLog.configure("dal_log4j.properties", true);
MyLog4j.configure("log4j.properties", true);
MyUtil.setDynamicLoading(5000);
DalHelper.setRowTitleLower(true);
DalHelper.setBioCodecMaxSize("cm20", 999000);
DalHelper.initConfigVrdb(cfg_vrdb);//"/com/umpay/v3/dal/dal_vrdb.properties"
DalHelper.initConfigAuth(cfg_auth);//"/com/umpay/v3/dal/dal_auth.properties"
DalHelper.initConfigRest(cfg_rest);//"/com/umpay/v3/dal/dal_rest.properties"
DalHelper.initConfig(Dalet4PSqlid.class,cfg_psqlid);//"/com/umpay/v3/dal/dal_psqlid.properties"
}
public static void test_local_vs_remote() throws Exception {
Map<String,String> args = new HashMap<String,String>();
args.put("tables", "tusers");
args.put("fields", "count(*) AS COUNT");//= [{COUNT=1}]
args.put("wheres", "id='13801092024'");
args.put("others", "");
DalApi4Inf api_remote = DalClientFactory.newRemoteApi(dal_uri, dal_fmt, 1, 5);
test_api(api_remote, "GET", "/dal/sqlid2/testdb/sql_select.xml", args, LinkedList.class);
//DalApi4Inf api_local = DalClientFactory.newLocalApi0(null, null, args, “testdb”); //【废弃】只支持sqlid模式
DalApi4Inf api_local = DalClientFactory.newLocalApi2(null, null, null, null); //【推荐】根据uri分发
test_api(api_local, "GET", "/dal/sqlid2/testdb/sql_select.xml", args, LinkedList.class);
api_remote.close(); //关闭
api_local.close();//关闭
}
static void test_api(DalApi4Inf api, String method, String uri, Map<String,String> args, Class<?> clz) throws Exception {
boolean modified = "PUT".equalsIgnoreCase(method);
Object ret = (modified ? api.doPUT(uri, args, clz) : api.doGET(uri, args, clz));
_log.info("### test_api(%s) = %s", uri, ret);
return ret;
}
38. 38
+实践:客户端(工厂模式)
新增DalClientFactory类
public static void close(DalApi4Inf api);
public static DalApi4Inf newRemoteApi(String uri, String fmt4, int min, int max);
public static DalApi4Inf newRemoteApi(String uri, String fmt4, int min, int max, String
authUri, String authPwd, String authIp);
public static DalApi4Inf newLocalApi2(String cfgVrdb, String cfgRest, String cfgAuth,
String cfgPsql);
public static DalApi4Inf newLocalApi0(String cfgVrdb, String cfgPsql,
Map<String,String> args, String dbname);// @deprecated
注意:
1,用newLocalApi2替代newLocalApi0方法,后者只支持Dalet4Sqlid类。
1,不要每次创建,尽量缓存。
2,在多ClassLoader环境下,无法通过static确保唯一,单子模式失效。
3,及时释放资源,如在WebApp关闭时,调用DalClientFactory.close方法。
39. 39
+实践:客户端(读写分离和预编译)
读写分离
api.doGET("/dal/sqlrw/vdb.testdb/sql_select.xml", args, LinkedList.class);
api.doPUT("/dal/sqlrw/vdb.testdb/sql_insert.xml", args, Integer.class);
预编译
配置(callid.properties)
GET.PrepareName1 = select * from tusers where id={userid.string}
public static void test_prepareid() throws Exception {
DalApi4Sqlid api = new DalApi4Sqlid(new URI(uri), 2, 5, “H2GZ”, “GBK”, 1234L);
api.setAuth("/dal/login/lius.xml", "liuspwd", "127.0.0.1");//【增加登录信息】
String uri = "/dal/prepareid/testdb/PrepareName1.xml";
Map<String,String> args = new HashMap<String,String>();
args.put(“userid.string”, “13801092024”);//【名字中包含类型信息,不支持datetime】
//args.put("arg1.int", "1234");
//args.put("arg2.long", "1234");
//args.put("arg3.byte", "1234");
//args.put("arg4.float", "1234");
//args.put("arg5.double", "1234");
//args.put("arg6.boolean", "1234");
Object ret = api.doGET(uri, args, LinkedList.class);
api.close();
_log.debug("# prepareid(%s) = %s", uri, ret);
}
参数名,含类型信息!
40. 40
+实践:客户端(生成PO和属性注入)
生成PO对象
public static void test_sqlid_PoGenerator() throws Exception {
PoGenerator.setInitVrdb("/com/bs3/app/dal/engine/dal_vrdb.properties");
PoGenerator.setUseNumber(true);//使用Integer还是int方式。
PoGenerator g = new PoGenerator();
g.setPackage("com.umpay.v3.dal.po2");
g.setPackageBase("./src");//定义PO文件的基路径
g.setDbType(“db2”);//db2不支持where 0子句。
g.genPo(PoGenerator.getConnection("crmusr"), "umpay.t_user", "*", false);
g.setDbType(“mysql");
g.genPo(PoGenerator.getConnection("testdb"), "user", "id,username", false);
g.genPo(PoGenerator.getConnection("testdb"), "user", null, true);//生成文件
g.genPo(PoGenerator.getConnection("testdb"), "tweets", null, true);
g.genPo(PoGenerator.getConnection("testdb"), "followers", null, true);
g.genPo(PoGenerator.getConnection("testdb"), "following", null, true);
}
根据PO对象注入属性值
List<Map<String,String>> rlist = (List<Map<String,String>>)
api.doGET("/dal/sqlid/testdb/user_findAll.xml", args, LinkedList.class);;
for(Map<String,String> map: rlist) {
User user = new User();
MyUtil.inject2setter(user, map, false);//将属性值注入user对象。
_log.info("# inject2setter() = %s", user);
}
41. 41
+实践:JMX管理功能(+演示)
工具:jconsole
组件:MBean
分组:Service4Mina2s-8020-Cm20Codec
Service4Mina2s
属性:SessionsCount/SessionsCountMax/…
操作:restart()/disconnectAll()/disconnectIP(ip)
ProtocolCodecFilter
ExecutorFilter
属性:poolSize/maximumPoolSize/…
NioSocketAcceptor或NioSocketConnector
属性:readIdleTime/maxReadBufferSize/…
组:NioSocketSession@127.0.0.1
NioSocketSession
操作:close()
分组:Service4Mina2s-8080-HttpCodec
。。。
其他:Bonecp
TODO:根据USER对Session分组。
42. 42
+实践:性能测试和功能测试
20100719 测试(张文凌)
测试环境:58/Linux,语句:values current,连接池c3p0
测试结果:
JDBC1:线程数100,每线程500请求,耗时6122,吞吐量:8167/s 【线程只用一个连接,全部完成后再释放】
JDBC2:线程数100,每线程500请求,耗时9996,吞吐量:5002/s【线程每次从连接池获取/释放/…】
Local:线程数100,每线程500请求,耗时54675,吞吐量:914/s【DalApiLocal】
Local:线程数100,每线程500请求,耗时61178,吞吐量:817/s【DalClient4Local】
Remote:线程数100,每线程500请求,耗时73078,吞吐量:758/s
20100729 测试(刘胜)优化DalEngine后
测试环境:220/WinXP,连接池bonecp,去掉mpsp.log日志,去掉GET控制台日志。
测试结果:本地模式
# test_sqlid_performance() 连接数(1..50),线程数50,每线程500请求,耗时13094ms,吞吐量:1909/s
地址:/dal/psqlid/uselect/db2_select_now.xml
# test_sqlid_performance() 连接数(1..50),线程数50,每线程500请求,耗时3922ms,吞吐量:6374/s 地
址:/dal/psqlid/testdb/mysql_select_now.xml
# test_sqlid_performance() 连接数(1..50),线程数50,每线程500请求,耗时3985ms,吞吐量:6273/s 地
址:/dal/psqlid/testdb/mysql_select_now.xml
# test_sqlid_performance() 连接数(1..50),线程数50,每线程500请求,耗时3750ms,吞吐量:6666/s 地
址:/dal/psqlid/testdb/mysql_select_now.xml
测试结果:远程模式(DalServer在本机)
0729.113557.625 [main] INFO L:50 DalClientsTestNio - 【BIO】连接数(50..50),线程数50,每线程
800请求,耗时32579ms,吞吐量1228/s cm20://localhost:8020/dal/sqlid2/testdb/sql_select.xml
0729.113707.968 [main] INFO L:50 DalClientsTestNio - 【BIO】连接数(20..20),线程数20,每线程
2000请求,耗时30593ms,吞吐量1307/s cm20://localhost:8020/dal/sqlid2/testdb/sql_select.xml
0729.114938.375 [main] INFO L:50 DalClientsTestNio - 【BIO】连接数(50..50),线程数50,每线程
800请求,耗时33016ms,吞吐量1211/s cm20://localhost:8020/dal/sqlid2/testdb/sql_select.xml
参考:
20100707(张文凌)DAL性能测试结果.xlsx.et 【Win/Linux,Local和Remote,JDK5/JDK6】
20100730(纪鑫宇)DAL功能测试结果.xlsx 【类型支持,功能支持,读写分离,字符集支持】
43. 43
+实践:结果集分页技术
方式:
1,iBatis或Hibernate
2,直接修改psqlid配置文件的sql语句。
样例:通过PoGenerator生成PO对象以及SQL模板
代码:见【实践:客户端(生成PO和属性注入) 】
方法:
String sql_query_first(String dbtype,String table,String fields,String wheres,String orders,int n);
String sql_query_limit(String dbtype,String table,String fields,String wheres,String orders,int
offset,int n);
类型:MySQL/PostgreSQL/SQLite/HSQLDB/H2
queryFirst = SELECT {fields} FROM tusers WHERE {wheres} ORDER BY {orders} LIMIT 15
queryPage = SELECT {fields} FROM tusers WHERE {wheres} ORDER BY {orders} LIMIT 15 OFFSET 0
类型:DB2
queryFirst = SELECT {fields} FROM umpay.t_user WHERE {wheres} ORDER BY {orders} FETCH FIRST 15
ROWS ONLY
queryPage = SELECT * FROM (SELECT RANK() OVER( ORDER BY {orders}) AS i_,{fields} FROM
umpay.t_user WHERE {wheres}) AS T_ WHERE i_>0 FETCH FIRST 15 ROWS ONLY
#queryPage = SELECT * FROM (SELECT ROWNUMBER() OVER( ORDER BY {orders}) AS i_,{fields} FROM
umpay.t_user WHERE {wheres}) AS T_ WHERE i_>0 FETCH FIRST 15 ROWS ONLY 【ROWNUMBER()=ROW_NUMBER() 】
类型:Oracle
queryFirst = SELECT {fields} FROM mobile.tarea WHERE {wheres} ORDER BY {orders} WHERE ROWNUM<=1
queryPage = SELECT * FROM(SELECT T.*,ROWNUM RN FROM (SELECT {fields} FROM mobile.tarea WHERE
{wheres} ORDER BY {orders}) T WHERE ROWNUM<=15) WHERE RN>0
参考:
http://en.wikipedia.org/wiki/Select_(SQL)
44. 44
+实践:访问MemCached*
相关配置
Dal.properties
com.bs3.app.dal.engine.Dalet4MCache=com/umpay/v3/dal/dal_mcache.properties
Dal_rest.properties
/dal/mcache = com.bs3.app.dal.engine.Dalet4MCache
/dal/mcache/{keyid} = com.bs3.app.dal.engine.Dalet4MCache
Dal_mcache.properties
mcache.server.0=localhost:11211
mcache.weight.0=5
mcache.initConn=2
mcache.minConn=2
mcache.maxConn=20
mcache.maxIdle=188000
mcache.maxBusyTime=122000
mcache.maintSleep=5000
mcache.socketTO=3000
mcache.socketConnectTO=9000
mcache.failover=false
mcache.nagle=false
mcache.aliveCheck=true
mcache.hashingAlg=3 【CONSISTENT_HASH】
测试用例:
DalClientsTest2.test_dalet4mcache()
GET http://localhost:8080/dal/mcache/id.xml?x-accept-charset=GBK&x-accept-format4=GSON
POST http://localhost:8080/dal/mcache/id.xml?x-accept-charset=GBK&x-accept-format4=GSON
GET http://localhost:8080/dal/mcache/id.xml?x-accept-charset=GBK&x-accept-format4=GSON&METHOD=POST&VALUE=123&CMD=replace
相关参数:
Keyid在uri中定义
Value只能是String类型,通过VALUE值传送。
方法与method相关(GET=get,PUT=set)。【通过增加CMD参数来支持get/set以外的其他方法。】
其他特性:1,动态更新配置。2,一致性HASH算法
45. 45
+实践:新的认证方式(多IP和Nonce)
原因:
引入负载均衡层,地址不再唯一确定。
未来可能存在其他认证。
改进:
1,支持逗号分隔的多authIP格式:ip1,ip2,ip3,… 【多IP源】
2,更新rest配置,根据authPath获取dalet来完成认证。【多算法】
3,改进authType算法,消除authNonce项。【精简数据项】
旧:bcd(md5(authPath|authPwd|authIP|nonce))
新:bcd(md5(authPath?nonce=x|authPwd|authIP|null))
新旧版交叉兼容性分析:
0,客户端(旧)访问服务端(旧)
算法:bcd(md5(/dal/login/user.xml|pwd|IP1|nonce))
校验:1)获取RemoteAddress;2)IP相同;3)获取nonce非null;4)计算MD5相同。
1,客户端(旧)访问服务端(新) 【兼容】
算法: bcd(md5(/dal/login/user.xml|pwd|IP1|nonce))
校验:1)获取authFrom项;2)IP包含; 3)获取nonce非null; 2)计算MD5相同。
2,客服端(新)访问服务端(旧) 【不兼容】
算法: bcd(md5(/dal/login/user.xml?nonce=x|pwd|IP1,IP2,IP3|null))
校验:1)获取RemoteAddress;2)IP不相同;2)获取nonce为null;3)计算MD5相同。
其他问题:
增加authIP新IP地址? 【不拒绝,只记录告警日志用于审计】
46. 46
*小节:版本进展和TODO列表
V0.5 DONE 验证原型:
MyStream,CM16,DalServer,ClientApi
V0.9 DONE 基本实现
协议改进CM16=>CM20,优化字符集处理
支持ActiveTest报文处理。
定义DbPool4Vrdb替代DbPool4Args使DataSource参数可配置。
定义NamedProperties统一动态加载配置,定义DalEngine2基类。
使用Sqlid模式,支持参数化SQL,增加ClientApi类型
支持Exception处理,直接序列化返回给Client端。
增加Login处理【=》合并Sqlid和Auth功能,每次都带验证信息,增加IP验证。】
V1.0 DONE 功能完善
定义DalApi4Local支持Sqlid模式的本地操作,可部分替代iBatis功能。
定义Restlet4Cm20SqlidWR服务,支持读写分离。
定义Restlet4Cm20Prepareid服务,支持预编译SQL功能。
压力测试:本机MySQL测试:~450#/s =》需要改进:提高到1000#/s。。。DONE
结果缓存:本机HashMap缓存: =》需要改进:使用JVM外的缓存(如EHCached,Memcached)
动态配置:可动态配置auth/rest/sqlid =》需要改进:无法动态配置vrdb。。DONE:通过jmx重启服务。
访问日志:生成SqlLog =》DONE:分离出:查询日志SqlGetLog,更新日志SqlPutLog
V1.5 TODO
管理控制:用户认证,连接数限制,强制关闭客户连接,JMX管理。
优化客户端API接口:【使用poll模型替代push模型。支持批处理。使用单独的登录请求。支持多HOST负载均衡。】
增强服务端Rest功能:定义RestletCm20Callid支持存储过程操作。
V2.0 TODO
支持更多的分片模式。(按ID分片;按时间分片;按索引表分片;)
支持NoRDB存储方式(memcached,TTServer,mongodb,db4o)
支持NWR模型来提高可用性。
47. 47
+小节:版本持续改进Q3
Restlet/Dalet
Dalet4Sqlid
Dalet4Sqlrw
Dalet4PrepareSql
Dalet4PrepareCall
Dalet4Sqlid
Dalet4SqlidN1/N2/N3/…
Engine/Servers
DalEngine
DalEngine4Xml
/dal/psqlid/vdb.testdb/sql_select.xml
Dalet4PSqlid
DalEngine4XmlRest 【支持单格式{XmlAny}/单协议{CM20}/单服务】
DalEngine2 【引入NamedProperties】
DalEngine2Restlet 【支持多格式{XmlAny|XProps}/多协议/多服务,简化HTTP访问】
ClientAPI
远程:DalClients.DalApi4Sqlid
本地:DalClients.DalApi4Local => DalClient4Local
其他
支持JMX管理:Service4Mina2/Filter{Codec|Executor}/NioAcceptor/NioSession
生成PO对象,属性注入【MyUtil.inject2setter(Map, PO)】
支持BLOB/CLOB类型【BLOB=>Byte[],CLOB=>String】
例:update umpay.T_MER_CNF set mercert=blob('2131324124124124124') where merid='5632‘
连接池(Push和Poll模式)
BioSockPoolPoll: 使用Poll模式,直接获取连接,提交请求,等待接受响应。(不支持ActiveTest操作)
BioSockPoolCall: 使用Push模式,将请求委托给BioSockPoolCall完成。
BioSockPoolService: 持有BioSockPoolCall句柄。支持ActiveTest线程。
字符:对GBK/GB18030生僻字的支持。
分页:通过PoGenerator生成分页语句(支持mysql/db2/oracle/…)
支持访问MemCached 【支持哈希一致性算法】
48. 48
+小节:版本持续改进Q4
服务端:
Dalet4MCache 增加CMD参数支持set/get以外方法
Dalet4Mongo 支持MongoDB存储
Dalet4RestKvs 支持REST模式存储到内存Map中。
Dalet4RestRdb 支持REST模式存储到Rdb中。
TODO
Dalet4Lock 分布式锁服务
Dalet4ShardInt 按照Int类型ID进行分片
Dalet4ShardDate按照Date类型ID进行分片
多表查询
select * from user_0 union all select * from user_1;
49. +新需求:基础支付平台项目
49
背景:基础支付平台(核心账务系统)
前台:FSL前置服务层(协议适配,配置工具)
中台:ASL应用服务层(业务网关,支付网关)
后台:BSL基础服务层(数据访问,核心账务)
业务网关
通信前置
FSL 调度服务
ASL
核心系统
数据服务
DAL
基础服务
BSL
DB
Tuxedo
支付网关
BSL
支付网关
通信前置
FSL
通信前置
FSL
网银直连
银企直连
通信前置
FSL
接入前置
WEB
管理服务
MML
综合管理服务系统(管理/监控/安全/认证/…)
方法:一致性
将现有DAL产品,改造成DAL平台。
用一套框架实现三个服务子系统。
架构一致,开发一致,测试一致。
ALL in ONE
调
度
和
路
由
ASL
50. 50
+新特性:从DAL产品到DAL平台
DAL软件产品
主要模块
DalServers(配置dal.properties)
DalClient(DalLocalAPI,DalRemoteAPI)
PoGenerator
产品特性
支持两种协议(CM20,HTTP)
支持两种处理(同步,异步)
支持多种序列化和gzip压缩
文本格式:Burlap,XStream,GSON,Jackson等
十六进制:Java,Hessian,Hessian2,Phpc,AMF3等
支持三种模式:标准SQL,预编译SQL,存储过程
支持读写分离等特性
DAL服务平台
BeansServer(配置beans.properties)
支持依赖注入和参数配置,方便二次开发
支持参数注入到dalet中
有限状态机FSM模型
前端支持CM20和HTTP协议(NIO方式)
后端支持CM20和HTTP协议(异步调度)
改
造
中
51. 51
+新特性:依赖注入和IoC容器
问题:
配置少而僵化dal.properties
缺少依赖管理
改进:
实现IoC容器BeansContext/BeansContext2
配置多且灵活beans.properties
实现依赖注入
组件创建
Setter注入
构造子注入
初始化和销毁方法
循环依赖
预启动和延迟加载
容器注入:Map,Properties,List
基础
平台中立:多编程语言
内容协商:多种序列化
属性注入:DataSource
52. 52
+新特性:高可用mcache访问
实现
Dalet4MCache
特性:直接访问
Dalet4MCacheAW
特性:永远可写,尝试多次写入
配置:mcache.aw.max = 3
Dalet4MCacheNWR
特性:永远可读,参考NWR模型
配置:mcache.ar.nwr = 331 保留3个备份(n<w+r)
问题:
如何确定最终存储在哪个mcache节点?
确保多个备份,不在同一mcache节点。
53. 53
+新特性:防止SQL注入
实现:
扩展Dalet4PSqlid为Dalet4PSqlidSafe类。
覆盖hasSqlInject()方法。
使用
从Dalet4PSqlidSafe继承。
54. 54
+新特性:缺省参数(动态SQL)
目的:实现iBatis动态SQL效果
实现:支持sqlid参数的缺省值
格式:method.psqlid.参数名= {具体值| 字段名}
扩展:参数名=字段名,参数值=字段名
where子句:字段名=字段名【true】
update子句:字段名=字段名【不修改】
配置:
GET.sql_test3 = select * from `{tablename}` where
id>={userid} AND age={age}
GET.sql_test3.tablename = tusers
GET.sql_test3.userid = lius
GET.sql_test3.age = age
55. 55
+新特性:限制用户连接数
实现
Dalet4BaseAuth读取LIMIT参数(缺省值99)
DalMina2H4Rpc配置userLimit属性。
配置
修改dal_auth.properties增加
hfrisk.LIMIT=1
修改beans.properties
ServerIoHandler.class= com.bs3.app.dal.engine.DalMina2H4Rpc
ServerIoHandler.passive= true
ServerIoHandler.processor= @DalEngine
ServerIoHandler.userLimit= @DalUserLimit
DalUserLimit.class=com.bs3.app.dal.engine.DalUserLimit
56. 56
+新特性:批处理模式
需求(张峻嘉)多条SQL同一事务(非批次)
实现:修改Dalet4PSqlid 支持事务性多表更新
配置:psqlid.properties
已实现——sqlid必须以小写batch开头,值为多条普通sql语句,格式如:
sql1;sql2;sql3,暂不支持预编译sql方式。
未实现——sqlid必须以小写pbatch开头,值为单条预编译sql语句,参数Map
中为arg#1=v1,arg#2=v2格式。
需求(贺林)相同SQL不同参数(批执行)
实现
定义Dalet4PSqlidN处理预编译批处理多次提交DB(SELECT和UPDATE)
定义Dalet4PSqlidNBatch处理预编译批处理一次提交DB(非SELECT)
配置:和psqlid类似,以psql开头
参数:{1.arg1/1.arg2/…} + {2.arg1/2.arg2/…} + {…}
样例:见DEMO中DalClientsTest2.test_batchs()
57. 57
+新特性:获取DB连接时间
需求(张峻嘉)提供连接池大小限额的决策支持
功能:日志中分别记录获取DB连接时间、执行SQL时间
实现:修改SQL日志输出格式。
配置:无
58. 58
+新特性:预编译动态表名0720
问题
在对SQL预编译时,需获取数据库表名,通过表结构来决定执
行计划,否则执行失败。
解决
对于预编译SQL和存储过程模式,区分两类参数:
以下划线开头的参数,在预编译前直接替换为具体参数值。
非下划线开头的参数,在预编译前替换为问号,作为参数。
配置
GET.sql_test2 = select * from `{table.string}` where
id={userid.string} ——成功
GET.psql_test2 = select * from {table.string} where
id={userid.string} ——失败
GET.psql_test3= select * from `{_table}` where
id={userid.string} ——成功
59. 59
+新特性:在Spring中配置DAL客户端
关于DalApi4SqlidDecorator的问题。
1,混杂两种复用模式:继承和使用,可去掉一种。
2,无需新类也可在spring中配置使用。
<bean id=" DalApi4Sqlid" class="com.bs3.app.dal.client.DalClientFactory"
factory-method="newRemoteApi">
<constructor-arg type="java.lang.String" value="cm20://localhost:8020/"/>
<constructor-arg type="java.lang.String" value="JAVA"/><!--
={JAVA|J2GZ|XS2X|XS2J|JACK|GSON|BURP|H1SP|H1GZ|H2SP|H2GZ|...} -->
<constructor-arg type="int" value="1"/>
<constructor-arg type="int" value="5"/>
<constructor-arg type="java.lang.String" value="/dal/auth/lius.xml" />
<constructor-arg type="java.lang.String" value="liuspwd"/>
<constructor-arg type="java.lang.String" value="10.10.36.53,127.0.0.1"/>
</bean>
60. 60
Q结&束A:Q&A
现场问题——?
1,
2,
3,
思考题——
1,什么是DAL?
2,为什么要用DAL?
3,目前的DAL有哪些功能特性?
4,何时使用DAL本地调用接口?
5,何时使用DAL远程调用接口?
6,如何在自定义dalet中获取其它组件?
7,如何在自定义dalet中获取DAL本地调用接口?
61. 61
参考索引
参考:
20081113大型分布式系统架构技术简介(刘胜)中级.pdf
20081211大型软件系统开发综述(刘胜)中级.pdf
20090219网络信息安全和认证技术(刘胜)中级.pdf
20090625服务器框架的概念和实践(刘胜)初级.ppt
20090625分布式认证和授权技术(刘胜)初级.ppt
《2009系统架构师大会(演讲稿)》
20090914系统架构师2009大会归来(刘胜)暨头脑风暴.ppt
20091024手机之家的数据访问层实践(许超前).ppt
20091024高性能Web服务器Nginx及相关新技术的应用实践(张宴).ppt
20091102关于RPC和序列化技术的比较.txt
20091224数据访问层DAL概念和实践1(刘胜).ppt
20100326数据访问层DAL概念和实践2(刘胜).ppt
20100423第一届UMPAY技术大会(刘胜)基于SOA的DAL架构和实践.ppt
62. 62
参考:Dynamo概念
术语:
Q=虚拟节点数;S=实际节点数;N=数据备份数
;
W=要写入至少W份才算成功;
R=要读入至少R份才算成功;
问题1:实现动态扩容
算法:Consistent-Hashing算法
问题:实际节点的负载能力不一样。
改进:引入虚节点(Q >> S*N)
问题2:确保数据可靠
备份:N>=3,要求备份在不同实节点。
算法:NWR模型与同步和异步备份
数据一致性:W+R>N (即R>N-W,每次读取都至少读
到一个最新版本,从不会是一份旧数据)
高可写环境:N=3,W=1,R=N
高可读环境:N=3,W=N,R=1
版本一致性:多版本数据,Vector-Clock算法
服务端保留所有版本,用Vector Clock记录版本信息
。
当读取操作发生的时候返回多个版本,由客户端的业
务层来解决这个冲突合并各个版本。
最简单的策略:最近一次的写覆盖以前的写。
问题3:消除单点故障
参考:
http://hi.baidu.com/zeorliu/blog/item/98486
7f0a4b55bc97931aaf2.html 介绍Amazon的
Dynamo
论文:『amazon-dynamo-sosp2007.pdf』
NoSQL接口设计:
get(key)
getAll([key1,key2,key3,keyN])
put(key,value,version)
delete(key)
delete(key,version)
63. 63
参考:Dynamo关键技术
分布式设计的需求和概念
1.Eventual consistency 【过程松,结果紧】
过程中允许部分不一致;
但是在事务处理结束或者有限的时间内保持事务的一致性。
2.可用性,容错性,高效性。【通过NWR平衡】
3.分布式设计中两类一致性问题:
单点数据读写一致性:通过数据存储的服务端控制即可(类似于DB的控制)
多点数据读写一致性:通过消息传播的方式来实现(类似于JGroup在多播通
道传播同步消息)。
4.冲突解决。【数据多版本】
要点:
1. Consistent hashing算法支持分布式多节点
a,支持不同能力节点的权重设置。
b.动态新增或者删除节点时,减少数据复制。
c.动态新增或者删除节点时,平均压力分摊。
2. Vector clock管理数据多版本
64. 64
参考:Dynamo关键技术
分布式Key-Value存储Dynamo:
特点
完全去中心化,人工管理工作很小。
总是可写,可根据读写情况进行调整NWR来优化
采用的都比较成熟的技术来处理可扩展性和可用性问题
问题:Partitioning
技术:改进的Consistent Hashing
优点:Incremental Scalability
问题:High Availability for writes
技术:Vector clocks with reconciliation during reads
技术:Version size is decoupled from update rates.
问题:Handling temporary failures
技术:Sloppy Quorum and hinted handoff
技术:Provides high availability and durability guarantee
when some of the replicas are not available.
问题:Recovering from permanent failures
技术:Anti-entropy using Merkle trees
技术:Synchronizes divergent replicas in the background.
问题:Membership and failure detection
技术:Gossip-based membership protocol and failure
detection.
技术:Preserves symmetry and avoids having a centralized
registry for storing membership and node liveness
information.
参考:
http://hi.baidu.com/zeorliu/blog/item/984867f0a4b55bc97931aaf2.h
tml 介绍Amazon的Dynamo
http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html
『amazon-dynamo-sosp2007.pdf』
65. 65
+参考:豆瓣网BeansDB
主页:http://code.google.com/p/beansdb/
为什么做BeansDB?
其它Key-Value选择
Memcachedb,tokyotrant,主从复制【不便于Fail-Over】
其它类Dynamo选择
Dynomite:erlang完整实现,内存效率可能有问题
Voldemort:Java部分实现
最初的动机:
存储大量图片【MogileFS比较慢】
BeansDB相对Dynamo的简化
简化服务器端,在客户端实现Routing功能。
简化版本管理,用单版本号+时间戳
简化数据拆分,手动管理数据分布
简化协议,使用mc兼容协议
简化server端实现,tc+memcached
简化同步,外部定时任务实现
特性:
高可用:通过多个可读写的用于备份实现高可用
最终一致性:通过哈希树实现快速完整数据同步(短时间内数据可能不一致)
容易扩展:可以在不中断服务的情况下进行容量扩展。
高性能:异步IO和高性能的KeyValue数据TokyoCabinet
可配置的可用性和一致性:通过N,W,R进行配置
简单协议:Memcache兼容协议,大量可用客户端
66. 66
+容错理论
The Byzantine Generals Problem
Leslie Lamport, Robert Shostak, and Marshall Pease
ACM TOPLAS 1982
Practical Byzantine Fault Tolerance
Miguel Castro and Barbara Liskov
OSDI 1999
参考:
http://blog.sina.com.cn/s/blog_483452da0100brdm.html 拜占庭将军问题
http://www.pmg.csail.mit.edu/bft/ 【论文集】
http://people.csail.mit.edu/cowling/hq/
http://userweb.cs.utexas.edu/users/dahlin/projects/bft/
Byzantine fault tolerance(Liskov).ppt
Byzantine fault tolerance - Rice University.ppt
BFT Protocols Under Fire.pdf
BFT Protocols Under Fire(nsdi_talk).pdf
Conflict-free-quorums.pdf
HQ Replication.pdf
。。。
67. 67
+容错:Byzantine将军问题
概念(The Byzantine Generals Problem)
问题:设计一个协议,一个司令要送一个命令给他的n-1个副官,使得:
IC1.所有忠诚的副官遵守同一个命令。
IC2.如司令是忠诚的,则每一个忠诚的副官遵守他送出的该命令。
约定:忠诚的将军将遵守协议,而叛徒则可能破坏协议,尽可能的干绕其它人的判断。叛徒是匿名
的。而且最后不需要确定谁是叛徒。
目的:要让爱国的将军达成一致,而非找叛国的将军。
结论:
1 叛徒数m大于或等于将军总数n的1/3时,拜占庭问题不可解。
结论:当n<=3m时,将军们无法达成一致,即不存在同时满足IC1和IC2的协议。
2.用口头信息(Oral Message,OM),叛徒数少于1/3,拜占庭问题可解.
口头信息的三个条件:
A1) 传送正确。【TCP】
A2) 接收者知道是谁发的。【认证】
A3) 沉默(不发信息)可被检测。【丢包】
结论:当n>=3m+1时,可以让将军们可以达成一致。此时共需要信息交换轮数m+1.
3 用书写信息(Signed Message),至少两个忠诚,拜占庭问题可解
在口头信息的基础上, 书写信息又增加了两个条件
A4) 忠诚司令的签名不能伪造,内容修改可检测。【签名】
A5) 任何人都可以识别司令的签名, 叛徒可以伪造叛徒司令的签名。【??】
结论:当n>=m+2时,可以让将军们可以达成一致,此时共需要信息交换轮数m+1.
总结:OM(n,1)中n>=4;SM(n,1)中n>=3; 【3备份】
参考:
原文:http://yaowei211.blog.sohu.com/30757545.html
68. 68
+容错:BTF Basic protocol
BFT: Protocol overview
Client c sends m = <REQUEST,o,t,c>σc to the primary. (o=operation,
t=monotonic timestamp)
Primary p assigns seq#n to m and sends <PRE-PREPARE,v,n,m> σp
PBFT main ideas:
•Static configuration (same 3f+1 nodes)
•To deal with malicious primary
to other replicas. (v=current view, i.e., replica set)
If replica i accepts the message, it sends <PREPARE,v,n,d,i> σi to
other replicas. (d is hash of the request). Signals that i agrees to
assign n to m in v.
•Use a 3-phase protocol to agree on sequence number
Once replica i has a pre-prepare and 2f+1 matching prepare
•To deal with loss of agreement
messages, it sends <COMMIT,v,n,d,i> σi to other replicas. At this
point, correct replicas •Use agree a bigger on quorum an order (2f+of 1 requests out of 3f+within 1 nodes)
a view.
•Need to authenticate communications
Once replica i has 2f+1 matching prepare and commit messages, it
executes m, then sends <REPLY,v,t,c,i,r> σi to the client. (The need
for this last step has to do with view changes.)
69. 69
+容错:Byzantine容错协议
BFT(Byzantine-Fault-Tolerance)Approach
agreement-based 【Replica广播】
BFT基本协议【Practical BFT,3段协商】。。。
LBFT协议【LBFT1和LBFT2】。。。。。。。
Zyzzyva【3f+1,3 one-way latencies but need 3f+1 responsive 】
quorum-based 【Client协调】无并发写冲突时更优
Q/U 【Query/Update, 5f+1,1 roundtrip(SOSP 2005) 】
HQ 【Hybrid Quorum,3f+1, 2 roundtrips(OSDI 2006) 】
PBFT [OSDI'99]
Q/U [SOSP'05]
HQ [OSDI'06]
BAR [SOSP'05]
BFT2F [NSDI'07]
Zyzzyva [SOSP'07]
Shepherd
[SOSP'07]
A2M [SOSP'07]
70. 70
+容错:LBFT1和LBFT2
目的:简化协议,提高效率
环境:
参考:
Diverse Replication for Single-
Machine Byzantine-Fault-
Tolerance.pdf
71. 71
-容错:设计DAL的LBFT3协议(废弃)
交互协议(写操作)
DAL.C发送写操作请求PUT。
DAL.S获得vdb中的写库wdb。
DAL.S对wdb执行写操作,记录wlog作为恢复日志。
DAL.S对活动读库集[rdb1,rdb2,…]执行写操作。
DAL.S对非活动读库[rdb3]记录写操作到Q{rdb3}。
DAL.Q执行队列任务,完成写操作。
。。。未完。
72. 72
参考:数据库分区技术
DB2的Shared-Nothing架构(v9.0+)
数据库被分区到集群的每个节点上。每个节点都有一个数据的唯一子集
,所有访问这些数据的都要到这个节点。
数据并行操作的性能,取决于数据被合理的分区。
每个分区被各自的处理器进行管理。
系统可以使用双磁盘子系统,保留一个物理备份,来防止某个节点错误
影响系统可用性。不过此时依然会显著的降低整体性能。
它的Shared-Nothing指的是在运行期间对数据的所有权,而不是物理
上的关系。如果某个子集使用的皮率很高,则会降低整个系统的吞吐量
和性能。
RAC的Shared-Cache架构
RAC让磁盘可以被所有的节点链接来解决这个问题。
数据库文件在所有的节点间逻辑共享。每个实例都可以访问所有的数据
。
共享磁盘访问可以通过硬件链接或者操作系统层提供一个所有节点上设
备的单一视图。如果多个节点同时链接相同的数据块,事务共享磁盘数
据库系统使用磁盘I/O来同步多个节点的数据访问,比如通过一个写入
块的锁来防止其他节点访问同样的数据块。
磁盘可以进行分区管理,不过如果没有很好的分区,则会显著的影响性
能,并增加维护连续数据缓冲区的开销。
RAC使用了Cache Fusion, 一个共享一致性缓冲技术,通过高速的内部
连接的来维持共享一致性缓冲。Cache Fusion利用了集群里面所有节
点的缓冲来服务于数据库事务。
补充:
Greenplum也采用Shared-Nothing架构。
参考:
http://coderarea.net/html/shujukukaifa/DB2/2009/0310/58281.html DB2
和Oracle体系结构
http://en.wikipedia.org/wiki/Partition_(database)
http://tolywang.itpub.net/post/48/306675 理解oracle rac cache fusion
73. 73
开放系统的存储:
》内置存储
》外挂存储【按连接的方式分】
》》直连式存储(Direct-Attached Storage,简称DAS)
》》网络化存储(Fabric-Attached Storage,简称FAS)按传输协议分
》》》网络接入存储(Network-Attached Storage,简称NAS)
》》》存储区域网络(Storage Area Network,简称SAN)
参考:数据库分片技术
分片(Sharding)和分区(Partition)
存储依赖可跨DB,可跨物理主机可跨表空间,不同物理属性,不能跨DB存储
数据划分根据时间,范围,面向服务等根据范围,Hash,列表,混合分区等
存储方式分布式集中式
扩展性Scale-Out Scale-Up
可用性无单点存在单点(DB本身)
价格低廉适中(DAS直连式存储),昂贵(SAN存储区域网络)
应用场景常见于Web2.0网站多数传统应用
实现分片:
分片(水平分区) 分区
开源Sharding软件:
分片模式:
1.按功能划分(垂直切分)
2.按某一字段值的范围划分(水平切分)
3.基于HASH的切分
4.基于路由表的切分
MySqlProxy+HScal,Hibernate Shards,Spock Proxy,HiveDB,PL/Proxy,PyShards
自定义分片:所有的DAO操作至少需要增加一个参数(date或者id)
按时间分片(交易日表):1)操作原始表,定期归档成日表;2)直接操作日表; 【推荐2】
按ID分片(用户表) :针对主键字段,使用递增ID,每500万条记录单独分片【如QQ号】
按字段分片(索引表) :针对索引字段,以增量方式建立独立的索引表并分片【可选】
参考:
存储技术:http://www.it.com.cn/f/server/053/21/89080.htm 浅议DAS、NAS、SAN三种模式。
分片技术:http://www.dbanotes.net/database/database_sharding.html 开源数据库Sharding技术(2008.7);
http://hi.baidu.com/jabber/blog/item/e39ef81f1bca2df3e1fe0b3d.html HiveDB,一个横向切分MySQL海量数据
的框架(2008.7);http://www.ibm.com/developerworks/cn/linux/database/mysql-ha/index.html 基于MySQL的
数据库集群系统的实现(2003.3);http://www.360doc.com/content/090314/23/96202_2810788.html 读
“DB-Sharding@Netlog”看DB Scale Out(2009.3);
74. 74
参考:数据库复制技术
DB2的SQL复制
多种来源:
多个目标(跨DB)
DB2的Q复制
单一来源
单一目标(仅DB2)
基于可靠消息队列
76. 76
参考:架构经验(淘宝,eBay)
淘宝网架构经验(淘宝网架构师黄裳) :
1、适当放弃一致性【最终一致性,补偿交易】
2、备份和隔离解决稳定性问题【Embrace Inconsistency 】
3、分割和异步解决性能问题【Asynchrony Everywhere】
4、自动化降低人力成本【Automate Everything】
5、产品化管理
eBay架构经验:
1、Partition Everything 【分布式】
2、Asynchrony Everywhere 【异步化】
3、Automate Everything 【自动化】
4、Remember Everything Fails 【避免单点:1增加冗余;2层次化】
5、Embrace Inconsistency 【弱一致性】
6、Expect (R)Evolution 【演化而非革命】
7、Dependencies Matter 【依赖关系】
8、Be Authoritative 【?权威】
9、Never Enough Data 【?】
10、Custom Infrastructure 【定制基础架构】
参考:
http://www.dbanotes.net/arch/taobao_arch.html 来自淘宝的架构经验
77. 77
*参考:淘宝经验(Session和CAP)
问题1:巨量用户会话保持的四个方式:
1.粘性session 【一个用户的session保持在同一台机器上】
可能买家和卖家有交互,不利于通信,
下次再次登陆,还得是原来的机器,不利于负载均衡;
2.session复制【将session复制到多个机器,一致性差】
3.集中式session 【服务器压力大】
4.不用session改写cookie 【有些信息无法写在cookie】
cookie < sessionid = 1234
cookie < sessionid = mcache://domain:port/path/1234.ext
注:淘宝采用的是3和4相结合的方案
问题2:关于CAP优先级问题(淘宝)
支付业务:(C>A>P)优先一致性,其次可用性,最后关注分片。
读写分离:主库Oracle,从库Mysql,跨DB复制技术。
应用拆分:隔离非关键应用和非关键数据。
参考:
http://blog.hjenglish.com/eshow/articles/1493835.html
2009的SD2.0大会见闻
78. 78
参考:开源C-JDBC概念0
综合方案1:定制jdbc驱动;定制jdbc服务;
Sequoia是c-jdbc项目的延续(因和SUN的jdbc商标冲
突而改名),该项目发端于INRIA(法国国家计算机和
自动化研究院)的sardes项目。2003年提出了RAIDb的
概念,并开发c-jdbc作为软件实现,RAIDb借鉴了RAID
的思想,采用灵活的数据库复制技术和集成中间件,
以廉价、异构的数据库构建冗余数据库集群,从而提
供高可扩展、灵活的高性能集群。
参考
http://c-jdbc.ow2.org/ HA DB clusters with JDBC(已
改名Sequoia 2.10.10 http://sequoia.continuent.org
http://linux.softpedia.com/progDownload/Sequoia-
Download-477.html下载
http://forge.continuent.org/jira/browse/SEQUOIA
问题,代码库:cvs -z3 -
d:pserver:anonymous@sequoiadb.cvs.sourcefo
rge.net:/cvsroot/sequoiadb co -P modulename
)
http://liuye.javaeye.com/blog/224496 异构数据库中间
件sequoia(c-jdbc)初体验
http://www.continuent.com/community/lab-projects/
sequoia Important Update on Sequoia
Note: Sequoia is no longer actively developed or
supported by Continuent. Our main open source
project is Continuent Tungsten. Please consider
Continuent Tungsten as an alternative.
It is important to understand that Sequoia has a
number of trade-offs that limit its usefulness
because of the performance impact and lack of
application transparency. Tungsten processes
updates more quickly, handles a wider range of
SQL, works over a WAN, and permits direct
database access without proxies.
79. 79
参考:开源c-jdbc概念1
RAIDb
RAIDb concept
Redundant Array of Inexpensive
Databases
RAIDb controller
gives the view of a single
database to the client
balance the load on the database
backends
RAIDb levels offers various tradeoff
of performance and fault tolerance
RAIDb levels
RAIDb-0 【分区】
Partitioning
no duplication and no fault
tolerance
at least 2 nodes
RAIDb-1 【镜像】
mirroring
performance bounded by write
broadcast
at least 2 nodes
RAIDb-2
partial replication
at least 2 copies of each table for
fault tolerance
at least 3 nodes
SQL requests
RAIDb controller
table 1 table 2 & 3 table ...
table n-1 table n
SQL requests
RAIDb controller
Full DB Full DB Full DB
Full DB Full DB
SQL requests
RAIDb controller
Full DB table x table y
table x & y table z
80. 80
参考:开源c-jdbc概念2
RAIDb
RAIDb levels composition
RAIDb-1-0
no limit to the composition
deepness
C-JDBC
overview
Middleware implementing RAIDb
100% Java implementation
open source (LGPL)
Two components
generic JDBC driver (C-JDBC
driver)
C-JDBC Controller
Read-one, Write all approach
provides eager (strong)
consistency
Supports heterogeneous databases
【异构DB】
RAIDb-0 controller
table w table x & y
SQL requests
RAIDb-1 controller
table z
RAIDb-0 controller
table w table y
RAIDb-0 controller
table x table y
table z
table x & z
table w
81. 81
参考:开源HA-JDBC
特性
支持任何通过JDBC的数据库访问。
高可用性/容错
其集群可关闭某个节点而不破坏一个的事务。
允许热激活或关闭某数据库节点,而不丢失服务。
运行时加减数据库节点的能力。
能被配置为自动失败激活数据库节点
通过分布式各个节点提高并发的读性能。
完全支持JDBC 3.0 and 4.0功能集。
利用数据库无关的策略同步一个失败的数据库节点
通过暴露JMX管理接口来管理数据库和集群。
使用LGPL开源协议。
依赖库
JGroups - 可靠的广播通信框架
Quartz - enterprise job scheduler
JiBX - an XML binding framework
SLF4J
参考:
http://wutaoo.javaeye.com/blog/146982 介绍(图)
http://ha-jdbc.sourceforge.net/faq.html#faq-
N1010F How does HA-JDBC compare to Sequoia?
82. 82
参考:开源HadoopDFS
Hadoop
HDFS具有高容错性。
HDFS适合大数据集应用,并且提供了对数
据读写的高吞吐率。
HDFS是一个master/slave的结构
在master上只运行一个Namenode
在每个slave上运行一个Datanode
HDFS支持传统层次文件组织结构。
Namenode管理着整个分布式文件系统。
HDFS采用三副本策略。
一个放在本节点上,
一个放在同一机架中的另一个节点上,
一个副本放在另一个不同的机架中的一个
节点上。
参考:
http://www.cnblogs.com/wayne1017
/archive/2007/03/18/668768.html
Hadoop学习笔记
http://www.blogjava.net/killme2008/
archive/2008/06/05/206043.html
HadoopDFS架构和设计要点
83. 83
参考:开源DataNucleus架构
参考:
http://code.google.com/intl/zh-CN/appengine/docs/java/overview.html GAE for Java
http://www.datanucleus.org/products/accessplatform/architecture.html DataNucleus
85. 85
参考:开源Amoeba
服务端方案1(自定义服务接口)
数据中心也是一种服务。
通过DAL服务访问数据,无需jdbc。
实现类似以前DbServer之类的服务。
服务端方案2(基于JDBC通信接口)
http://amoeba.meidusa.com/ Amoeba
Amoeba for MySQL【仅MySQL,性能较高】
Amoeba for Aladdin【任意DB,性能稍差】
参考:
http://www.infoq.com/cn/articles/inter
view-chensiru-amoeba 专访开源项目
Amoeba架构师陈思儒
http://hi.baidu.com/zeorliu/blog/item/
e0f315d12a15dfd5572c84be.html 试用
log4jdbc监控SQL的执行情况(zt)+开源项
目Amoeba
86. 86
参考:手机之家DAL
http://www.javaeye.com/wiki/interview/1931-data-access-
layer 采访分布式数据访问层(Data Access Layer)
作者许超前
http://www.longker.org/ 许超前博客