分类 数据库 下的文章

关于集群和分布式部署

<p>EJB的RPC是同步调用可实现分布式计算,是SessionBean和EntityBean用的,而JMS是异步调用。RMI,和webservice也可以实现分布式计算。</p><div style="page-break-after: always;"><span style="display: none;"><!--more-->& nbsp ;</span></div><p>
举 例说明,假设我们的系统有三个EJB组件:人事、财务、销售,都是开放远程接口,有A、B两台应用服务器,EJB分布式的概念就是可以在 A上部署人事、财务的EJB包,在B上部署销售的EJB包,假如有一天用户发现负载不太均衡,就可能调整为在A上部署财务的EJB包,在B上部署人事、销 售的EJB包,而程序不必修改。</p><p>而应用服务器集群是这样的,在A、B上都部署全部EJB包,当然还需要在服务器上进行一些集群的设置,这样一来,负载均衡就完全交给应用服务器来管理了。</p><p>至于集群是否足以替代分布式部署(注意:不是分布式计算),正是大家争论的焦点。</p><p>EJB解决的是分布式计算问题,不是群集问题,就算你用EJB,你照样无法做到缓存同步,Session同步,分布式和群集是两个不同的概念</p><p>主 要看具体是什么集群。现在有些用F5之类的负载均衡器的应用也被叫做集群,还有双机热备(部分人也把它叫集群,其实只有一台机器在工作,另一台是 备份机,平时不参与业务,只有主机不能提供服务的时候,备份机采工作)。还有用一些JVM集群缓存软件构件的集群。这些集群每台机器一般都需要单独部署。 因为使用F5负载均衡和双机热备的,其实是一台台单机。JVM缓存我没有用过,不太清楚。不过估计应用服务器自己并不知道还有其他机器和自己同步。</p><p>标准的JavaEE集群一般分两种,war集群及EJB集群。war因为考虑到Session复制的问题,一般不推荐做大集群。不过用来做2-3台的廉价入门集群还是可以的。
EJB 集群一般在上面部署的都是EJB组件。不同厂商用不同的办法来保证有状态SessionBean的集群复制。比如Weblogic采用双机结对、Sun使 用特殊的数据库同步。一般有一台专门的代理管理服务器负责对整个集群的管理,所以在这台管理器上进行部署就可以了。
应用在集群上面跑和在单机 上 面跑是完全不同的两个概念。很多单机上可以使用的框架和设计模式在集群环境下是绝对不能使用的。比如单例模式。集群环境下根本无法再集群中只有一个单例, 每个服务器都会有自己的单例。还有就是Spring,Spring目前是不能用于标准的JavaEE集群环境下的(因为spring里应用了很多 singleton模式)。当然,有人推出了Spring的集群框架,不过我不太清楚是否好用。AOP配置集群的话,估计会很复杂。</p><p>
别人说的,没实趼过...</p><p>
标准的JavaEE集群,一般情况下是这样的。
入口是一个负载均衡器(有时候也用apache之类的),然后是若干台web服务器(如Tomcat),再后边是EJB集群。最后是数据库。
这是JavaEE集群模型的标准构造。JavaEE集群的核心是EJB集群。但是如果应用没有达到足够大的规模,且设计不好的话,会产生很多问题。这也是当初为什么老EJB架构被人诟病的地方。</p><p>单 机应用是中小型项目的主流。我们在中小型项目中一般只用到事务处理,分布式、容灾等功能一般用不上。所以Spring才会发展这么快。但是企业在 发展,当初用Spring开发的程序需要跑集群了,结果发现无法在集群上使用,所以才会出现用AOP方式对Spring添加集群和JVM分布式缓存来进行 集群化的方案。但即使如此,很多单机下可以使用的代码,在集群下可能是根本无法跑的。单例、静态对象等等,在集群模式下会出现各种问题。
所以,现在很多人都只用F5和Apache做分发器,后边跟一大堆互不往来的Tomcat之类的Web服务器。这么做最大的问题是无法使用缓存。因为如果使用缓存,那么其他机器更改了数据库的话,缓存无法刷新而形成脏数据。结果大大拖累了性能。
如果你的应用是中小型低负载应用,那么可以只考虑单机。如果以后要使用集群,可以先用Spring集群(好像是叫Cluster4Spring)和JVM分布式缓存。如果应用大到必须分布式的程度,那么还是更换成EJB架构吧。</p>

- 阅读剩余部分 -

文本流和二进制流

