#
一、问题:铁路的售票系统的数据量是海量吗?
不是。因为数据量不大,真不大。
每一个车次与车次间是独立的,每车次不超过2000张票,一天发车不超过50万车次;
以预售期15天来讲,15*0.1亿张不超过1.5亿笔的热线数据,称不上海量数据的。
再加上可以按线路分库,更是不到千万级的单表容量。已经发车完成的进入归档分析。
即数据库按路线使用不同的服务器,不同的车次放在不同的表中。并发量锁真不大。
当然,如果不分库分表,再加上不归档处理,铁路的售票系统的数据量看起来是海量的;
关键是这海量的数据没有意义。
二、如何分库分表?
2.1 分库,考虑数据间没有直接关系和服务器如何部署
铁路的售票系统为例来说,按路线分库,再按车次分表是合理的。
设路线有1万条,按每1000条需要两台服务器(一台热机沉余),不到20台服务器
如果使用SAN存储,则使用SAN作为存储,本机作为热机沉余,只需要10台。
当然使用mySQL这种经济型数据库,服务器需要更多来防灾;
即可以采用双写或多写的方式来保证数据的绝对安全。
2.2分表,考虑数据间不存在重叠,即数据满足二分原则
铁路的售票系统的任意两个车次是没有关系的,所以可以分表。
电信的某个用户的通话和其它用户的通话记录,也是没有关系,所以可以分表处理
(实际上电信的系统,分库分表后也是不大的,难在后台的计费、结算等规则)
三、数据库访问接口
1. 元数据:如何识别到当前要处理的数量在哪张表?
铁路的售票系统会有一个车次管理系统,例2012年2月12日 D3206 车次,
按预先设计的在哪台服务器的哪个库,建哪个表。
2.建立元数据的规则:即具体如何分库分表的规则
这个就是数据库的访问接口。
3.数据库访问接口的透明程度
即哪个层知道哪些元数据信息。
例,是否让窗口售票的客户端来解析元数据的规则然后缓存,还是通过中间件来解析缓存的
具体各层使用怎样透明程度,和业务性质、节点和数据中心的拓扑等有关。
四、历史数据归档与分析
1.使用分库分表后,数据需要归档,分析处理的程序变得复杂,但使联机交易变得简单
2.分析:要注意是针对热线数据分析、归档数据分析、混合分析有关,
通过分库分表和归档,更方便使用分布式的统计方案。
具体可以参考,淘宝的开放平台架构师写的文章:
结论:分库分表跟不分库分表,整个架构是完全不一样的。
像铁票的售票系统、淘宝、电信、银行等,绝对要采用分库分表的数据存储方案,
来解决数据量的增长而不影响性能的问题。
像淘宝等互联网应用还要解决带宽即CDN问题。
数据源文件:my-oracle-ds.xml
<datasources>
<local-tx-datasource>
<jndi-name>jdbc/my-local</jndi-name>
<connection-url>
jdbc:oracle:thin:@10.5.7.30:1521:orcl
</connection-url>
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
<security-domain>EncryptedOracleDbRealm</security-domain>
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter
</exception-sorter-class-name>
<metadata>
<type-mapping>Oracle10g</type-mapping>
</metadata>
<depends>
jboss.security:service=JaasSecurityDomain,domain=ServerMasterPassword
</depends>
</local-tx-datasource>
<mbean code="org.jboss.security.plugins.JaasSecurityDomain"
name="jboss.security:service=JaasSecurityDomain,domain=ServerMasterPassword">
<constructor>
<arg type="java.lang.String" value="ServerMasterPassword"></arg>
</constructor>
<!-- The opaque master password file used to decrypt the encrypted
database password key -->
<attribute name="KeyStorePass">
{CLASS}org.jboss.security.plugins.FilePassword:${jboss.server.home.dir}/conf/server.password
</attribute>
<attribute name="Salt">abcdefgh</attribute>
<attribute name="IterationCount">13</attribute>
</mbean>
</datasources>
在jboss4.3/jboss-as/server/default/conf/login-config.xml中增加节点:
<application-policy name="EncryptedOracleDbRealm">
<authentication>
<login-module
code="org.jboss.resource.security.JaasSecurityDomainIdentityLoginModule"
flag="required">
<module-option name="username">username</module-option>
<module-option name="password">
3wW33nIpavHK4pd3qoNTbA
</module-option>
<module-option name="managedConnectionFactoryName">
jboss.jca:service=LocalTxCM,name=jdbc/my-local
</module-option>
<module-option name="jaasSecurityDomain">
jboss.security:service=JaasSecurityDomain,domain=ServerMasterPassword
</module-option>
</login-module>
</authentication>
</application-policy>
以上的password由下面命令得出:
E:\JBOSS\jboss4.3\jboss-as\server\default\lib>java -cp jbosssx.jar
org.jboss.security.plugins.PBEUtils abcdefgh 13 master mypassowrd
Encoded password: 2mqrIBSpp8JVWFAqCBklhf
生成server.password文件:
E:\JBOSS\jboss4.3\jboss-as\server\default\lib>java -cp jbosssx.jar
org.jboss.security.plugins.FilePassword abcdefgh 13 master server.password
产生后拷贝到:${jboss.server.home.dir}/conf中。
非对称型加密非常适合多个客户端和服务器之间的秘密通讯,客户端使用同一个公钥将明文加密,而这个公钥不能逆向的解密,密文发送到服务器后有服务器端用私钥解密,这样就做到了明文的加密传送。
非对称型加密也有它先天的缺点,加密、解密速度慢制约了它的发挥,如果你有大量的文字需要加密传送,建议你通过非对称型加密来把对称型‘密钥’分发到客户端,及时更新对称型‘密钥’。
package com.paul.module.common.util;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import javax.crypto.Cipher;
public class RSASecurityUtil2 {
/** 指定加密算法为RSA */
private static final String ALGORITHM = "RSA";
/** 密钥长度,用来初始化 */
private static final int KEYSIZE = 1024;
/** 指定公钥存放文件 */
private static String PUBLIC_KEY_FILE = "PublicKey";
/** 指定私钥存放文件 */
private static String PRIVATE_KEY_FILE = "PrivateKey";
/**
* 生成密钥对
* @throws Exception
*/
private static void generateKeyPair() throws Exception {
// /** RSA算法要求有一个可信任的随机数源 */
// SecureRandom secureRandom = new SecureRandom();
/** 为RSA算法创建一个KeyPairGenerator对象 */
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
/** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
// keyPairGenerator.initialize(KEYSIZE, secureRandom);
keyPairGenerator.initialize(KEYSIZE);
/** 生成密匙对 */
KeyPair keyPair = keyPairGenerator.generateKeyPair();
/** 得到公钥 */
Key publicKey = keyPair.getPublic();
/** 得到私钥 */
Key privateKey = keyPair.getPrivate();
ObjectOutputStream oos1 = null;
ObjectOutputStream oos2 = null;
try {
/** 用对象流将生成的密钥写入文件 */
oos1 = new ObjectOutputStream(new FileOutputStream(PUBLIC_KEY_FILE));
oos2 = new ObjectOutputStream(new FileOutputStream(PRIVATE_KEY_FILE));
oos1.writeObject(publicKey);
oos2.writeObject(privateKey);
} catch (Exception e) {
throw e;
}
finally{
/** 清空缓存,关闭文件输出流 */
oos1.close();
oos2.close();
}
}
/**
* 加密方法
* @param source 源数据
* @return
* @throws Exception
*/
public static String encrypt(String source) throws Exception {
generateKeyPair();
Key publicKey;
ObjectInputStream ois = null;
try {
/** 将文件中的公钥对象读出 */
ois = new ObjectInputStream(new FileInputStream(
PUBLIC_KEY_FILE));
publicKey = (Key) ois.readObject();
} catch (Exception e) {
throw e;
}
finally{
ois.close();
}
/** 得到Cipher对象来实现对源数据的RSA加密 */
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] b = source.getBytes();
/** 执行加密操作 */
byte[] b1 = cipher.doFinal(b);
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(b1);
}
/**
* 解密算法
* @param cryptograph 密文
* @return
* @throws Exception
*/
public static String decrypt(String cryptograph) throws Exception {
Key privateKey;
ObjectInputStream ois = null;
try {
/** 将文件中的私钥对象读出 */
ois = new ObjectInputStream(new FileInputStream(
PRIVATE_KEY_FILE));
privateKey = (Key) ois.readObject();
} catch (Exception e) {
throw e;
}
finally{
ois.close();
}
/** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
BASE64Decoder decoder = new BASE64Decoder();
byte[] b1 = decoder.decodeBuffer(cryptograph);
/** 执行解密操作 */
byte[] b = cipher.doFinal(b1);
return new String(b);
}
public static void main(String[] args) throws Exception {
String source = "恭喜发财!";// 要加密的字符串
System.out.println("准备用公钥加密的字符串为:" + source);
String cryptograph = encrypt(source);// 生成的密文
System.out.print("用公钥加密后的结果为:" + cryptograph);
System.out.println();
String target = decrypt(cryptograph);// 解密密文
System.out.println("用私钥解密后的字符串为:" + target);
System.out.println();
}
}
http://blog.sina.com.cn/s/blog_43b03c72010080t2.html
http://topic.csdn.net/t/20040510/14/3049788.html
http://yuanliyin.iteye.com/blog/853334
2011年10月31日,腾讯即通平台部高级总监庄泗华在北京航空航天大学的演讲《1亿在线背后的技术挑战》让许多听众变成了庄老师的粉丝。
腾讯大讲堂放出庄泗华的演讲视频,转载请注明来自
腾讯大讲堂。
演讲PPT下载:
http://djt.open.qq.com/portal.php?mod=view&aid=19视频:1.4亿在线背后的故事第1部分:从十万级到百万级在线
第2部分:千万级在线
第3部分:亿级在线
第4部分:总结
又到新年了,日历又要从2011年翻到2012年了,这使我有太多的感慨,进而勾起了对太大往事的回忆。过去的10年,毫无疑问是中国软件业发展最快的10年。当我们刚刚毕业的时候,还在使用VB、PB开发一些简单的数据库应用,而现在却几乎看不到它们的踪影,换来的是诸如J2EE和.NET这样的大型web应用。而这期间,RUP、XP、敏捷开发、持续集成••••••一个接一个的新概念层出不穷,令人眼花缭乱。现在想来,恍如隔世。
但更令我印象深刻而难以忘怀的,是我亲自经历的、亲眼目睹的、道听途说的一个又一个的软件项目,它们有的获得了成功,但更多的是令人沮丧的失败。套用一下大文豪托尔斯泰体:幸福的家庭都是一样的,不幸的家庭却各有各的不幸;幸福的软件项目都是一样的,不幸的软件项目却各有各的不幸;或者说,成功的软件项目都是一样的,失败的项目却各有各的问题。我常常在想,我们的项目开发到底怎么了,进而把它们一个一个的剥开来深入分析,竟然触目惊心。它们有的是需求的问题,有的是客户关系的问题,还有设计的问题、技术的问题、时间管理的问题、人员培养的问题••••••但归根到底更多的还是需求的问题。需求分析既是一份体力活儿,更是一份技术活儿,它既是人际交往的艺术,又是逻辑分析与严密思考的产物。正是我们在需求分析过程存在的巨大隐患,最终导致了那么多项目的失败。也许你认为我在危言耸听,好吧,我来举几个典型事例分析分析吧。
我的第一个故事来自大名鼎鼎的东软。我在2005年接一个项目的时候,听说这个项目之前是东软做的。当时东软在做这个项目的时候,整个过程经历了10多次结构性的大变更,局部性的调整更是不计其数。据说某天早上,客户对某个功能不满意,他们不得不对几百处程序进行修改。之后客户对修改的内容还是不满意,又不得不将几百处修改重新改回来。最后这个项目导致的结果是,整个这个项目组的所有成员都离开了东软,并似乎从此不愿涉足软件开发领域。多么惨痛的教训啊!我常常听到网友抱怨客户总是对需求改来改去,但客户对需求改来改去的真正原因是什么呢?当我们对客户的需求没有真正理解清楚时,我们做出来的东西客户必然不满意。客户只知道他不满意,但怎样才能使他满意呢?他不知道,于是就在一点儿一点儿试,于是这种反复变更就这样发生了。如果我们明白了这一点,深入地去理解客户的业务,进而想到客户的心坎儿上去,最后做出来的东西必然是客户满意的。记住,当客户提出业务变更的时候,我们一定不能被客户牵着走,客户说啥就是啥。我们要从业务角度深入的去分析,他为什么提出变更,提得合不合理,我有没有更合理的方案满足这个需求。当我们提出更加合理的方案时,客户是乐于接受的,变更也变得可控了。
第二个故事来自我自己的项目,一个早期的项目。在这个项目中,客户扔给了我们很多他们目前正在使用的统计报表,要我们按照报表的格式做出来。这些报表都是手工报表,许多格式既不规范,又很难于被计算机实现。这些报表令我耗费了不少闹细胞,直到最终项目失败都没法完成。这件事留给我的深刻教训是,不能客户怎么说软件就怎么做。客户提出的原始需求往往是不考虑技术实现,基于非计算机管理的操作模式提出来的。他们提出的很多需求常常比较理想而不切实际,毕竟人家是非技术的。但我们作为技术人员,需求分析必须实事求是地、基于技术可以实现的角度去考虑。那种“有条件要上,没有条件创造条件”的鲁莽行事,结果必然是悲惨的。所以我们必须要基于技术实现去引导客户的需求。同时,计算机信息化管理就是一次改革,对以往手工管理模式的改革。如果我们上了信息化管理系统,采用的管理模式却依然是过去的手工模式,新系统的优势从何而来呢?因此,我们做需求就应当首先理解现有的管理模式,然后站在信息化管理的角度去审视他们的管理模式是否合理,最后一步一步地去引导他们按照更加合理的方式去操作与管理。
2007年,我参与了一个集团信息化建设的项目。这个项目中的客户是一个庞大的群体,他们分别扮演着各种角色。从机构层次划分,有集团领导、二级机构人员、三级机构人员;从职能角色划分,有高层领导、财务人员、生产管理员、采购人员、销售人员,等等。在这样一个复杂场景中,不同人员对这个项目的需求是各自不同的。非常遗憾的是,我们在进行需求分析的时候没有认真分析清楚所有类型人员的需求。在进行需求调研的时候,总是集团领导带领我们到基层单位,然后基层单位将各方面的人员叫来开大会。这样的大会,各类型的人员七嘴八舌各说各自的需求,还有很多基层人员在大会上因为羞涩根本就没有提出自己的需求。这样经过数次开会,需求调研就草草收场。我们拿着一个不充分的需求分析结果就开始项目开发,最终的结果可想而知。直到项目上线以后,我们才发现许多更加细节的业务需求都没能分析到,系统根本没法运行,不得不宣告失败。一个软件项目的需求调研首先必须要进行角色分析,然后对不同的角色分别进行调研。需求调研的最初需要召开项目动员大会,这是十分必要的。但真正要完成需求分析,应该是一个一个的小会,1~3个业务专家,只讨论某个领域的业务需求,并且很多问题都不是能一蹴而就完成的,我们必须与专家建立联系,反复沟通后完成。需求分析必须遵从的是一定的科学方法,而不是盲目的大上快上。
我的最后一个故事可能典型到几乎每个人都曾经遇到过。我们的项目从需求分析到设计、开发、测试都十分顺利。但到了项目进行的后期,快到达最后期限时,我们将我们的开发成果提交给客户看,客户却对开发不满意,提出了一大堆修改,而且这些修改工作量还不小。怎么办呢?加班、赶工,测试时间被最大限度压缩。最后项目倒是如期上线了,但大家疲惫不堪,并且上线以后才发现许多的BUG。需求分析不是一蹴而就的,它应当贯穿整个开发周期,不断的分析确认的过程。以上这个事例,如果我们提早将开发成果给客户看,提早解决问题,后面的情况就将不再发生。这就是敏捷开发倡导的需求反馈。敏捷开发认为,需求分析阶段不可能解决所有的需求问题,因此在设计、开发、测试,直到最终交付客户,这整个过程都应当不停地用开发的成果与客户交流,及时获得反馈。只有这样才能及时纠正需求理解的偏差,保证项目的成功。
以上的故事各有各自的不幸,各自都在不同的开发环节出现了问题。但经过深入的分析,各自的问题最终都归结为需求分析出现了问题。为了使我们今后的软件项目不会重蹈覆辙,似乎真的有必要讨论一下我们应该怎样做需求分析。
昨天,2012年1月11日,网友 @fenng 写了一篇文章,批评铁道部火车票网上订购系统,http://www.12306.cn [1]。同时在新浪发了一条言辞激烈的微博,“去你的‘海量事务高速处理系统’”,引起热议 [2]。
春节将到,大家买不着车票,赶不上大年三十与家人团聚,急切心情可以理解。但是拍桌子开骂,只能宣泄情绪,解决不了实际问题。
开发一套订票系统并不难,难在应对春运期间,日均 10 亿级别的洪峰流量。日均 10 亿级别的洪峰请求,在中国这个人口全球第一大国,不算稀罕,不仅火车票订票系统会遇到,而且电子商务在促销时,也会遇到,社交网站遇到新闻热点时,也会遇到。
所以,能够在中国成功运行的云计算系统,推广到全球,一定也能成功。
但是在美国成功运行的云计算系统,移植到中国,却不一定成功。
如果我们能够设计建造一套,稳定而高效的铁路订票系统,不仅解决了中国老百姓的实际问题,而且在全球高科技业界,也是一大亮点,而且是贴着中国标签的前沿科技的亮点。
于是软件工程师们献计献策,讨论如何改进 12306 网上购票系统
[3]。其中比较有代表性的,有两篇 [4,5]。
网友的评论中,有观点认为,[4] 利用“虚拟排队”的手段,将过程拉长负载降低,是网游的设计思路。而 [5] 利用缓存技术,一层层地降低系统负荷, 是互联网的设计思路。
个人认为,[4] 和 [5] 并不是相互排斥的两种路线,两者着重解决的问题不同,不妨结合起来使用,取长补短。
下面介绍一下我们的设计草案,追求实用,摈弃花哨。抛砖引玉,欢迎拍砖。
图一。12306.cn 网站系统架构设想图。
Courtesy
http://i879.photobucket.com/albums/ab351/kan_deng/12306.png
图一是系统架构图,典型的“展现层”/ “业务层”/ “数据层”的三段论。
用户接入有两类,一个是运行在电脑里的浏览器,例如 IE,另一个是手机。
无论用户用电脑浏览器,还是手机访问 http://www.12306.cn 网站,用户请求首先被网站的负载均衡器接收。负载均衡器连接着一群门户服务器,根据各个门户服务器的负载轻重,负载均衡器把用户请求,转发到某一相对清闲的门户服务器。
门户服务器的任务类似于收发室老头儿,它只读每个用户请求的前几个 bytes,目的是确定用户请求的类型,然后把请求投放到相应类型的队列中去。门户服务器的处理逻辑非常简单,这样做的好处,是让它能够快速处理大批量用户请求。
根据 [5] 的分析,12306 处理的用户请求,大致分为三类,
1. 查询。用户订票前,查询车次以及余票。用户下订单后,查询是否已经订上票。
2. 订票,包括确定车次和票数,然后付款。用户付款时,需要在网银等网站上操作。
3. 第一次访问的用户,需要登记,包括姓名和信用卡等信息。
三类请求的业务处理过程,被分为两个阶段,
1. 运行于缓存中的任务队列。设置队列的目的,是防止处理过程耗时太长,导致大量用户请求拥塞于门户服务器,导致系统瘫痪。
2. 业务处理处理器,对于每一类业务,分别有一群业务服务器。不同业务的处理流程,各不相同。
图二。12306.cn 网站查询和订票业务流程设想图。
Courtesy
http://i879.photobucket.com/albums/ab351/kan_deng/12306-1.png
图二描述了查询和订票,两个业务的处理流程。登记业务流程从略。
查询的业务流程,参见图二上半部,分五步。
这里有两个问题需要注意,
1. 用户发出请求后,经过短暂的等待时间,能够迅速看到结果。平均等待时间不能超过 1 秒。
2. 影响整个查询速度的关键,是“查询服务器”的设计。
查询任务可以进一步细化,大致分成三种。
1. 查询车次和时间表,这是静态内容,很少与数据库交互,数据量也不大,可以缓存在内存中。
车次和时间表的数据结构,不妨采用 Key-Value 的方式,开发简单,使用效率高。Key-Value 的具体实现有很多产品,[5] 建议使用 Redis。
这些是技术细节,不妨通过对比实验,针对火车票订票系统的实际流量,以及峰值波动,确定哪一个产品最合适。
2. 查询某一班次的剩余车票,这需要调用数据库中不断更新的数据。
[5] 建议把剩余车票只分为两种,“有”或“无”,这样减少调用访问数据库的次数,降低数据库的压力。但是这样做,不一定能够满足用户的需求,说不定会招致网友的批评讥讽。
[4] 建议在订票队列中,增加测算订票队列长度的功能,根据订票队列长度以及队列中每个请求的购票数量,可以计算出每个车次的剩余座位。如果 12306.cn 网站只有一个后台系统,这个办法行之有效。
但是假如 12306.cn 网站采用分布式结构,每个铁路分局设有子系统,分别管理各个铁路分局辖区内的各个车次。在分布式系统下,这个办法面临任务转发的麻烦。不仅开发工作量大,而且会延长查询流程处理时间,导致用户长久等待。
3. 已经下单的用户,查询是否已经成功地订上票。
每个用户通常只关心自己订的票。如果把每个用户订购的车票的所有内容,都缓存在内存里,不仅非常耗用内存空间,内存空间使用效率低下,更严重的问题是,访问数据库过于频繁,数据量大,增大数据库的压力。
解决上述分布式同步,以及数据库压力的两个问题,不妨从订票的流程设计和数据结构设计入手。
假如有个北京用户在网上订购了一套联票,途经北京铁路局和郑州铁路局辖区的两个车次。
用户从北京上网,由北京铁路局的子系统,处理他的请求。
北京铁路局的订票服务器把他的请求一分为二,北京铁路局的车次的订票,在北京子系统完成,郑州铁路局的车次在郑州子系统完成。
每个子系统处理四种 Key-Value 数据组。
1. 用户ID:多个 (订单ID)s。
2. 订单ID:多个 (订票结果ID)s。
3. 订票结果ID: 一个 (用户ID,车次ID)。
4. 车次ID:一个(日期),多个 (座位,用户ID)。
北京订票服务器完成订票后,把上述四个数据组,写入北京子系统的数据库,同时缓存进北京的查询服务器,参见图二下半部第6步和第7步。
郑州订票服务器完成订票后,把上述四个数据组,写入郑州子系统的数据库,同时缓存进北京的查询服务器,而不是郑州的服务器。
让订票服务器把订票数据,同时写入数据库和查询服务器的缓存,目的是让数据库永久保留订票记录,而让大多数查询,只访问缓存,降低数据库的压力。
北京用户的订票数据,只缓存在北京的查询服务器,不跨域缓存,从而降低缓存空间的占用,和同步的麻烦。这样做,有个前提假设,查询用户与订票用户,基本上是同一个人,而且从同一个城市上网。
但是这里有个缺陷,某用户在北京上网订了票。过了几天,他在北京上网,输入用户ID和密码后,就会看到他订购的所有车票。可是又过了几天,他去了郑州,从郑州上网,同样输入用户ID和密码,却看不到他订购的所有车票。
解决这个缺陷的办法并不麻烦,在用户查询订票信息时,需要注明订票地点,系统根据订票地点,把查询请求转发到相应区域的子系统。
另外,每次订票的时候,网站会给他的手机发送短信,提供订票信息,参见图二下半部第8步和第9步。
以上是一个初步设计,还有不少细节需要完善,例如防火墙如何布置等等。
这个设计不仅适用于单一的集中式部署,而且也适合分布式部署。
或许有读者会问,为什么没有用到云计算?其实上述架构设计,为将来向云计算演变,留下了伏笔。
在上述架构设计中,我们假定每个环节需要用多少服务器,需要多大容量的数据库,预先都已经规划好。
但是假如事先的规划,低于实际承受的流量和数据量,那么系统就会崩溃。
所以,事先的规划,只能以峰值为基准设立。
但是峰值将会是多少?
事先难以确定。即便能够确定峰值,然后以峰值为基准,规划系统的能力,那么春运过后,就会有大量资源冗余,造成资源浪费?
如何既能抗洪,又不造成资源浪费?解决方案是云计算,而且目前看来,除了云计算,没有别的办法。
Reference,
[1] 海量事务高速处理系统。
http://www.douban.com/note/195179318/
[2] 去你*的‘海量事务高速处理系统’。
http://weibo.com/1577826897/y0jGYcZfW
[3] 火车订票系统的设想。
http://weibo.com/1570303725/y0l9Y2mwE
[4] 铁路订票系统的简单设计。
http://blog.codingnow.com/2012/01/ticket_queue.html
[5] 铁路订票网站个人的设计浅见。
http://hi.baidu.com/caoz/blog/item/f4f1d7caee09b558f21fe780.html
题图来自
Designyoutrust
商譽管理─看見危機,穿透危機,決勝於未戰之前
全面品質管理, 2/e
曼陀羅九宮格思考術─達成目標成功圓夢
六個標準差的品質管制─ 60 小時學會實務應用的手冊
在失業中創業:被炒魷魚又怎樣!
領導未來的 CEO-12 堂 EMBA 名師的管理必修課
早上 3 分鐘變身管理大師, 2/e
整合行銷傳播策略與企劃
Photoshop 視訊課程合集 (21)
DTP 視訊課程合集 (7)
3ds Max 視訊課程合集(22)
Photoshop 視訊課程合集 (22)
Photoshop 視訊課程合集 (21)
巴菲特 & 索羅斯聯手出擊─不看會後悔的投資策略
揭開肥貓經理人薪酬的黑盒子
圖解第一次看懂經濟指標就上手
把鳥事變好事的神奇手帳術
用 Please 換 Yes 的職場成功學
Pose 這樣擺最 OK ─人像攝影與場景的完美結合
寫給 SA 的 UML / UseCase 實務手冊
Thinking in Java 中文版 (Thinking in Java, 4/e)
jQuery 實戰手冊 (jQuery in Action, 2/e)
讓人不自覺說 YES 的交涉力
翻譯大師教你寫出好句子
日本超級店長首次公開讓客戶「好想再見到妳」的心機說話術
iPhone 基礎程式設計
圖解 NLP 惡魔說話術─實例篇
3ds Max 視訊課程合集 1
寫給經理人的專案管理發達之路-使用 Project 2010
軟體測試專案實作-技術、流程與管理
一、环境
数据库服务器:Oracle 9i2
操作系统:Windows XP SP2
JBoss版本:4.2.2
JDK:Sun 1.5.0.13
网络配置:同一机器的一个网卡上绑定两个ip地址192.168.1.18和192.168.1.147
二、配置
1.配置消息和事务日志持久保存的数据源,从JBoss安装位置的docs\examples\jca目录下拷贝到server\all\deploy目录下,并修改其中的连接配置,这里使用OracleDS作为持久保存的数据源。注意:别忘了把Oracle的jdbc驱动程序拷贝到server\all\lib目录下。
2.修改DestinationManager配置,删除server\all\deploy-hasingleton\jms目录下的hsqldb-jdbc2-service.xml文件,拷贝docs\examples\jms目录下的oracle-jdbc2-service.xml到server\all\deploy-hasingleton目录下,使用OracleDS作为DestinationManager的数据源。
3. 修改StateManager配置,将其中的数据源配置由
jboss.jca:service=DataSourceBinding,name=DefaultDS 改
jboss.jca:service=DataSourceBinding,name=OracleDS 4. 配置测试的Topic,在server\all\deploy-hasingleton\jms目录下新建一个名为jbossweek-jms-service.xml文件,
<mbean code="org.jboss.mq.server.jmx.Topic" name="jboss.mq.destination:service=Topic,name=jbossweekTopic">
<depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
</mbean> 5. 创建node1的服务器配置,将server\all目录复制一份改名为node1
6. 配置完成。
三、验证
1. 分别以run –c all –b192.168.1.17和run –c node1–b192.168.1.148先后启动all和node1配置。此时192.168.1.17为主节点,浏览http://192.168.1.17:8080/jmx-console/。打开JNDIView可以看到jbossweekTopic的JNDI名称。此时192.168.1.17为主节点,浏览http://192.168.1.148:8080/jmx-console/。打开JNDIView就会发现没有jbossweekTopic的JNDI名称。
2. 关闭192.168.1.17上的all服务器,此时在192.168.1.148上的node服务器的控制台上会出现如下信息:
13:11:13,921 INFO [TreeCache] viewAccepted(): [192.168.1.17:2292|2] [192.168.1.148:2327]
13:11:14,015 INFO [TreeCache] viewAccepted(): [192.168.1.17:2288|2] [192.168.1.148:2321]
13:11:14,218 INFO [DefaultPartition] New cluster view for partition DefaultPartition (id: 2, delta: -1) : [192.168.1.148:1099]
13:11:14,218 INFO [DefaultPartition] I am (192.168.1.148:1099) received members hipChanged event: 13:11:14,218 INFO [DefaultPartition] Dead members: 1 ([192.168.1.17:1099])
13:11:14,218 INFO [DefaultPartition] New Members : 0 ([])
13:11:14,218 INFO [DefaultPartition] All Members : 1 ([192.168.1.148:1099])
13:11:14,453 INFO [TreeCache] viewAccepted(): [192.168.1.17:2279|2] [192.168.1.148:2306]
13:11:16,218 INFO [TomcatDeployer] deploy, ctxPath=/jbossmq-httpil, warUrl=.../deploy-hasingleton/jms/jbossmq-httpil.sar/jbossmq-httpil.war/
13:11:17,406 INFO [jbossweekTopic] Bound to JNDI name: topic/jbossweekTopic
13:11:17,453 INFO [A] Bound to JNDI name: queue/A
13:11:17,453 INFO [B] Bound to JNDI name: queue/B
13:11:17,468 INFO [C] Bound to JNDI name: queue/C
13:11:17,468 INFO [D] Bound to JNDI name: queue/D
13:11:17,468 INFO [ex] Bound to JNDI name: queue/ex
13:11:17,484 INFO [testTopic] Bound to JNDI name: topic/testTopic
13:11:17,500 INFO [securedTopic] Bound to JNDI name: topic/securedTopic
13:11:17,500 INFO [testDurableTopic] Bound to JNDI name: topic/testDurableTopic
13:11:17,500 INFO [testQueue] Bound to JNDI name: queue/testQueue
13:11:17,562 INFO [UILServerILService] JBossMQ UIL service available at : /192.168.1.148:8093 13:11:17,609 INFO [DLQ] Bound to JNDI name: queue/DLQ
3. JMS集群的主节点自动切换到192.168.1.148上的node1节点,浏览http://192.168.1.148:8080/jmx-console/。打开JNDIView就会找到jbossweekTopic的JNDI名称。
http://linliangyi2007.iteye.com/blog/316997http://docs.redhat.com/docs/zh-CN/JBoss_Enterprise_Application_Platform/5/html/JBoss_Messaging_User_Guide/index.html
找到你运行的instance的conf/jboss-service.xml, eg: $JBOSS_HOME/server/default/conf/jboss-service.xml
找到
mbean服务中,名字为 ServiceBindingManager 的,里面有个叫做ports-01的内容,打开这个注释,就可以了。
如果你要运行多个,那么就需要有多个ServiceBindingManager ports-02,这是第三个,ports-03这是地四个,
这个文件,对应${jboss.home.url}/docs/examples/binding-manager/sample-bindings.xml里面的ports-01部分,ports-02部分,只不过需要在这里启用,启动的同时,$JBOSS_HOME/server/default/deploy/jboss-web.deployer/server.xml里面的就不起作用了。