<p>我们在写C程序的时候经常会涉及到对流的操作,比如说从标准输入流读取一串字符串,然后通过标准输出流输出显示在屏幕上,这也就是所谓的IO操作。那么流究竟是什么东西?下面首先对流这个概念做一下解释。</p><p>一. 流(stream)的概念</p><p>计 算机有很多外部设备,比如键盘、鼠标、CD-ROM驱动器、硬盘、网络接口、视频适配器等。这些设备都和IO操作有关系,而每种设备都具有不同的特性和操 作协议。操作系统负责实现微处理器和和这些外设的通信细节,并向应用开发程序员提供更为简单和统一的IO接口,比如Linux操作系统下的 open(),read(),write()等系统调用使我们可以以文件的形式打开并读写一个设备。</p><div style="page-break-after: always;"><span style="display: none;"><!--more-->& nbsp ;</span></div><p>ANSI C进一步对IO的概念进行抽象。就C程序而言,所有的IO操作只是简单地从程序移进或者移出字节,这种字节流便被称为流(stream)。程序员只需要关心创建正确的输出字节数据,以及正确的解释从输入读取的字节数据,特定IO设备的细节对程序员是隐藏的。</p><p>因此流是一个高度抽象的概念,它将数据的输入和输出看作是数据的流入和流出,这样不管是什么IO设备:显示器、键盘还是硬盘,都被视为同一种东西。都可以作为流的源和目的,对它们的操作,就是数据的流入和流出。</p><p>在C语言中流分为两种类型:文本流(text stream)和二进制流(binary stream)。下面分别进行介绍。</p><p>二. 文本流</p><p>文本流是指在流中流动的数据是以字符的形式出现的。流中的每一个字符对应一个字节,用于存放对应的ASCII码值,因此文本流中的数据可以显示和打印出来,都是用户可以读懂的信息。比如数5678在文本流中的存放形式是:</p><p>ASCII码: 00110101 00110110 00110111 00111000
                          ↓     ↓    ↓    ↓
        十进制码: 5     6    7    8</p><p>一共占用4个字节。</p><p>文 本流的有些特性在不同的系统中可能不同。其中之一是文本行的最大长度,标准规定至少允许254个字符。另一个可能的不同是文本行的结束方式。例如,在 MS-DOS系统中,文本文件约定以一个回车符和一个换行符(也叫行反馈符)结尾,不过UNIX系统只使用一个换行符结尾。文本流中不能包含空字符(即 ASCII码中的NULL)。</p><p>三. 二进制流</p><p>二进制流中的字节将完全根据程序编写它们的形式写入到文件或者设备中,而且完全根据它们从文件或者设备读取的形式读入到程序中。它们并未做任何改变,这种类型的流适于非文本数据,但是如果你不希望IO函数修改文本文件的行末字符,也可以把它用于文本文件。</p><p>二进制流中的数据是按照二进制编码的方式来存放文件的。比如数5678的二进制流中的存储形式为:00010110 00101110只占二个字节。二进制数据也可在屏幕上显示, 但其内容无法读懂。</p><p>二进制流比文本流更节省空间,且不用对换行符进行转换,这样可以大大加快流的速度,提高效率,二进制流没有行长度的限制,也可以包含空字符(NULL)。因此,对于含有大量数据信息的数字流,可以采用二进制流的方式;对于含有大量字符信息的流,则采用文本流的方式。</p>

- 阅读剩余部分 -

JSONObject与JSONArray的使用

<p>1.JAR包简介</p><p>要使程序可以运行必须引入JSON-lib包,JSON-lib包同时依赖于以下的JAR包:</p><p>commons-lang.jar
commons-beanutils.jar
commons-collections.jar
commons-logging.jar 
ezmorph.jar
json-lib-2.2.2-jdk15.jar</p><p>2.JSONObject对象使用</p><p>JSON- lib包是一个beans,collections,maps,java arrays 和XML和JSON互相转换的包。在本例中,我们将使用JSONObject类创建JSONObject对象,然后我们打印这些对象的值。为了使用 JSONObject对象,我们要引入"net.sf.json"包。为了给对象添加元素,我们要使用put()方法。</p><div style="page-break-after: always;"><span style="display: none;"><!--more-->& nbsp ;</span></div><p>2.1.实例1</p><p> </p><p>package jsontest; 
 
import net.sf.json.JSONArray; 
import net.sf.json.JSONObject; 
 
public class JSONObjectSample { 
 
    // 创建JSONObject对象 
    private static JSONObject createJSONObject() { 
        JSONObject jsonObject = new JSONObject(); 
        jsonObject.put("username", "huangwuyi"); 
        jsonObject.put("sex", "男"); 
        jsonObject.put("QQ", "413425430"); 
        jsonObject.put("Min.score", new Integer(99)); 
        jsonObject.put("nickname", "梦中心境"); 
        return jsonObject; 
    } 
 
    public static void main(String[] args) { 
        JSONObject jsonObject = JSONObjectSample.createJSONObject();//静待方法,直接通过类名+方法调用 
        // 输出jsonobject对象 
        System.out.println("jsonObject:" + jsonObject); 
 
        // 判读输出对象的类型 
        boolean isArray = jsonObject.isArray(); 
        boolean isEmpty = jsonObject.isEmpty(); 
        boolean isNullObject = jsonObject.isNullObject(); 
        System.out.println("是否为数组:" + isArray + ", 是否为空:" + isEmpty 
                + ", isNullObject:" + isNullObject); 
 
        // 添加属性,在jsonObject后面追加元素。 
        jsonObject.element("address", "福建省厦门市"); 
        System.out.println("添加属性后的对象:" + jsonObject); 
 
        // 返回一个JSONArray对象 
        JSONArray jsonArray = new JSONArray(); 
        jsonArray.add(0, "this is a jsonArray value"); 
        jsonArray.add(1, "another jsonArray value"); 
        jsonObject.element("jsonArray", jsonArray); 
        //在jsonObject后面住家一个jsonArray 
        JSONArray array = jsonObject.getJSONArray("jsonArray"); 
        System.out.println(jsonObject); 
         
         
        System.out.println("返回一个JSONArray对象:" + array); 
        // 添加JSONArray后的值 
        // {"username":"huangwuyi","sex":"男","QQ":"413425430","Min.score":99,"nickname":"梦中心境","address":"福建省厦门市","jsonArray":["this is a jsonArray value","another jsonArray value"]} 
        System.out.println("结果=" + jsonObject); 
 
        // 根据key返回一个字符串 
        String username = jsonObject.getString("username"); 
        System.out.println("username==>" + username); 
 
        // 把字符转换为 JSONObject 
        String temp = jsonObject.toString(); 
        JSONObject object = JSONObject.fromObject(temp); 
        // 转换后根据Key返回值 
        System.out.println("qq=" + object.get("QQ")); 
 
    } 
 
} </p><p>输出结果</p><p>jsonObject:{"username":"huangwuyi","sex":"男","QQ":"413425430","Min.score":99,"nickname":"梦中心境"} 
是否为数组:false, 是否为空:false, isNullObject:false 
添加属性后的对象:{"username":"huangwuyi","sex":"男","QQ":"413425430","Min.score":99,"nickname":"梦中心境","address":"福建省厦门市"} 
{"username":"huangwuyi","sex":"男","QQ":"413425430","Min.score":99,"nickname":"梦中心境","address":"福建省厦门市","jsonArray":["this is a jsonArray value","another jsonArray value"]} 
返回一个JSONArray对象:["this is a jsonArray value","another jsonArray value"] 
结果={"username":"huangwuyi","sex":"男","QQ":"413425430","Min.score":99,"nickname":"梦中心境","address":"福建省厦门市","jsonArray":["this is a jsonArray value","another jsonArray value"]} 
username==>huangwuyi 
qq=413425430 </p><p>2.2.实例</p><p>package jsontest; 
 
import net.sf.json.JSONArray; 
import net.sf.json.JSONObject; 
 
public class JSONTest { 
    public static void main(String args[]) 
    { 
        JSONObject jsonObj0  = new JSONObject(); 
        JSONObject jsonObj  = new JSONObject(); 
        JSONObject jsonObj2  = new JSONObject(); 
        JSONObject jsonObj3  = new JSONObject(); 
        JSONArray jsonArray = new JSONArray(); 
         
        //创建jsonObj0 
        jsonObj0.put("name0", "zhangsan"); 
        jsonObj0.put("sex1", "female"); 
        System.out.println("jsonObj0:"+jsonObj0); 
         
        //创建jsonObj1 
        jsonObj.put("name", "xuwei"); 
        jsonObj.put("sex", "male"); 
        System.out.println("jsonObj:"+jsonObj); 
     
        //创建jsonObj2,包含两个条目,条目内容分别为jsonObj0,jsonObj1 
        jsonObj2.put("item0", jsonObj0); 
        jsonObj2.put("item1", jsonObj); 
        System.out.println("jsonObj2:"+jsonObj2); 
         
        //创建jsonObj3,只有一个条目,内容为jsonObj2 
        jsonObj3.element("j3", jsonObj2); 
        System.out.println("jsonObj3:"+jsonObj3); 
     
        //往JSONArray中添加JSONObject对象。发现JSONArray跟JSONObject的区别就是JSONArray比JSONObject多中括号[] 
        jsonArray.add(jsonObj); 
        System.out.println("jsonArray:"+jsonArray); 
         
        JSONObject jsonObj4  = new JSONObject(); 
        jsonObj4.element("weather", jsonArray); 
        System.out.println("jsonObj4:"+jsonObj4); 
    } 
} </p><p>输出结果:</p><p>jsonObj0:{"name0":"zhangsan","sex1":"female"} 
jsonObj:{"name":"xuwei","sex":"male"} 
jsonObj2:{"item0":{"name0":"zhangsan","sex1":"female"},"item1":{"name":"xuwei","sex":"male"}} 
jsonObj3:{"j3":{"item0":{"name0":"zhangsan","sex1":"female"},"item1":{"name":"xuwei","sex":"male"}}} 
jsonArray:[{"name":"xuwei","sex":"male"}] 
jsonObj4:{"weather":[{"name":"xuwei","sex":"male"}]} </p>

- 阅读剩余部分 -

zz Apache 2.2.15 + PHP 5.3.2+ mysql windows环境配置

<h1 class="postTitle" style="font-size: 12px; margin: 10px 0px; padding: 3px; background-color: rgb(255, 255, 255); border-bottom-color: rgb(204, 204, 204); border-bottom-width: 1px; border-bottom-style: dashed; line-height: 19px; widows: 2; font-family: georgia, Verdana, Helvetica, Arial; orphans: 2; color: rgb(170, 170, 170);"><span style="color: rgb(51, 51, 51);"><span style="line-height: 21px; font-size: 14px; font-weight: normal;">1.下载Apache 2.2.15</span></span></h1><div class="postBody" style="text-align: justify; background-color: rgb(255, 255, 255); widows: 2; font-size: 13px; line-height: 19px; font-family: georgia, Verdana, Helvetica, Arial; orphans: 2; color: rgb(170, 170, 170);"><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">http://httpd.apache.org/download.cgi#apache22<;/span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">要下载的是Win32 Binary without crypto (no mod_ssl) (MSI Installer): </span><span style="color: rgb(51, 51, 51);">httpd-2.2.15-win32-x86-no_ssl.msi</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">PS: 天空软件站居然有2.2.4版本(Apache官网才到2.2.15),但确实是可用的,下载链接: </span><span style="color: rgb(51, 51, 51);">http://www.skycn.com/soft/1218.html<;/span></p><div style="page-break-after: always;"><span style="display: none;"><!--more-->& nbsp ;</span></div><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">​</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">2.下载PHP 5.3.2</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">http://windows.php.net/download/<;/span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">这里下载的是VC6 x86 Thread Safe的zip版</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">具体原因参考</span><span style="color: rgb(51, 51, 51);">PHP关于VC9和VC6以及Thread Safe和Non Thread Safe版本选择的问题</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">PS: 切记是要zip版,不要下错Installer版,Installer版有些文件没放在安装目录里面.</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">3.安装Apache和PHP环境</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">为了方便路径配置的,我安装Apache时把路径改为C:Apache,把PHP的zip包解压缩到C:PHP</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">4.配置Apache环境</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> 打开Apache的配置文件C:Apacheconfhttpd.conf</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">1)查找"DocumentRoot",该参数是用来指定Apache的网站根目录,</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">默认值是C:/Apache/htdocs,为了便于调试,我把值改为E:/Website(如果目录不存在,启动Apache服务时会出错)</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">2)查找"This should be changed to whatever you set DocumentRoot to."</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">在这行下面有一行<Directory "C:/Apache/htdocs">,改成<Directory "E:/Website"></span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">3)查找"<Directory />",在<Directory />和</Directory>之间有一行"Deny from all",改成"Allow from all"</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">4)查找"DirectoryIndex",在index.html后面加index.php(此为默认首页文件名,可加可不加)</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">PS: 配置路径的值是反斜杠'/',不是斜杠'&#39;</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">5.配置PHP环境</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> 在C:PHP中有两个可选的配置文件:php.ini-development和php.ini-production, 用记事本打开php.ini-development</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">1).查找"doc_root",将其值设置为E:/Website(必须跟Apache的DocumentRoot的值一致)</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">2)查找"extension_dir",该参数是用来指定扩展插件的dll目录,这里设置为C:PHPext</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">这行一般是被注释掉的,去掉extension_dir前面的";"号即可.</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">3)查找"extension=",反注释下面这两行:(就是把前面的";"号去掉)</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">extension=php_gd2.dll</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">extension=php_mysql.dll</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">4)查找"default_charset",默认是iso-8859-1,改成UTF-8(也可以改成GBK)</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">5)查找"register_globals",默认是Off,有些系统需要改成On(例如WordPress),有些却需要Off(例如DeDeCMS)</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">6)保存php.ini-development,并重命名为php.ini,放到C:WINDOWS</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">7)把php5ts.dll文件放到C:WINDOWSsystem32</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">6.配置Apache和PHP整合</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">1)把php5apache2_2.dll文件放到C:Apachemodules</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">2)打开C:Apacheconfhttpd.conf</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">查找"LoadModule",在LoadModule列表的最后加一行LoadModule php5_module modules/php5apache2_2.dll</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">查找"AddType",在AddType列表的最后加一行AddType application/x-httpd-php .php</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">3)重启Apache服务(Monitor界面的Restart按钮)</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">7.测试环境</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">1)打开IE,输入</span><span style="color: rgb(51, 51, 51);">http://localhost/<;/span><span style="color: rgb(51, 51, 51);">,没报错就是成功了.</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);"> </span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">2)在E:Website目录新建一个"test.php"文件,用记事本编辑文件,输入"<?php phpinfo(); ?>",保存并关闭.</span></p><p style="margin: 5px auto; padding: 0px;"><span style="color: rgb(51, 51, 51);">在IE输入</span><span style="color: rgb(51, 51, 51);">http://localhost/test.php<;/span><span style="color: rgb(51, 51, 51);">,出现PHP的版本信息就代表配置成功了.</span></p></div>

- 阅读剩余部分 -

一种以ID特征为依据的数据分片(Sharding)策略

<p>假如您有一个应用程序,随着业务越来越有起色,系统所牵涉到的数据量也就越来越大,此时您要涉及到对系统进行伸缩(Scale)的 问题了。一种典型的扩展方法叫做“向上伸缩(Scale Up)”,它的意思是通过使用更好的硬件来提高系统的性能参数。而另一种方法则叫做“向外伸缩(Scale Out)”,它是指通过增加额外的硬件(如服务器)来达到相同的效果。从“硬件成本”还是“系统极限”的角度来说,“向外伸缩”一般都会优于“向上伸 缩”,因此大部分上规模的系统都会在一定程度上考虑“向外”的方式。由于许多系统的瓶颈都处在数据存储上,因此一种叫做“数据分片(Database Sharding)”的数据架构方式应运而生,本文便会讨论这种数据架构方式的一种比较典型的实现方式。</p><div style="page-break-after: always;"><span style="display: none;"><!--more-->& nbsp ;</span></div><h1>简介</h1><p>数据分片,自然便是将整体数据分摊在多个存储设备(下文统称为“数据分区”或“分区”)上,这样每个存储设备的数据量相对就会小很多,以此满足系统的性能需求。值得注意的是,系统分片的策略有很多,例如常见的有以下几种:</p><ul> <li>根据ID特征:例如对记录的ID取模,得到的结果是几,那么这条记录就放在编号为几的数据分区上。</li> <li>根据时间范围:例如前100万个用户数据在第1个分区中,第二个100万用户数据放在第2个分区中。</li> <li>基于检索表:根据ID先去一个表内找到它所在的分区,然后再去目标分区进行查找。</li> <li>……</li></ul><p>在这些数据分片策略之中没有哪个有绝对的优势,选择哪种策略完全是根据系统的业务或是数据特征来确定的。值得强调的是:数据分片不是银弹,它对系统的性能和伸缩性(Scalability)带 来一定好处的同时,也会对系统开发带来许多复杂度。例如,有两条记录分别处在不同的服务器上,那么如果有一个业务是为它们建立一个“关联”,那么很可能表 示“关联”的记录就必须在两个分区内各放一条。另外,如果您重视数据的完整性,那么跨数据分区的事务又立即变成了性能杀手。最后,如果有一些需要进行全局 查找的业务,光有数据分片策略也很难对系统性能带来什么优势。</p><p>数据分片虽然重要,但在使用之前一定要三思而后行。一旦踏上这艘贼船,往往不成功便成仁,很难回头。在我的经验里,一个滥用数据分片策略而事倍功半的项目给我留下了非常深刻的印象(当然也有成功的啦),因此目前我对待数据分片策略变得愈发谨慎。</p><p>那么现在,我们便来讨论一种比较常见的数据分片策略。</p><h1>策略描述</h1><p>这里我先描述一个极其简单的业务:</p><ol> <li>系统中有用户,用户可以发表文章,文章会有评论</li> <li>可以根据用户查找文章</li> <li>可以根据文章查找评论</li></ol><p>那么,如果我要对这样一个系统进行数据分片又该怎么做呢?这里我们可以使用上面提到的第一种方式,即对记录的ID取模,并根据结果选择数据所在的分区。根据后两条业务中描述的查询要求,我们会为分区策略补充这样的规则:</p><ul> <li>某个用户的所有文章,与这个用户处在同一数据分区内。</li> <li>某篇文章的所有评论,与这篇文章处在用一数据分区内。</li></ul><p>您可能会说,似乎只要保证“相同用户文章在同一个数据分区内”就行了,不是吗?没错,不过我这里让文章和用户在同一个分区内,也是为了方便许多额外的操作(例如在关系数据库中进行连接)。那么假设我们有4个数据分区,那么它们内部的条目可能便是:</p><table border="1" cellpadding="5" cellspacing="0"> <tbody> <tr> <td>分区0</td> <td>分区1</td> </tr> <tr> <td> <ul> <li>User 4 <ul> <li>Article 8</li> <li>Article 12 <ul> <li>Comment 4</li> <li>Comment 16</li> </ul> </li> </ul> </li> <li>User 12</li> <li>Article 4</li> </ul> </td> <td> <ul> <li>User 1 <ul> <li>Article 5</li> <li>Article 9 <ul> <li>Comment 13</li> <li>Comment 17</li> </ul> </li> </ul> </li> <li>User 5</li> <li>Article 13</li> </ul> </td> </tr> <tr> <td>分区2</td> <td>分区3</td> </tr> <tr> <td> <ul> <li>User 2 <ul> <li>Article 10</li> <li>Article 14 <ul> <li>Comment 6</li> <li>Comment 10</li> </ul> </li> </ul> </li> <li>User 10</li> <li>Article 4</li> </ul> </td> <td> <ul> <li>User 7 <ul> <li>Article 7</li> <li>Article 11 <ul> <li>Comment 3</li> <li>Comment 15</li> </ul> </li> </ul> </li> <li>User 11</li> <li>Article 4</li> </ul> </td> </tr> </tbody></table><p>在 ID为0的分区中,所有对象的ID模4均为0,其他分区里的对象也有这样的规律。那么好,在实际应用中,如果我们需要查找“ID为2的用户”,便去第2分 区搜索便是;如果要查找“ID为8的文章的所有评论”那么也只要去第0分区进行一次查询即可。既然查询不成问题,那么我们该如何添加新记录呢?其实这也不 难,只要:</p><ul> <li>添加新用户时,随机选择一个数据分区</li> <li>添加新文章时,选择文章作者所在分区(可根据Article的UserID求模得到)</li> <li>添加新评论时,选择文章所在分区(可根据Comment的ArticleID求模得到)</li></ul><p>但 是,我们又如何保证新纪录的ID正好满足我们的分区规律?例如我们向第3分区添加的新数据,则它的ID必须是3、7、11等等。以前,我们可能会使用数据 库的自增列作为ID的值,但这似乎不能满足我们“取模”的要求。以前我们可能还会使用GUID,但是我们如何生成一个“被4模于3”的GUID呢?其实我 们还是可以使用自增ID来解决这个问题,只不过需要进行一些简单的设置。例如在SQL Server中,默认的自增ID属性为IDENTITY(1, 1),表示ID从1开始,以1为间距自动增长。于是我们在创建数据分区的时候,每个自增列的属性则可以设置为:</p><ul> <li>分区0:IDENTITY(4, 4)</li> <li>分区1:IDENTITY(1, 4)</li> <li>分区2:IDENTITY(2, 4)</li> <li>分区3:IDENTITY(3, 4)</li></ul><p>这样,ID方面的问题便交由数据库来关心吧,我们的使用方式和以前并没有什么区别。</p><h1>缺陷</h1><p>那么这个数据分片策略有什么缺陷呢?当然缺陷还是有很多啦,只是大多数问题可能还是要和业务放在一起考虑时才会凸显出来。不过有一个问题倒和业务关系不大:如果数据继续增长,单个数据分区的数据量也超标了,怎么办?</p><p>自 然,继续拆分咯。那么我们使用什么分区规则呢?和原先一致吗?我们举个例子便知。假设我们原有4个分区,有一个ID为1的用户落在第1分区里,他的文章也 都在这个分区里,ID分别是1、5、9、13、17等等。于是在某一天,我们需要将分区数量提高到5个(财力有限,一台一台来吧),在重新计算每篇文章所 在的分区之后,我们忽然发现:</p><ul> <li>ID为1的文章,模5余1,处在分区1。</li> <li>ID为5的文章,模5余0,处在分区0。</li> <li>ID为9的文章,模5余4,处在分区4。</li> <li>ID为13的文章,模5余3,处在分区3。</li> <li>ID为17的文章,模5余2,处在分区2。</li></ul><p>呼,5 个分区都齐了!这说明,如果我们保持记录原来的ID不变,是没有办法直接使用之前的分区规则——无论您扩展成几个分区,(即便是从4个到8个)也只能“缓 解”也不能“解决”这个情况。那么这时候该如何是好呢?例如,我们可以重新分配记录,改变原有ID,只是这么做会产生一个问题,便是外部URL可能也会随 着ID一起改变,这样对SEO的折损很大。为此,我们可以制作一个查询表:例如在查询小于1234567的ID时(这是“老系统”的最大ID),假设是 100,则根据查询表得知这条记录的新ID为7654321,再以此去数据源进行查找。解决这类问题的方法还有几种,但无论怎么做都会对新系统带来额外的 复杂度。而且,一次扩展也罢,如果以后还要有所扩展呢?</p><p>consistent-hahsing</p><p>有朋友可能会说,取模自然会带来这样的问题,那么为什么不用一致性哈希(Consistent Hash)呢? 现在一致性哈希是个很流行的东西,和Memcached一样,如果不用上就会被一些高级架构师所鄙视。不过在这里一致性哈希也不能解决问题。一致性哈希的 目的,是希望“在增加服务器的时候降低数据移动规模,让尽可能多的数据保留在原有的服务器”上。而我们现在的问题却是“在增加服务器的时候,让特征相同的 数据同样放在一起”。两个目标不同,这并不是一致性哈希的应用场景。</p><p>我在以前的一个项目中曾经用过这样的方法:根据对访问量与数据量的 预估,我们认为使用最多24个分区便一定可以满足性能要求(为什么是24个?因为它能被许多数字整除)。于是,从项目第一次在生产环境中部署时便创建了 24个数据分区,只不过一开始只用了2台服务器,每台服务器放置12个数据分区。待以后需要扩展时,则将数据分区均匀地迁移到新的服务器上即可。我们团队 当时便是用这种方法避免尴尬的数据分配问题。</p><p>没错,数据分区的数目是个限制,但您真认为,24个数据分区还是无法满足您的项目需求吗? 要知道,需要用上24个数据分区的项目,一般来说本身已经有充分的时间和经济实力进行架构上的重大调整(也该调整了,几乎没有什么架构可以满足各种数据规 模的需求)。此外,无论是系统优化还是数据分片都可以同时运用其他手段。</p><p>不过,我们目前还是想办法解决这个问题吧。</p><h1>策略改进</h1><p>我们之所以会遇到上面这个问题,在于我们没有选择好合适的策略,这个策略把一些重要的“要求”给“具体化”了,导致“具体化”后的结果在外部条件改变的时候,却无法重新满足原有的“要求”。还是以前面的案例来说明问题,其实我们“要求”其实是:</p><ul> <li>某个用户的所有文章,与这个用户处在同一数据分区内。</li> <li>某篇文章的所有评论,与这篇文章处在用一数据分区内。</li></ul><p>而我们“具体化”以后的结果却是:</p><ul> <li>某个用户的所有文章ID,与这个用户的ID模4后的余数相同。</li> <li>某篇文章的所有评论ID,与这篇文章的ID模4后的余数相同。</li></ul><p>之 所以能如此“具体化”,这是因为有“4个分区”这样的前提条件在,一旦这个前提条件发生了改变,则杯具无法避免。因此,我们在制定规则的时候,其实不应该 把前提条件给过分的“具体化”——具体化可以,但不能过度,得留有一定空间(这个稍后再谈)。打个比方,还是前面的条件(XX和XX处在同一数据分区 内),但我们换一种具体化的方式:</p><ul> <li>某个用户的所有文章ID的前缀,便是这个用户的ID。例如,ID为1的用户的所有文章,其ID便可能是1-A1、1-A2、1-A3……</li> <li>某篇文章的所有评论ID,与这个文章的ID使用相同前缀。例如,ID为3-A1的文章的所有评论,其ID便可能是3-C1、3-C2、3-C3……</li></ul><p>使 用这个策略,我们便可以保证与某个用户相关的“所有数据”都共享相同的“特征”(ID的前缀都相同),然后我们便可以根据这个特征来选择分区——例如,还 是以“取模”的方式。此时,我们已经确保了“相同分区内的所有数据都具备相同的特征”,即便分区数量有所调整,我们也只需要根据特征重新计算分区即可,影 响不大。而以前为什么不行?因为“模4的余数”只是“结果”而不是“特征”,这里的“特征”应该是“追本溯源后的用户ID相同”,而这一点已经体现在新的 策略中了。</p><p>还是通过图示来说明问题吧。假设原有4个分区,使用“取模”的策略:</p><table border="1" cellpadding="5" cellspacing="0"> <tbody> <tr> <td>分区0</td> <td>分区1</td> </tr> <tr> <td> <ul> <li>User 4 <ul> <li>Article 4-A1</li> <li>Article 4-A2 <ul> <li>Comment 4-C1</li> <li>Comment 4-C2</li> </ul> </li> </ul> </li> <li>User 12</li> <li>Article 12-A3</li> </ul> </td> <td> <ul> <li>User 1 <ul> <li>Article 1-A4</li> <li>Article 1-A5 <ul> <li>Comment 1-C3</li> <li>Comment 1-C4</li> </ul> </li> </ul> </li> <li>User 5</li> <li>Article 5-A6</li> </ul> </td> </tr> <tr> <td>分区2</td> <td>分区3</td> </tr> <tr> <td> <ul> <li>User 2 <ul> <li>Article 2-A7</li> <li>Article 2-A8 <ul> <li>Comment 2-C5</li> <li>Comment 2-C6</li> </ul> </li> </ul> </li> <li>User 10</li> <li>Article 10-A9</li> </ul> </td> <td> <ul> <li>User 7 <ul> <li>Article 7-A10</li> <li>Article 7-A11 <ul> <li>Comment 7-C7</li> <li>Comment 7-C8</li> </ul> </li> </ul> </li> <li>User 11</li> <li>Article 11-A12</li> </ul> </td> </tr> </tbody></table><p>当分区数量调整为5个之后(为了避免分区3空缺,我又补充了一些对象):</p><table border="1" cellpadding="5" cellspacing="0"> <tbody> <tr> <td>分区0</td> <td>分区1</td> </tr> <tr> <td> <ul> <li>User 10 <ul> <li>Article 10-A9</li> </ul> </li> <li>User 5</li> <li>Article 5-A6</li> </ul> </td> <td> <ul> <li>User 1 <ul> <li>Article 1-A4</li> <li>Article 1-A5 <ul> <li>Comment 1-C3</li> <li>Comment 1-C4</li> </ul> </li> </ul> </li> <li>User 11</li> <li>Article 11-A12</li> </ul> </td> </tr> <tr> <td>分区2</td> <td>分区3</td> </tr> <tr> <td> <ul> <li>User 2 <ul> <li>Article 2-A7</li> <li>Article 2-A8 <ul> <li>Comment 2-C5</li> <li>Comment 2-C6</li> </ul> </li> </ul> </li> <li>User 12</li> <li>Article 12-A3</li> <li>Article 7-A10</li> <li>Article 7-A11 <ul> <li>Comment 7-C7</li> <li>Comment 7-C8</li> </ul> </li> <li>User 7</li> </ul> </td> <td> <ul> <li>User 8 <ul> <li>Article 8-A12</li> <li>Article 8-A13 <ul> <li>Comment 8-C9</li> <li>Comment 7-C10</li> </ul> </li> </ul> </li> </ul> </td> </tr> <tr> <td>分区4</td> <td> </td> </tr> <tr> <td> <ul> <li>User 4 <ul> <li>Article 4-A1</li> <li>Article 4-A2 <ul> <li>Comment 4-C1</li> <li>Comment 4-C2</li> </ul> </li> </ul> </li> </ul> </td> <td> </td> </tr> </tbody></table><p>是不是很合理?</p><p>值 得一提的是,只要满足了“特征”这个要求,其实选择分区的方式并没有什么限制。例如,我们可以不用“取模”的方式,而是使用“一致性哈希”——没错,这里 就是一致性哈希的使用场景了。在利用“一致性哈希”来选择分区之后,在添加服务器的情况下便可以相对减少数据的迁移数量了。</p><p>当然,在实 现时还可以运用一些技巧。例如,我们的特征并非一定要“把用户ID作为前缀”——毕竟用户ID可能比较长,作为ID前缀还真有些难看(请想象把GUID作 为ID前缀,再加上另一个GUID作为ID主体的情景)。此时,我们可以把前提条件先进行一定程度的“具体化”(但就像之前提到的,不能过度),例如我们 可以把用户ID先进行取模,可能是1000万,便可以得到一个落在较大区间范围内的数字。然后,再把这个数字作BASE64编码,一下子前缀就缩小为4个 字符以内了。而且,1000万这个区间范围,无论是使用取模还是一致性哈希的方式来选择分区都非常可行,一般不会造成什么问题。</p><h1>总结</h1><p>数 据分片是系统优化的常用设计方式之一。正如前文所说的那样,数据分片的做法很多,本文提到的方式只是其中一种方式。这种根据ID特征的分片方式比较容易遇 到的问题之一,便是在数据分区数量改变时造成的规则冲突,这也正是我这篇文章所讨论的主要内容。从这个角度看来,其他一些分片方式,如创建时间也好,查找 表也罢,这样的问题反而不太常见。如果您有这方面的经验或是疑惑,也欢迎与我进行交流。</p><p>现在Web 2.0网站越来越热门了,此类项目的数据量也越来越大,从近几年的讨论形式可以看出,越来越多的人在强调什么大规模、高性能、或是海量数据。然后,似乎每 个人都会横向切分、纵向切分、缓存、分离。我猜,再接下来,估计又会有许多人以用关系型数据库为耻了吧?但是,想想这样的问题:博客园和JavaEye都 是国内技术社区的翘楚,它们都只用了1台数据库服务器。StackOverflow世界上最大的编程网站(它是使用ASP.NET MVC写的,兄弟们记住这个经典案例吧),似乎也只用了1台还是2台数据库服务器(可能配置比较高)及SQL Server。因此,即便是单台服务器,即便是使用关系型数据库,它在性能方面的潜力也是非常之高的。</p><p>因 此,数据分片应该只在需要的时候才做,因为它带来的复杂度会比中心存储的方式高出很多。这带来的结果是,可能您的应用程序还没有用足架构的能力就已经失败 了,这样各种投资也已经浪费了。假如您一开始用最简单的方式去做,可能很快会带来成长所需要空间及资源,此时再做更多投资进行架构优化也不迟——架构不是一蹴而就,而是演变得来的。当然,第一次投入多少复杂度是个需要权衡的东西,这也是考验架构师能力的地方。架构不是空中楼阁,而是各种真实资源调配的结果。</p>

- 阅读剩余部分 -

在与SQL server建立连接时出现与网络相关的或特定与实例的错误

<p> 在与SQL server建立连接时出现与网络相关的或特定与实例的错误 ...........error 40 错误 SQL Server错误 02  .. 今天运行SQL 08的时候给我来个这个提示. 我就纳闷了...研究了半天 ..发现是有个服务没启动 .......在这里记录下 .方便一下跟我一样对SQL比较菜的童鞋们....</p><p>      1. 打开 SQL Server 2008 的配置管理器.</p><div style="page-break-after: always;"><span style="display: none;"><!--more-->& nbsp ;</span></div><p>      2. 点击SQL Server 服务选项 然后看右边...应该有4个服务.都是没有启动的</p><p>      3. 启动SQL Server(MSSQLSERVER)  即可</p><p>如果不行就再过看一眼下面的  MSSQLSERVER 的协议</p><p>   看TCP/IP 是不是启动了</p><p>   Shared Memory 也要启动 .</p>

- 阅读剩余部分 -

随机文章

最近回复

分类

其它

友情连接

推广链接