<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    neverend的日志

    不記錄,終將被遺忘。 一萬(wàn)年太久,只爭(zhēng)朝夕。 他們用數(shù)字構(gòu)建了整個(gè)世界。

      BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
      62 Posts :: 1 Stories :: 17 Comments :: 0 Trackbacks

    #

    以root用戶登錄
    1.下載并安裝SVN服務(wù)
    $  sudo apt-get install subversion
    $  sudo apt-get install libapache2-svn

    2.設(shè)置SVN用戶組
    $ sudo addgroup subversion
    $ sudo usermod -G subversion -a root
    注銷后重新登錄

    3.創(chuàng)建SVN目錄
    $ sudo mkdir /home/svn
    $ cd /home/svn
    $ sudo mkdir labproject
    $ sudo chown -R root:subversion labproject

    4.創(chuàng)建 SVN 文件倉(cāng)庫(kù):
    $ sudo svnadmin create /home/svn/labproject
    $ sudo chmod -R g+rws labproject

    5. 通過(guò)自帶協(xié)議訪問(wèn) svnserve 服務(wù)器
     修改 /home/svn/labproject/conf/svnserve.conf 來(lái)配置其訪問(wèn)控制
     取消一下配置項(xiàng)的注釋
     # [general]
     # password-db = passwd
     
     在password文件中編輯賬號(hào)和密碼,格式如下
     username=password
     注意,以上兩步操作行前不要留任何空白字符

     運(yùn)行svnserve服務(wù)
     sudo svnserve -d -r /home/svn/labproject
     配置完成。
     如果需要將svnserve設(shè)置成開機(jī)自動(dòng)啟動(dòng)服務(wù)
     可在/etc/rc.loacl文件中添加:
     sudo svnserve -d -r /home/svn/labproject
     
     基本命令
     訪問(wèn)SVN倉(cāng)庫(kù):
     $ svn co svn://hostname labproject --username user_name
     新增文件test.c
     $ svn add test.c
     將文件test.c提交到服務(wù)器
     $ svn commit -m "comment."
     更新文件倉(cāng)庫(kù)
     $ svn up

    posted @ 2011-08-15 23:46 neverend 閱讀(522) | 評(píng)論 (0)編輯 收藏

    首先在Abode網(wǎng)站下載插件包。目前64位版在此處下載。我只接命令搞定:

    然后如下


    tar xvzf flashplayer10_2_p3_64bit_linux_111710.tar.gz

    mkdir -p $HOME/.mozilla/plugins

    mv libflashplayer.so $HOME/.mozilla/plugins/

    最后,重啟firefox既可。

    posted @ 2011-08-09 21:50 neverend 閱讀(649) | 評(píng)論 (0)編輯 收藏

    最近寫了些多線程的程序,用Thread.sleep()的時(shí)候有時(shí)會(huì)碰到InterruptedException。查了一些資料,下面是我自己的一些理解。

    阻塞方法
    一些多線程相關(guān)的方法是阻塞方法,比如Thread.sleep(), Thread.wait(), Thread.join()。

    這些方法的執(zhí)行通常需要比較長(zhǎng)的時(shí)間來(lái)完成,當(dāng)代碼執(zhí)行到阻塞方法時(shí),一般要等待該方法返回后

    才能繼續(xù)往下執(zhí)行,而InterruptedException提供了一種特殊的機(jī)制提前結(jié)束阻塞方法。

    中斷變量
    每個(gè)線程都會(huì)維護(hù)一個(gè)bool變量,表示線程處于中斷(true)或者非中斷狀態(tài)(false)。在線程初始的情況下中斷變量為false。

    這個(gè)變量的bool值可以通過(guò)Thread.isInterrupted()方法來(lái)讀取,通過(guò)Thread.interrupted()方法來(lái)清除中斷(即將中斷變量置為false)。

    線程中斷
    一個(gè)線程可以通過(guò)調(diào)用Thread.interrupt()方法來(lái)中斷另外一個(gè)線程,具體過(guò)程如下:

    1. 中斷變量被設(shè)置為true。

    2. 如果線程執(zhí)行到了阻塞方法,那么該方法取消阻塞,并將中斷變量重新置為false。
    (這種機(jī)制是通過(guò)阻塞方法內(nèi)部不斷輪詢中斷變量的值來(lái)實(shí)現(xiàn)的)

    例子:
     1 class ThreadTest implements Runnable {
     2 
     3     @Override
     4     public void run() {
     5                 System.out.println("before sleep");
     6             try {
     7                 Thread.sleep(5000);
     8             } catch (InterruptedException e) {
     9                                 System.out.println(Thread.currentThread().getName());
    10                 Thread.currentThread().interrupt();
    11                 System.out.println("after interrupt");
    12             }        
    13         System.out.println("after sleep");    
    14         
    15         try {
    16             Thread.sleep(5000);
    17         } catch (InterruptedException e) {
    18             // TODO Auto-generated catch block
    19             //e.printStackTrace();
    20             System.out.println(Thread.currentThread().getName());
    21             Thread.currentThread().interrupt();
    22             System.out.println("after interrupt");
    23         }
    24         System.out.println("after sleep");    
    25     }
    26     
    27 }
    28 
    29 public class ThreadBasic {
    30     
    31     public static void main(String[] args) {
    32         
    33         Thread t = new Thread(new ThreadTest(), "thread-1");
    34         t.start();
    35         
    36         t.interrupt();
    37         System.out.println(t.isInterrupted());
    38     }
    39 }






    posted @ 2011-06-14 20:03 neverend 閱讀(19797) | 評(píng)論 (1)編輯 收藏

    術(shù)語(yǔ)說(shuō)明:
    QPS = req/sec = 請(qǐng)求數(shù)/秒

    【QPS計(jì)算PV和機(jī)器的方式】

    QPS統(tǒng)計(jì)方式 [一般使用 http_load 進(jìn)行統(tǒng)計(jì)]
    QPS = 總請(qǐng)求數(shù) / ( 進(jìn)程總數(shù) *   請(qǐng)求時(shí)間 )
    QPS: 單個(gè)進(jìn)程每秒請(qǐng)求服務(wù)器的成功次數(shù)

    單臺(tái)服務(wù)器每天PV計(jì)算
    公式1:每天總PV = QPS * 3600 * 6
    公式2:每天總PV = QPS * 3600 * 8

    服務(wù)器計(jì)算
    服務(wù)器數(shù)量 =   ceil( 每天總PV / 單臺(tái)服務(wù)器每天總PV )

    【峰值QPS和機(jī)器計(jì)算公式】

    原理:每天80%的訪問(wèn)集中在20%的時(shí)間里,這20%時(shí)間叫做峰值時(shí)間
    公式:( 總PV數(shù) * 80% ) / ( 每天秒數(shù) * 20% ) = 峰值時(shí)間每秒請(qǐng)求數(shù)(QPS)
    機(jī)器:峰值時(shí)間每秒QPS / 單臺(tái)機(jī)器的QPS   = 需要的機(jī)器

    問(wèn):每天300w PV 的在單臺(tái)機(jī)器上,這臺(tái)機(jī)器需要多少Q(mào)PS?
    答:( 3000000 * 0.8 ) / (86400 * 0.2 ) = 139 (QPS)

    問(wèn):如果一臺(tái)機(jī)器的QPS是58,需要幾臺(tái)機(jī)器來(lái)支持?
    答:139 / 58 = 3



    http://blog.hummingbird-one.com/?tag=web-%E6%80%A7%E8%83%BD-qps-%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4

    http://jjw.javaeye.com/blog/703864



    posted @ 2011-01-25 17:13 neverend 閱讀(22204) | 評(píng)論 (2)編輯 收藏

    Windows提供了WNetAddConnection()函數(shù)來(lái)建立網(wǎng)絡(luò)映射,NetUserAdd()函數(shù)來(lái)添加用戶。這兩個(gè)函數(shù)和在一起可以實(shí)現(xiàn)為遠(yuǎn)程主機(jī)添加用戶的功能。但是,要真正實(shí)現(xiàn)遠(yuǎn)程添加用戶的功能,需要在遠(yuǎn)程主機(jī)上做正確的配置。如果遠(yuǎn)程主機(jī)是Windows XP Pro,需要做如下配置:
    1. 開啟遠(yuǎn)程連接
    我的電腦——>右鍵——>屬性——>遠(yuǎn)程——>勾選“允許用戶連接到此計(jì)算機(jī)”

    2. 開啟網(wǎng)絡(luò)共享功能。
    新建一個(gè)文件夾,右鍵——>共享——>創(chuàng)建共享。

    3. 更改遠(yuǎn)程用戶安全策略
    管理工具——>本地安全策略——>安全選項(xiàng)——>網(wǎng)絡(luò)訪問(wèn):本地賬戶的共享和安全模式,雙擊,改為“經(jīng)典——本地用戶以自己的身份驗(yàn)證”

    4.開啟Telnet (不確定是否必要)
    如果不做配置3,執(zhí)行NetUserAdd()函數(shù)時(shí),會(huì)報(bào)出訪問(wèn)權(quán)限不夠的問(wèn)題。因?yàn)槟J(rèn)的安全策略“僅來(lái)賓”是指不管網(wǎng)絡(luò)登錄的用戶/密碼參數(shù)擁有什么樣的系統(tǒng)權(quán)限,登陸后一律賦予Guest用戶的權(quán)限,以Guest賬戶添加一個(gè)Administrators組的賬戶時(shí)自然會(huì)出現(xiàn)權(quán)限不足的問(wèn)題。而“經(jīng)典”模式是指網(wǎng)絡(luò)登錄后的賬戶與輸入的用戶/密碼參數(shù)的賬戶保持一致的權(quán)限,即如果輸入管理員賬號(hào),登錄后就擁有管理員組的權(quán)限;如果以Guest用戶登錄,登錄后就擁有Guest賬戶的權(quán)限。

    PS: Windows 2000的內(nèi)置設(shè)置就是“經(jīng)典”模式,所以不會(huì)出現(xiàn)上述問(wèn)題。

    參考資料:
    http://hi.baidu.com/mofangzhe/blog/item/e5c05fedf39d62d1b21cb10d.html
    http://www.sq01.cn/viewthread.php?tid=161

    posted @ 2010-11-08 21:25 neverend 閱讀(672) | 評(píng)論 (0)編輯 收藏

         摘要: Linux/BSD在/etc/shadow文件中存放加密過(guò)的密碼,加密函數(shù)是crypt(),具體的源程序在glibc里面的crypt目錄下。 crypt()函數(shù)最初使用DES算法加密密碼明文,生成的密文格式是2個(gè)字符的salt和11個(gè)字符的DES輸出; 后來(lái)又出現(xiàn)了使用MD5算法生成密文的crypt()函數(shù),這種方式更加安全。 ReadHat命令行下使用authconfig-tu...  閱讀全文
    posted @ 2010-11-06 21:14 neverend 閱讀(2008) | 評(píng)論 (0)編輯 收藏

    服務(wù)器端 192.1.0.160
    客戶機(jī)端 192.1.0.221

    一、在服務(wù)器端配置LDAP服務(wù):
    1.下載 openldap-2.4.11.tar.gz和db-4.7.25.tar.gz

    2.安裝BerkeleyDB
    #rpm -qa|grep db
    # tar xvf db
    -4.7.25.tar.gz
    # cd db_4.
    7.25
    # cd build_unix
    /
    # ..
    /dist/configure -prefix=/usr/local/BerkeleyDB
    # make
    # make install

    安裝完成后執(zhí)行
    #cp /usr/local/BerkeleyDB/include/* /usr/include/
    #cp /usr/local/BerkeleyDB/lib/* /usr/lib/
    可避免如下錯(cuò)誤:
    checking   Berkeley   DB   version   for   BDB/HDB   backends...   no   
    configure:   error:   BDB/HDB:   BerkeleyDB   version   incompatible

    3.安裝OpenLDAP
    #gunzip -c openldap-2.4.15.tgz | tar xvfB -
    #cd openldap
    -2.4.15/
    #.
    /configure --prefix=/usr/local/openldap
    #make depend
    #make
    #make install

    4.啟動(dòng)LDAP服務(wù)
    #cd /usr/local/openldap/libexec
    #.
    /slapd

    5.測(cè)試LDAP服務(wù)是否正常啟動(dòng)
    #ldapsearch --'' -s base '(objectclass=*)' namingContexts
    返回
    dn:

      namingContexts: dc=my-domain,dc=com
    則說(shuō)明正常啟動(dòng)

    6.正常關(guān)閉LDAP服務(wù)
    #kill -INT `cat /usr/local/openldap/var/run/slapd.pid`

    7.日志配置
    日志級(jí)別是累加的:296 = 256 日志連接/操作/結(jié)果 + 32 搜索過(guò)濾器處理 + 8 連接管理:
    文件slapd.config中添加:
    loglevel 296

    日志信息會(huì)被記錄到 syslogd LOG_LOCAL4 機(jī)制中。還需要將下面的內(nèi)容添加到 /etc/syslog.conf 中:

    local4.debug /var/log/slapd.log

    重啟syslog服務(wù)
    service syslog restart

    在/var/log/slapd.log中即可查看ldap的日志信息。
     
    二、客戶機(jī)端制作賬號(hào)遷移腳本
    IBM的《使用 OpenLDAP 集中管理用戶帳號(hào)》指出RedHat Enterprise 版本會(huì)自帶
    openldap-server、openldap-client和一些賬號(hào)移植的腳本
    但是在內(nèi)網(wǎng)160和我昨天在虛擬機(jī)上裝的RedHat上卻沒有找到相關(guān)文件。
    今天又在虛擬機(jī)上裝了一個(gè),發(fā)現(xiàn)默認(rèn)安裝并不包括這些,需要定制安裝:

    在光盤安裝過(guò)程中有個(gè)界面讓選擇默認(rèn)安裝還是定制安裝,選擇“定制安裝”,下一步,勾選如下軟件包:

    開發(fā)--開發(fā)庫(kù)
    openldap-devel-2.3.27
    perl-ldap
    perl-mozllla-ldap

    服務(wù)器——網(wǎng)絡(luò)服務(wù)器
    openldap-servers-2.3.27

    基本系統(tǒng)——系統(tǒng)工具
    openldap-client-2.3.27

    基本系統(tǒng)——老的軟件支持
    compat-db
    compat-openldap

    安裝完成后,就可以找到移植腳本和LDAP的一些文件了。

    遷移密碼和 shadow 信息

    Red Hat 所提供的 openldap-servers 包包含 PADL Software Pty Ltd. 公司的 MigrationTools 工具。我們將使用這些工具將數(shù)據(jù)從 Linux 系統(tǒng)文件(例如 /etc/group 和 /etc/password)轉(zhuǎn)換成 LDAP LDIF 格式,這是數(shù)據(jù)庫(kù)信息的一種文本格式的表示。這種格式是行界定、冒號(hào)分隔的屬性-值對(duì)。

    有一組 Perl 腳本被安裝到 /usr/share/openldap/migration/ 中執(zhí)行遷移。這些 Perl 腳本的配置信息包含在 migrate_common.ph 文件的開頭。對(duì)于我們的目的來(lái)說(shuō),只需要修改命名前綴的變量來(lái)使用條目的識(shí)別名就足夠了,如下所示:

    $DEFAULT_BASE = "dc=mydomain,dc=com"

    在進(jìn)行這些修改之后,請(qǐng)運(yùn)行腳本 migrate_base.pl,它會(huì)創(chuàng)建根項(xiàng),并為 Hosts、Networks、Group 和 People 等創(chuàng)建低一級(jí)的組織單元:


     運(yùn)行 migrate_base.pl
    # ./migrate_base.pl > base.ldif
                

    編輯 base.ldif,刪除除下面之外的所有條目:


     base.ldif 條目
    # cat base.ldif
                dn: dc=mydomain,dc=com
                dc: ibm
                objectClass: top
                objectClass: domain
                dn: ou=People,dc=ibm,dc=com
                ou: People
                objectClass: top
                objectClass: organizationalUnit
                dn: ou=Group,dc=ibm,dc=com
                ou: Group
                objectClass: top
                objectClass: organizationalUnit
                

    在 LDAP 服務(wù)器上,使用 OpenLDAP 客戶機(jī)工具 ldapadd 將以下條目插入到數(shù)據(jù)庫(kù)中。簡(jiǎn)單身份驗(yàn)證必須要使用 -x 選項(xiàng)指定。在 slapd.conf 中定義的 rootdn 身份驗(yàn)證識(shí)別名是 “cn=Manager,dc=mydomain,dc=com”。對(duì)于簡(jiǎn)單身份驗(yàn)證來(lái)說(shuō),必須使用密碼。選項(xiàng) -W 強(qiáng)制提示輸入密碼。這個(gè)密碼就是在 slapd.conf 文件中指定的 rootpw 參數(shù)的值。包含這些條目的 LDIF 文件是使用 -f 選項(xiàng)指定的:


     使用 ldapadd 插入條目
    # ldapadd -x -D "cn=Manager,dc=mydomain,dc=com" -W -f base.ldif
                

    接下來(lái),從 /etc/group 中遷移 ldapuser 組:


     遷移 ldapuser 組
    # grep ldapuser /etc/group > group.in
                # ./migrate_group.pl group.in > group.ldif
                #  cat group.ldif
                dn: cn=ldapuser,ou=Group,dc=mydomain,dc=com
                objectClass: posixGroup
                objectClass: top
                cn: ldapuser
                userPassword: {crypt}x
                gidNumber: 500
                # ldapadd -x -D "cn=Manager,dc=mydomain,dc=com" -W -f group.ldif
                

    最后,從 /etc/passwd 和 /etc/shadow 中遷移 ldapuser 的信息:


     遷移 ldapuser 信息
    # grep ldapuser /etc/passwd > passwd.in
                # ./migrate_passwd.pl passwd.in > passwd.ldif
                # cat passwd.ldif
                dn: uid=ldapuser,ou=People,dc=mydomain,dc=com
                uid: ldapuser
                cn: ldapuser
                objectClass: account
                objectClass: posixAccount
                objectClass: top
                objectClass: shadowAccount
                userPassword: {crypt$1$TeOlOcMc$cpQaa0WpLSFRC1HIHW5bt1
                shadowLastChange: 13048
                shadowMax: 99999
                shadowWarning: 7
                loginShell: /bin/bash
                uidNumber: 500
                gidNumber: 500
                homeDirectory: /home/ldapuser
                gecos: ldapuser
                # ldapadd -x -D "cn=Manager,dc=mydomain,dc=com" -W -f passwd.ldif
                

    三、客戶機(jī)端配置NSS&PAM
    參考IBM《使用 OpenLDAP 集中管理用戶帳號(hào)》 配置 LDAP 客戶機(jī)部分
    方法1 圖形界面配置
    authconfig-tui
    方法2 修改配置文件
    /etc/ldap.conf、/etc/nsswitch.conf、/etc/sysconfig/authconfig 和/etc/pam.d/system-auth
    我的/etc/pam.d/system-auth的配置如下:

     

    #%PAM-1.0
    # This file is auto
    -generated.
    # User changes will be destroyed the next time authconfig is run.
    auth        required      pam_env.so
    auth        sufficient    pam_unix.so nullok try_first_pass
    auth        requisite     pam_succeed_if.so uid 
    >= 500 quiet
    auth        sufficient    pam_ldap.so use_first_pass
    auth        required      pam_deny.so

    account     required      pam_unix.so broken_shadow
    account     sufficient    pam_localuser.so
    account     sufficient    pam_succeed_if.so uid 
    < 500 quiet
    account     [
    default=bad success=ok user_unknown=ignore] pam_ldap.so
    account     required      pam_permit.so

    password    requisite     pam_cracklib.so try_first_pass retry
    =3
    password    sufficient    pam_unix.so md5 shadow nullok try_first_pass use_authtok
    password    sufficient    pam_ldap.so use_authtok
    password    required      pam_deny.so

    session     optional      pam_keyinit.so revoke
    session    required    pam_mkhomedir.so skel
    =/etc/skel/ umask=0022
    session     required      pam_limits.so
    session     [success
    =1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
    session     required      pam_unix.so
    session     optional      pam_ldap.so

    一點(diǎn)說(shuō)明:pam_mkhomedir.so 負(fù)責(zé)用戶初次登陸沒有home目錄時(shí)為其創(chuàng)建home目錄。沒有這項(xiàng)配置的話,新用戶登陸可能會(huì)報(bào)/home目錄找不到的錯(cuò)誤。

    問(wèn)題:
    SSL的配置
    主從LDAP服務(wù)器的配置
    日志級(jí)別的配置

    PAM的作用究竟是什么?
    身份鑒別到底是由系統(tǒng)完成的還是LDAP完成的?
    資源和組織的信息如何組織?
    授權(quán)是如何進(jìn)行的?
    posted @ 2010-11-02 22:49 neverend 閱讀(1438) | 評(píng)論 (0)編輯 收藏

    本文主要參考官方文檔:http://www.openldap.org/doc/admin24/quickstart.html
    和網(wǎng)上流傳的教程:http://www.lifv.cn/?p=462

    OpenLDAP下載地址:http://download.bergmans.us/openldap/openldap-2.2.29/openldap-2.2.29-db-4.3.29-openssl-0.9.8a-win32_Setup.exe 下載后點(diǎn)擊安裝即可。

    配置sldap.conf :在安裝目錄下找到sldap.conf ,修改配置如下:
    suffix "dc=example,dc=com" 
    rootdn 
    "cn=Manager,dc=example,dc=com" 
    rootpw secret 

    啟動(dòng)OpenLDAP:進(jìn)入cmd命令行,跳轉(zhuǎn)到OpenLDAP安裝目錄下,運(yùn)行:
    slapd -1
    用可以看到控制臺(tái)下打印一片信息,openldap 默認(rèn)是用的 Berkeley DB 數(shù)據(jù)庫(kù)存儲(chǔ)目錄數(shù)據(jù)的。

    再開一個(gè)cmd,跳轉(zhuǎn)到OpenLDAP安裝目錄下。

    測(cè)試OpenLDAP是否正常啟動(dòng):
    ldapsearch --s base (objectclass=*) namingContexts
    官方文檔里,這一條命令加了些單引號(hào),但帶單引號(hào)的命令在Windows環(huán)境下跑不通。后面的命令也都避免
    使用引號(hào)。
    如果返回:
    dn: 
    namingContexts: dc
    =example,dc=com
    則說(shuō)明OpenLDAP成功啟動(dòng)

    增加一個(gè)條目:
    1.做一個(gè)LDIF文件
    2.使用ldapadd命令

    1.在安裝目錄下,新建文件example.ldif,輸入如下內(nèi)容:
    dn: dc=example,dc=com 
    objectclass: dcObject 
    objectclass: organization 
    o: Example Company 
    dc: example 

    dn: cn
    =Manager,dc=example,dc=com 
    objectclass: organizationalRole 
    cn: Manager
    注意:在文檔每一行的開頭和結(jié)尾不要有空格,文檔最后最好也別回車。建議不要拷貝,用手敲這幾行。

    2.cmd在安裝目錄下,運(yùn)行:
    ldapadd --D cn=Manager,dc=example,dc=com --f example.ldif

    可能會(huì)要求輸入密碼:secret (配置文件里寫的這個(gè)密碼)

    添加條目成功后,會(huì)有提示: adding new entry cn=Manager,dc=example,dc=com

    簡(jiǎn)單查詢:
    ldapsearch --b dc=example,dc=com (objectclass=*)

    查詢成功后,會(huì)返回剛才插入的條目。

    JNDI連接OpenLDAP
    Java的JNDI接口很強(qiáng)大,可以連接LDAP服務(wù)。
    import java.util.Hashtable;
    import javax.naming.Context;
    import javax.naming.NamingException;
    import javax.naming.directory.DirContext;
    import javax.naming.directory.InitialDirContext; 
    public class TestOpenLDAP {

        
    /**
         * 
    @param args
         
    */
        
    public static void main(String[] args) {
            
    // TODO Auto-generated method stub
            TestOpenLDAP LDAPTest1 = new TestOpenLDAP();
            String root 
    = "dc=example,dc=com"//root
            Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY, 
    "com.sun.jndi.ldap.LdapCtxFactory" );
            env.put(Context.PROVIDER_URL, 
    "ldap://localhost/" + root);
            env.put(Context.SECURITY_AUTHENTICATION, 
    "simple" );
            env.put(Context.SECURITY_PRINCIPAL, 
    "cn=Manager,dc=example,dc=com" );
            env.put(Context.SECURITY_CREDENTIALS, 
    "secret" );
            DirContext ctx 
    = null ;
            
    try {
            ctx 
    = new InitialDirContext(env);
            System.out.println( 
    "認(rèn)證成功" );
            }
            
    catch (javax.naming.AuthenticationException e) {
            e.printStackTrace();
            System.out.println( 
    "認(rèn)證失敗" );
            }
            
    catch (Exception e) {
            System.out.println( 
    "認(rèn)證出錯(cuò):" );
            e.printStackTrace();
            }
    if (ctx != null ) {
            
    try {
            ctx.close();
            }
            
    catch (NamingException e) {
            
    //ignore
            }
            }

        }

    }

    問(wèn)題:
    1. 圖形化界面LDAPBrowser的配置
    下載地址: http://files.blogjava.net/Unmi/LdapBrowser282.rar
    解壓后進(jìn)入LdapBrowser282目錄,打開配置文件OpenLdap_Localhost.cfg
    修改配置:
    basedn=dc=example,dc=com
    managerdn
    =cn=Manager,dc=example,dc=com
    運(yùn)行l(wèi)be.bat進(jìn)入圖形界面后選擇連接OpenLdap_Localhost即可。

    2. OpenLDAP的語(yǔ)法,內(nèi)置ObjectClass

    LDAP學(xué)習(xí)

    entry(record,directory object)  條目 一條數(shù)據(jù) 相當(dāng)于數(shù)據(jù)表的一條記錄

    entry由若干個(gè)attribute組成,objectclass是必須的attribute,用于描述entry的schema

    attribute是name/value對(duì)形式,例如cn = liuxuanyu cn = mengke 一個(gè)name 可以對(duì)應(yīng)多個(gè)值

    container是一種特殊的entry,為數(shù)據(jù)的組織和管理提供一個(gè)繼承體系結(jié)構(gòu),例如ou
    任何entry都可以在特定的情況下變成container

    與關(guān)系數(shù)據(jù)庫(kù)的比較:
    LDAP讀操作性能高,寫操作性能不如DB,DB 讀寫均可,讀操作性能不如LDAP
    數(shù)據(jù)結(jié)構(gòu)不同
    LDAP適合于存儲(chǔ)繼承結(jié)構(gòu)的數(shù)據(jù)


    namespace
    DN (distinguish name) DN是entry的名字,entry的唯一標(biāo)識(shí)
    RDN (relative distinguish name) entry在某個(gè)容器范圍內(nèi)的標(biāo)識(shí)
    CN (common name) 常用名稱 習(xí)慣上被用作RDN
    DC (domain component) 域名

    LDAP只允許樹形結(jié)構(gòu)

    object identifier (OID) 例如:2.5.4.3 它是屬性類型的標(biāo)識(shí)符

    schema
    object class 定義了entry的類型
    有三種類型的object Class: 抽象類、輔助類和結(jié)構(gòu)化類。

    構(gòu)造schema的方式 :
    1. 組合現(xiàn)有的object class
    2. 擴(kuò)展現(xiàn)有的object class 繼承 使用輔助類(實(shí)際上是一種聚合關(guān)系)

    The subschema publishes the schema to clients

    inetOrgPerson is a contemporary definition for a person entry RFC 2798


    3. JLDAP與JNDI的比較
     JLDAP是由novel開發(fā)的,原是針對(duì)Novel的NDS目錄設(shè)計(jì)的JAVA訪問(wèn)工具。NOVEL的NDS和網(wǎng)景(NETSCAPE)的目錄是工具界最早的目錄產(chǎn)品。JLDAP并非JNDI的服務(wù)供應(yīng)者,而是同一抽象層次下的訪問(wèn)工具集。與JNDI-LDAP相比,JLDAP更接近于類關(guān)系數(shù)據(jù)庫(kù)的訪問(wèn)方式。

       NDS是遵守LDAP協(xié)議的并進(jìn)行了擴(kuò)展的類MAD產(chǎn)品。而NOVEL也已把JLDAP捐獻(xiàn)給了OPENLDAP開源項(xiàng)目,可以世界范圍內(nèi)自由使用。與 JNDI相比,JLDAP無(wú)須繼承DirContext才能實(shí)現(xiàn)添加,也無(wú)需預(yù)先生成添加的類,可以象普通數(shù)據(jù)訪問(wèn)那樣,生成連接,然后使用::add方法添加。這樣,添加的靈活性要強(qiáng)于JNDI。

    但由于JLDAP目前是訪問(wèn)NDS,因此,它不具備JNDI完全面向?qū)ο蟠鎯?chǔ)的能力,對(duì)于高級(jí)的LDAP應(yīng)用,JLDAP不是合適的選擇。


    4. OpenLDAP的深入管理
    posted @ 2010-10-08 23:05 neverend 閱讀(14374) | 評(píng)論 (5)編輯 收藏


    2.1求8位二進(jìn)制數(shù)中1的個(gè)數(shù)
    解法1:直觀法,每次除以2,計(jì)算余數(shù)為1的個(gè)數(shù) O(log2v)
    解法2:簡(jiǎn)單位操作,每次與0x01做與運(yùn)算,再右移一位。O(log2v)
    解法3:使用位操作v & (v-1) , 每次可減少二進(jìn)制數(shù)字中的一個(gè)1。(若v & (v-1) == 0, 則v為2的方冪)
    解法4:空間換時(shí)間,利用題目中字長(zhǎng)8位的破綻,建立一個(gè)窮舉數(shù)組。O(1)

    知識(shí)點(diǎn):位運(yùn)算的性質(zhì)
    附:數(shù)組有2n+1個(gè)數(shù),其中n個(gè)數(shù)成對(duì)出現(xiàn),找出非成對(duì)出現(xiàn)的那個(gè)數(shù)。
    數(shù)組所有元素做異或操作。

    2.2
    1.N!的末尾有多少個(gè)零
    2.N!二進(jìn)制表示中最低位1的位置

    1.解法:質(zhì)因數(shù)分解可知,0只有2*5可得,所以0的個(gè)數(shù)就是質(zhì)因數(shù)分解中2的個(gè)數(shù)與5的個(gè)數(shù)的最小值,實(shí)際上就是
    求5的個(gè)數(shù)Z。
    Z= [N/5] + [N/5^2] +[N/5^3]+ ……
    [N/5]表示不大于N的數(shù)中5的倍數(shù)貢獻(xiàn)一個(gè)5
    [N/5^2]表示不大于N的數(shù)中5^2再貢獻(xiàn)一個(gè)5/。

    2.解法:因?yàn)橘|(zhì)因數(shù)分解中只有2是偶數(shù),所以Z = [N/2] + [N/2^2] + [N/2^3] + …… +

    2.3尋找多數(shù)元素問(wèn)題
    解法:減治:每次刪除兩個(gè)不同的ID,水王ID出現(xiàn)的次數(shù)仍舊會(huì)超過(guò)總數(shù)的一半。

    2.4從1到N的所有數(shù)中“1”出現(xiàn)的個(gè)數(shù)
    解法:尋找1出現(xiàn)的規(guī)律,比較復(fù)雜。

    2.5尋找N個(gè)整數(shù)中最大的K個(gè)數(shù)
    解法1:選擇排序,選出最大的K個(gè)數(shù)。 O(n*k)
     一點(diǎn)改進(jìn):部分堆排序,先建堆,再排出最大的k個(gè)數(shù)即可。O(n)+O(logn*k)
    解法2:分治,利用快速排序的劃分思路。O(n*log2k)
    解法3:二分搜索(與《編程珠璣》第二章問(wèn)題A思路類似),有兩種劃分方式:
    1.設(shè)已知N個(gè)數(shù)中最小值Vmin,最大值Vmax,對(duì)區(qū)間[Vmin, Vmax]做二分即可。
    2.設(shè)N個(gè)整數(shù)是M位長(zhǎng)的。從最高位開始,按bi位0、1二分。
    此解法適用于大數(shù)據(jù)量的處理,不過(guò)要多次讀寫若干個(gè)臨時(shí)文件。
    解法4:建一個(gè)最小堆存儲(chǔ)K個(gè)數(shù),堆頂為堆中最小值。
    對(duì)第k到N個(gè)數(shù),若A[i]大于堆頂H[0],令H[0]=A[i],再調(diào)用shift-down過(guò)程調(diào)整堆。
    此解法非常適合于N值很大的情況,復(fù)雜度為O(n * log2k)
    解法5:空間換時(shí)間,用count[Vmax]計(jì)算每個(gè)數(shù)字出現(xiàn)的次數(shù)。
    如果Vmax很大,將[0, Vmax]分成m個(gè)小塊,再分別討論即可。

    2.7最大公約數(shù)問(wèn)題
     用位運(yùn)算求解
       位運(yùn)算問(wèn)題:
       1.求一個(gè)整數(shù)的二進(jìn)制表示中1的個(gè)數(shù)
       2.逆轉(zhuǎn)一個(gè)整數(shù)的二進(jìn)制表示問(wèn)題

    2.9斐波那契數(shù)列
    ·遞歸 效率最低
    ·迭代 O(n)
    ·矩陣分治法

    2.14子數(shù)組之和的最大值
    分治
    動(dòng)態(tài)規(guī)劃

    2.15子矩陣之和的最大值
    固定一維,另一維轉(zhuǎn)化為子數(shù)組之和的最大值問(wèn)題

    2.16求數(shù)組中最長(zhǎng)遞增字符列的長(zhǎng)度

    解法1:動(dòng)態(tài)規(guī)劃

    假設(shè)array[]的前i個(gè)元素中,最長(zhǎng)遞增子序列的長(zhǎng)度為L(zhǎng)IS[i],

    則,LIS[i + 1] = max{1, LIS[k]+1}, array[i+1] > array[k], for any k<=i

    int LIS(int[] array) {
    int[] LIS = new int[array.length];
    for (int i = 0 ; i < array.length; i++) {
        LIS[i] 
    = 1;
        
    for (int j = 0; j<i; j++) {
            
    if (array[i] > array[j] && LIS[j] + 1 >LIS[i])
                LIS[i] 
    = LIS[j] + ; 
        }

    }

     

    O(N^2)的時(shí)間復(fù)雜度

    解法2:

    MLIS[i]定義為前i個(gè)元素中,以array[i]為最大元素的最長(zhǎng)遞增子序列的長(zhǎng)度。

    可以證明,MLIS[i]的最大值也是最終的結(jié)果。

    MaxV[i]保存長(zhǎng)度為i的遞增子序列最大元素的最小值。

    解法2的程序更新MaxV的部分應(yīng)該是有問(wèn)題的,由此導(dǎo)致時(shí)間復(fù)雜度的分析錯(cuò)誤,并且解法3也是錯(cuò)誤的。


    2.17數(shù)組循環(huán)移位

    void rightshift(int *arr, int N, int k) {
        K 
    %= N;
        Reverse(arr, 
    0, N-k-1);
        Reverse(arr, N
    -k, N-1);
        Reverse(arr, 
    0, N-1);
    }

     

    數(shù)組問(wèn)題思路:

    排序思路

    動(dòng)態(tài)規(guī)劃

    看成一個(gè)數(shù)列或向量


    2.18數(shù)組分割


    3.1字符串移位包含的問(wèn)題

    給定兩個(gè)字符串s1和s2,要求判定s2能否被s1做循環(huán)移位得到的字符串包含。例如:s1 = AABCD , s2 = CDAA,返回true. 給定s1 = ABCD 和 s2 = ACBD,返回false.

    解法1:模擬字符串移位的過(guò)程,判斷是否包含子串

    解法2:判斷s2是否為s1s1的子串即可。

    解法3:不申請(qǐng)空間,模擬判斷s2是否為s1s1子串的過(guò)程。

    思路:字符串可以抽象成向量來(lái)考慮。


    3.2電話號(hào)碼對(duì)應(yīng)英語(yǔ)單詞

    類似于求冪集問(wèn)題

    解法1:迭代,用while循環(huán)模擬

    解法2:遞歸

     

    3.3計(jì)算字符串相似度
    遞歸求解

    int calStrDis(char[] strA, int pABegin, int pAEnd, 
                
    char[] strB, int pBBegin, int pBEnd) {
            
    if (pABegin > pAEnd) {
                
    if (pBBegin > pBEnd) {
                    
    return 0;
                } 
    else {
                    
    return pBEnd - pBBegin + 1;
                }
            }
            
            
    if (pBBegin > pBEnd) {
                
    if (pABegin > pAEnd) {
                    
    return 0;
                } 
    else {
                    
    return pAEnd - pABegin + 1;
                }
            }
            
            
    if (strA[pABegin] == strB[pBBegin]) {
                
    return calStrDis(strA, pABegin + 1, pAEnd, strB,
                        pBBegin 
    + 1, pBEnd);
            } 
    else {
                
    int t1 = calStrDis(strA, pABegin, pAEnd, strB, pBBegin + 1
                        pBEnd);
                
    int t2 = calStrDis(strA, pABegin + 1, pAEnd, strB, pBBegin ,
                        pBEnd);
                
    int t3 = calStrDis(strA, pABegin + 1, pAEnd, strB, pBBegin + 1 ,
                        pBEnd);
                
    return min(t1, t2, t3) + 1;
            }
        }
    遞歸優(yōu)化,如何存儲(chǔ)子問(wèn)題的解?

    3.4從無(wú)頭鏈表中刪除節(jié)點(diǎn)
    這個(gè)問(wèn)題很無(wú)恥

    3.5最短摘要生成
    有空再看

    3.6編程判斷兩個(gè)鏈表是否相交
    轉(zhuǎn)化成鏈表是否有環(huán)的問(wèn)題

    3.7隊(duì)列中取最大值操作
    可分解為兩個(gè)子問(wèn)題
    子問(wèn)題1:設(shè)計(jì)一個(gè)堆棧,使入棧,出棧,取最大值的時(shí)間復(fù)雜度都是O(1)。
    思路:用空間換時(shí)間,加一個(gè)數(shù)組link2NextMaxItem[],link2NextMaxItem[i]存儲(chǔ)的是前i個(gè)元素中最大值的下標(biāo)。

    子問(wèn)題2:用上述特性的兩個(gè)堆棧實(shí)現(xiàn)一個(gè)隊(duì)列
    堆棧A負(fù)責(zé)入隊(duì),堆棧B負(fù)責(zé)出隊(duì)。當(dāng)堆棧B空的時(shí)候,將堆棧A中的數(shù)據(jù)全部彈出并壓入堆棧B

    3.8 求二叉樹結(jié)點(diǎn)之間的最大距離
    動(dòng)態(tài)規(guī)劃實(shí)現(xiàn),還是不太懂。

    3.9重建二叉樹
    遞歸求解

    3.10分層遍歷二叉樹
    隊(duì)列遍歷二叉樹+變量標(biāo)記層次

    3.11程序改錯(cuò)
    編寫正確的二分搜索程序
    C代碼:

    int BinSearch(SeqList * R, int n , KeyType K )//在有序表R[0..n-1]中進(jìn)行二分查找,成功時(shí)返回結(jié)點(diǎn)的位置,失敗時(shí)返回-1
    int low=0,high=n-1,mid; //置當(dāng)前查找區(qū)間上、下界的初值
      if(R[low].key==K)
      
    {
      
    return 0
     ;
      }

      
    while(low<=high)//當(dāng)前查找區(qū)間R[low..high]非空
      mid=low+((high-low)/2);//使用 (low + high) / 2 會(huì)有整數(shù)溢出的問(wèn)題
      if(R[mid].key==K)
      
    {
      
    return mid; //查找成功返回

      }

      
    if(R[mid].key>K)
      high
    =mid-1//繼續(xù)在R[low..mid-1]中查找

      else
      low
    =mid+1; //繼續(xù)在R[mid+1..high]中查找
      }

      
    return -1; //當(dāng)low>high時(shí)表示查找區(qū)間為空,查找失敗
      }
     //BinSeareh


    Java代碼:

    public static int binarySearch(int[] srcArray, int des)
      
    {
      
    int low = 0
    ;
      
    int high = srcArray.length-1
    ;
      
    while(low <= high) 
    {
      
    int middle = (low + high)/2
    ;
      
    if(des == srcArray[middle]) 
    {
      
    return
     middle;
      }
    else if(des <srcArray[middle]) {
      high 
    = middle - 1
    ;
      }
    else {
      low 
    = middle + 1
    ;
      }

      }

      
    return -1;
      }


    4.8三角形測(cè)試用例
    測(cè)試用例的三種類型:
    正常輸入 覆蓋功能點(diǎn)
    非法輸入 值域錯(cuò)誤 類型錯(cuò)誤
    邊界值輸入 0 1 MAX MIN 

    posted @ 2010-09-29 11:10 neverend 閱讀(1251) | 評(píng)論 (0)編輯 收藏

    第1章 引言 隨著互聯(lián)網(wǎng)應(yīng)用的廣泛普及,海量數(shù)據(jù)的存儲(chǔ)和訪問(wèn)成為了系統(tǒng)設(shè)計(jì)的瓶頸問(wèn)題。對(duì)于一個(gè)大型的互聯(lián)網(wǎng)應(yīng)用,每天幾十億的PV無(wú)疑對(duì)數(shù)據(jù)庫(kù)造成了相當(dāng)高的負(fù)載。對(duì)于系統(tǒng)的穩(wěn)定性和擴(kuò)展性造成了極大的問(wèn)題。通過(guò)數(shù)據(jù)切分來(lái)提高網(wǎng)站性能,橫向擴(kuò)展數(shù)據(jù)層已經(jīng)成為架構(gòu)研發(fā)人員首選的方式。水平切分?jǐn)?shù)據(jù)庫(kù),可以降低單臺(tái)機(jī)器的負(fù)載,同時(shí)最大限度的降低了了宕機(jī)造成的損失。通過(guò)負(fù)載均衡策略,有效的降低了單臺(tái)機(jī)器的訪問(wèn)負(fù)載,降低了宕機(jī)的可能性;通過(guò)集群方案,解決了數(shù)據(jù)庫(kù)宕機(jī)帶來(lái)的單點(diǎn)數(shù)據(jù)庫(kù)不能訪問(wèn)的問(wèn)題;通過(guò)讀寫分離策略更是最大限度了提高了應(yīng)用中讀取(Read)數(shù)據(jù)的速度和并發(fā)量。目前國(guó)內(nèi)的大型互聯(lián)網(wǎng)應(yīng)用中,大量的采用了這樣的數(shù)據(jù)切分方案,Taobao,Alibaba,Tencent,它們大都實(shí)現(xiàn)了自己的分布式數(shù)據(jù)訪問(wèn)層(DDAL)。以實(shí)現(xiàn)方式和實(shí)現(xiàn)的層次來(lái)劃分,大概分為兩個(gè)層次(Java應(yīng)用為例):JDBC層的封裝,ORM框架層的實(shí)現(xiàn)。就JDBC層的直接封裝而言,現(xiàn)在國(guó)內(nèi)發(fā)展較好的一個(gè)項(xiàng)目是被稱作“變形蟲”(Amoeba)的項(xiàng)目,由阿里集團(tuán)的研究院開發(fā),現(xiàn)在仍然處于測(cè)試階段(beta版),其運(yùn)行效率和生產(chǎn)時(shí)效性有待考究。就ORM框架層的實(shí)現(xiàn)而言,比如Taobao的基于ibatis和Spring的的分布式數(shù)據(jù)訪問(wèn)層,已有多年的應(yīng)用,運(yùn)行效率和生產(chǎn)實(shí)效性得到了開發(fā)人員和用戶的肯定。本文就是以O(shè)RM框架層為基礎(chǔ)而實(shí)現(xiàn)的分布式數(shù)據(jù)訪問(wèn)層。本課題的難點(diǎn)在于分庫(kù)后,路由規(guī)則的制定和選擇以及后期的擴(kuò)展性,比如:如何做到用最少的數(shù)據(jù)遷移量,達(dá)到擴(kuò)充數(shù)據(jù)庫(kù)容量(增加機(jī)器節(jié)點(diǎn))的目的。核心問(wèn)題將圍繞數(shù)據(jù)庫(kù)分庫(kù)分表的路由規(guī)則和負(fù)載均衡策略展開。 第2章 基本原理和概念 2.1基本原理: 人類認(rèn)知問(wèn)題的過(guò)程總是這樣的:what(什么)-?why(為什么)-?how(怎么 做),接下來(lái),本文將就這三個(gè)問(wèn)題展開討論和研究: 2.1.1什么是數(shù)據(jù)切分 "Shard" 這個(gè)詞英文的意思是"碎片",而作為數(shù)據(jù)庫(kù)相關(guān)的技術(shù)用語(yǔ),似乎最早見于大型多人在線角色扮演游戲中。"Sharding" 姑且稱之為"分片"。Sharding 不是一門新技術(shù),而是一個(gè)相對(duì)簡(jiǎn)樸的軟件理念。眾所周知,MySQL 5 之后才有了數(shù)據(jù)表分區(qū)功能,那么在此之前,很多 MySQL 的潛在用戶都對(duì) MySQL 的擴(kuò)展性有所顧慮,而是否具備分區(qū)功能就成了衡量一個(gè)數(shù)據(jù)庫(kù)可擴(kuò)展性與否的一個(gè)關(guān)鍵指標(biāo)(當(dāng)然不是唯一指標(biāo))。數(shù)據(jù)庫(kù)擴(kuò)展性是一個(gè)永恒的話題,MySQL 的推廣者經(jīng)常會(huì)被問(wèn)到:如在單一數(shù)據(jù)庫(kù)上處理應(yīng)用數(shù)據(jù)捉襟見肘而需要進(jìn)行分區(qū)化之類的處理,是如何辦到的呢? 答案是:Sharding。 Sharding 不是一個(gè)某個(gè)特定數(shù)據(jù)庫(kù)軟件附屬的功能,而是在具體技術(shù)細(xì)節(jié)之上的抽象處理,是水平擴(kuò)展(Scale Out,亦或橫向擴(kuò)展、向外擴(kuò)展)的解決方案,其主要目的是為突破單節(jié)點(diǎn)數(shù)據(jù)庫(kù)服務(wù)器的 I/O 能力限制,解決數(shù)據(jù)庫(kù)擴(kuò)展性問(wèn)題。 通過(guò)一系列的切分規(guī)則將數(shù)據(jù)水平分布到不同的DB或table中,在通過(guò)相應(yīng)的DB路由 或者 table路由規(guī)則找到需要查詢的具體的DB或者table,以進(jìn)行Query操作。這里所說(shuō)的“sharding”通常是指“水平切分”, 這也是本文討論的重點(diǎn)。具體將有什么樣的切分方式呢和路由方式呢?行文至此,讀者難免有所疑問(wèn),接下來(lái)舉個(gè)簡(jiǎn)單的例子:我們針對(duì)一個(gè)Blog應(yīng)用中的日志來(lái)說(shuō)明,比如日志文章(article)表有如下字段: 面對(duì)這樣的一個(gè)表,我們?cè)鯓忧蟹帜兀吭鯓訉⑦@樣的數(shù)據(jù)分布到不同的數(shù)據(jù)庫(kù)中的表中去呢?其實(shí)分析blog的應(yīng)用,我們不難得出這樣的結(jié)論:blog的應(yīng)用中,用戶分為兩種:瀏覽者和blog的主人。瀏覽者瀏覽某個(gè)blog,實(shí)際上是在一個(gè)特定的用戶的blog下進(jìn)行瀏覽的,而blog的主人管理自己的blog,也同樣是在特定的用戶blog下進(jìn)行操作的(在自己的空間下)。所謂的特定的用戶,用數(shù)據(jù)庫(kù)的字段表示就是“user_id”。就是這個(gè)“user_id”,它就是我們需要的分庫(kù)的依據(jù)和規(guī)則的基礎(chǔ)。我們可以這樣做,將user_id為 1~10000的所有的文章信息放入DB1中的article表中,將user_id為10001~20000的所有文章信息放入DB2中的 article表中,以此類推,一直到DBn。 這樣一來(lái),文章數(shù)據(jù)就很自然的被分到了各個(gè)數(shù)據(jù)庫(kù)中,達(dá)到了數(shù)據(jù)切分的目的。接下來(lái)要解決的問(wèn)題就是怎樣找到具體的數(shù)據(jù)庫(kù)呢?其實(shí)問(wèn)題也是簡(jiǎn)單明顯的,既然分庫(kù)的時(shí)候我們用到了區(qū)分字段user_id,那么很自然,數(shù)據(jù)庫(kù)路由的過(guò)程當(dāng)然還是少不了 user_id的。考慮一下我們剛才呈現(xiàn)的blog應(yīng)用,不管是訪問(wèn)別人的blog還是管理自己的blog,總之我都要知道這個(gè)blog的用戶是誰(shuí)吧,也就是我們知道了這個(gè)blog的user_id,就利用這個(gè)user_id,利用分庫(kù)時(shí)候的規(guī)則,反過(guò)來(lái)定位具體的數(shù)據(jù)庫(kù),比如user_id是234,利用該才的規(guī)則,就應(yīng)該定位到DB1,假如user_id是12343,利用該才的規(guī)則,就應(yīng)該定位到DB2。以此類推,利用分庫(kù)的規(guī)則,反向的路由到具體的DB,這個(gè)過(guò)程我們稱之為“DB路由”。 當(dāng)然考慮到數(shù)據(jù)切分的DB設(shè)計(jì)必然是非常規(guī),不正統(tǒng)的DB設(shè)計(jì)。那么什么樣的DB設(shè)計(jì)是正統(tǒng)的DB設(shè)計(jì)呢? 我們平常規(guī)規(guī)矩矩用的基本都是。平常我們會(huì)自覺的按照范式來(lái)設(shè)計(jì)我們的數(shù)據(jù)庫(kù),負(fù)載高點(diǎn)可能考慮使用相關(guān)的Replication機(jī)制來(lái)提高讀寫的吞吐和性能,這可能已經(jīng)可以滿足很多需求,但這套機(jī)制自身的缺陷還是比較顯而易見的(下文會(huì)提及)。上面提到的“自覺的按照范式設(shè)計(jì)”。考慮到數(shù)據(jù)切分的DB設(shè)計(jì),將違背這個(gè)通常的規(guī)矩和約束,為了切分,我們不得不在數(shù)據(jù)庫(kù)的表中出現(xiàn)冗余字段,用作區(qū)分字段或者叫做分庫(kù)的標(biāo)記字段,比如上面的article的例子中的user_id這樣的字段(當(dāng)然,剛才的例子并沒有很好的體現(xiàn)出user_id的冗余性,因?yàn)閡ser_id這個(gè)字段即使就是不分庫(kù),也是要出現(xiàn)的,算是我們撿了便宜吧)。當(dāng)然冗余字段的出現(xiàn)并不只是在分庫(kù)的場(chǎng)景下才出現(xiàn)的,在很多大型應(yīng)用中,冗余也是必須的,這個(gè)涉及到高效DB的設(shè)計(jì),本文不再贅述。 2.1.2為什么要數(shù)據(jù)切分 上面對(duì)什么是數(shù)據(jù)切分做了個(gè)概要的描述和解釋,讀者可能會(huì)疑問(wèn),為什么需要數(shù)據(jù)切分呢?像 Oracle這樣成熟穩(wěn)定的數(shù)據(jù)庫(kù),足以支撐海量數(shù)據(jù)的存儲(chǔ)與查詢了?為什么還需要數(shù)據(jù)切片呢?的確,Oracle的DB確實(shí)很成熟很穩(wěn)定,但是高昂的使用費(fèi)用和高端的硬件支撐不是每一個(gè)公司能支付的起的。試想一下一年幾千萬(wàn)的使用費(fèi)用和動(dòng)輒上千萬(wàn)元的小型機(jī)作為硬件支撐,這是一般公司能支付的起的嗎?即使就是能支付的起,假如有更好的方案,有更廉價(jià)且水平擴(kuò)展性能更好的方案,我們?yōu)槭裁床贿x擇呢? 但是,事情總是不盡人意。平常我們會(huì)自覺的按照范式來(lái)設(shè)計(jì)我們的數(shù)據(jù)庫(kù),負(fù)載高點(diǎn)可能考慮使用相關(guān)的Replication機(jī)制來(lái)提高讀寫的吞吐和性能,這可能已經(jīng)可以滿足很多需求,但這套機(jī)制自身的缺陷還是比較顯而易見的。首先它的有效很依賴于讀操作的比例,Master往往會(huì)成為瓶頸所在,寫操作需要順序排隊(duì)來(lái)執(zhí)行,過(guò)載的話Master首先扛不住,Slaves的數(shù)據(jù)同步的延遲也可能比較大,而且會(huì)大大耗費(fèi)CPU的計(jì)算能力,因?yàn)閣rite操作在Master上執(zhí)行以后還是需要在每臺(tái)slave機(jī)器上都跑一次。這時(shí)候 Sharding可能會(huì)成為雞肋了。 Replication搞不定,那么為什么Sharding可以工作呢?道理很簡(jiǎn)單,因?yàn)樗梢院芎玫臄U(kuò)展。我們知道每臺(tái)機(jī)器無(wú)論配置多么好它都有自身的物理上限,所以當(dāng)我們應(yīng)用已經(jīng)能觸及或遠(yuǎn)遠(yuǎn)超出單臺(tái)機(jī)器的某個(gè)上限的時(shí)候,我們惟有尋找別的機(jī)器的幫助或者繼續(xù)升級(jí)的我們的硬件,但常見的方案還是橫向擴(kuò)展, 通過(guò)添加更多的機(jī)器來(lái)共同承擔(dān)壓力。我們還得考慮當(dāng)我們的業(yè)務(wù)邏輯不斷增長(zhǎng),我們的機(jī)器能不能通過(guò)線性增長(zhǎng)就能滿足需求?Sharding可以輕松的將計(jì)算,存儲(chǔ),I/O并行分發(fā)到多臺(tái)機(jī)器上,這樣可以充分利用多臺(tái)機(jī)器各種處理能力,同時(shí)可以避免單點(diǎn)失敗,提供系統(tǒng)的可用性,進(jìn)行很好的錯(cuò)誤隔離。 綜合以上因素,數(shù)據(jù)切分是很有必要的,且我們?cè)诖擞懻摰臄?shù)據(jù)切分也是將MySql作為背景的。基于成本的考慮,很多公司也選擇了Free且Open的MySql。對(duì)MySql有所了解的開發(fā)人員可能會(huì)知道,MySQL 5 之后才有了數(shù)據(jù)表分區(qū)功能,那么在此之前,很多 MySQL 的潛在用戶都對(duì) MySQL 的擴(kuò)展性有所顧慮,而是否具備分區(qū)功能就成了衡量一個(gè)數(shù)據(jù)庫(kù)可擴(kuò)展性與否的一個(gè)關(guān)鍵指標(biāo)(當(dāng)然不是唯一指標(biāo))。數(shù)據(jù)庫(kù)擴(kuò)展性是一個(gè)永恒的話題,MySQL 的推廣者經(jīng)常會(huì)被問(wèn)到:如在單一數(shù)據(jù)庫(kù)上處理應(yīng)用數(shù)據(jù)捉襟見肘而需要進(jìn)行分區(qū)化之類的處理,是如何辦到的呢? 答案也是Sharding,也就是我們所說(shuō)的數(shù)據(jù)切分方案。 我們用免費(fèi)的MySQL和廉價(jià)的Server甚至是PC做集群,達(dá)到小型機(jī)+大型商業(yè)DB的效果,減少大量的資金投入,降低運(yùn)營(yíng)成本,何樂而不為呢?所以,我們選擇Sharding,擁抱Sharding。 2.1.3怎么做到數(shù)據(jù)切分 說(shuō)到數(shù)據(jù)切分,再次我們講對(duì)數(shù)據(jù)切分的方法和形式進(jìn)行比較詳細(xì)的闡述和說(shuō)明。 數(shù)據(jù)切分可以是物理 上的,對(duì)數(shù)據(jù)通過(guò)一系列的切分規(guī)則將數(shù)據(jù)分布到不同的DB服務(wù)器上,通過(guò)路由規(guī)則路由訪問(wèn)特定的數(shù)據(jù)庫(kù),這樣一來(lái)每次訪問(wèn)面對(duì)的就不是單臺(tái)服務(wù)器了,而是N臺(tái)服務(wù)器,這樣就可以降低單臺(tái)機(jī)器的負(fù)載壓力。 數(shù) 據(jù)切分也可以是數(shù)據(jù)庫(kù)內(nèi)的 ,對(duì)數(shù)據(jù)通過(guò)一系列的切分規(guī)則,將數(shù)據(jù)分布到一個(gè)數(shù)據(jù)庫(kù)的不同表中,比如將article分為article_001,article_002等子表,若干個(gè)子表水平拼合有組成了邏輯上一個(gè)完整的article表,這樣做的目的其實(shí)也是很簡(jiǎn)單的。 舉個(gè)例子說(shuō)明,比如article表中現(xiàn)在有5000w條數(shù)據(jù),此時(shí)我們需要在這個(gè)表中增加(insert)一條新的數(shù)據(jù),insert完畢后,數(shù)據(jù)庫(kù)會(huì)針對(duì)這張表重新建立索引,5000w行數(shù)據(jù)建立索引的系統(tǒng)開銷還是不容忽視的。但是反過(guò)來(lái),假如我們將這個(gè)表分成100 個(gè)table呢,從article_001一直到article_100,5000w行數(shù)據(jù)平均下來(lái),每個(gè)子表里邊就只有50萬(wàn)行數(shù)據(jù),這時(shí)候我們向一張只有50w行數(shù)據(jù)的table中insert數(shù)據(jù)后建立索引的時(shí)間就會(huì)呈數(shù)量級(jí)的下降,極大了提高了DB的運(yùn)行時(shí)效率,提高了DB的并發(fā)量。當(dāng)然分表的好處還不知這些,還有諸如寫操作的鎖操作等,都會(huì)帶來(lái)很多顯然的好處。 綜上,分庫(kù)降低了單點(diǎn)機(jī)器的負(fù)載;分表,提高了數(shù)據(jù)操作的效率,尤其是Write操作的效率。 行文至此我們依然沒有涉及到如何切分的問(wèn)題。接下來(lái),我們將對(duì)切分規(guī)則進(jìn)行詳盡的闡述和說(shuō)明。 上文中提到,要想做到數(shù)據(jù)的水平切分,在每一個(gè)表中都要有相冗余字符 作為切分依據(jù)和標(biāo)記字段,通常的應(yīng)用中我們選用user_id作為區(qū)分字段,基于此就有如下三種分庫(kù)的方式和規(guī)則: (當(dāng)然還可以有其他的方式) 按號(hào)段分: (1) user_id為區(qū)分,1~1000的對(duì)應(yīng)DB1,1001~2000的對(duì)應(yīng)DB2,以此類推; 優(yōu)點(diǎn):可部分遷移 缺點(diǎn):數(shù)據(jù)分布不均 (2)hash取模分: 對(duì)user_id進(jìn)行hash(或者如果user_id是數(shù)值型的話直接使用user_id 的值也可),然后用一個(gè)特定的數(shù)字,比如應(yīng)用中需要將一個(gè)數(shù)據(jù)庫(kù)切分成4個(gè)數(shù)據(jù)庫(kù)的話,我們就用4這個(gè)數(shù)字對(duì)user_id的hash值進(jìn)行取模運(yùn)算,也就是user_id%4,這樣的話每次運(yùn)算就有四種可能:結(jié)果為1的時(shí)候?qū)?yīng)DB1;結(jié)果為2的時(shí)候?qū)?yīng)DB2;結(jié)果為3的時(shí)候?qū)?yīng)DB3;結(jié)果為0的時(shí)候?qū)?yīng)DB4,這樣一來(lái)就非常均勻的將數(shù)據(jù)分配到4個(gè)DB中。 優(yōu)點(diǎn):數(shù)據(jù)分布均勻 缺點(diǎn):數(shù)據(jù)遷移的時(shí)候麻煩,不能按照機(jī)器性能分?jǐn)倲?shù)據(jù) (3)在認(rèn)證庫(kù)中保存數(shù)據(jù)庫(kù)配置 就是建立一個(gè)DB,這個(gè)DB單獨(dú)保存user_id到DB的映射關(guān)系,每次訪問(wèn)數(shù)據(jù)庫(kù)的時(shí)候都要先查詢一次這個(gè)數(shù)據(jù)庫(kù),以得到具體的DB信息,然后才能進(jìn)行我們需要的查詢操作。 優(yōu)點(diǎn):靈活性強(qiáng),一對(duì)一關(guān)系 缺點(diǎn):每次查詢之前都要多一次查詢,性能大打折扣 以上就是通常的開發(fā)中我們選擇的三種方式,有些復(fù)雜的項(xiàng)目中可能會(huì)混合使用這三種方式。 通過(guò)上面的描述,我們對(duì)分庫(kù)的規(guī)則也有了簡(jiǎn)單的認(rèn)識(shí)和了解。當(dāng)然還會(huì)有更好更完善的分庫(kù)方式,還需要我們不斷的探索和發(fā)現(xiàn)。 第3章 本課題研究的基本輪廓 上面的文字,我們按照人類認(rèn)知事物的規(guī)律,what?why?how這樣的方式闡述了數(shù)據(jù)庫(kù)切分的一些概念和意義以及對(duì)一些常規(guī)的切分規(guī)則做了概要的介紹。本課題所討論的分布數(shù)據(jù)層并不僅僅如此,它是一個(gè)完整的數(shù)據(jù)層解決方案,它到底是什么樣的呢?接下來(lái)的文字,我將詳細(xì)闡述本研究課題的完整思想和實(shí)現(xiàn)方式。 分布式數(shù)據(jù)方案提供功能如下: (1)提供分庫(kù)規(guī)則和路由規(guī)則(RouteRule簡(jiǎn)稱RR),將上面的說(shuō)明中提到的三中切分規(guī)則直接內(nèi)嵌入本系統(tǒng),具體的嵌入方式在接下來(lái)的內(nèi)容中進(jìn)行詳細(xì)的說(shuō)明和論述; (2)引入集群(Group)的概念,保證數(shù)據(jù)的高可用性; (3)引入負(fù)載均衡策略(LoadBalancePolicy簡(jiǎn)稱LB); (4)引入集群節(jié)點(diǎn)可用性探測(cè)機(jī)制,對(duì)單點(diǎn)機(jī)器的可用性進(jìn)行定時(shí)的偵測(cè),以保證LB策略的正確實(shí)施,以確保系統(tǒng)的高度穩(wěn)定性; (5)引入讀/寫分離,提高數(shù)據(jù)的查詢速度; 僅僅是分庫(kù)分表的數(shù)據(jù)層設(shè)計(jì)也是不夠完善的,當(dāng)某個(gè)節(jié)點(diǎn)上的DB服務(wù)器出現(xiàn)了宕機(jī)的情況的時(shí)候,會(huì)是什么樣的呢?是的,我們采用了數(shù)據(jù)庫(kù)切分方案,也就是說(shuō)有N太機(jī)器組成了一個(gè)完整的DB ,如果有一臺(tái)機(jī)器宕機(jī)的話,也僅僅是一個(gè)DB的N分之一的數(shù)據(jù)不能訪問(wèn)而已,這是我們能接受的,起碼比切分之前的情況好很多了,總不至于整個(gè)DB都不能訪問(wèn)。一般的應(yīng)用中,這樣的機(jī)器故障導(dǎo)致的數(shù)據(jù)無(wú)法訪問(wèn)是可以接受的,假設(shè)我們的系統(tǒng)是一個(gè)高并發(fā)的電子商務(wù)網(wǎng)站呢?單節(jié)點(diǎn)機(jī)器宕機(jī)帶來(lái)的經(jīng)濟(jì)損失是非常嚴(yán)重的。也就是說(shuō),現(xiàn)在我們這樣的方案還是存在問(wèn)題的,容錯(cuò)性能是經(jīng)不起考驗(yàn)的。當(dāng)然了,問(wèn)題總是有解決方案的。我們引入集群的概念,在此我稱之為Group,也就是每一個(gè)分庫(kù)的節(jié)點(diǎn)我們引入多臺(tái)機(jī)器,每臺(tái)機(jī)器保存的數(shù)據(jù)是一樣的,一般情況下這多臺(tái)機(jī)器分?jǐn)傌?fù)載,當(dāng)出現(xiàn)宕機(jī)情況,負(fù)載均衡器將分配負(fù)載給這臺(tái)宕機(jī)的機(jī)器。這樣一來(lái), 就解決了容錯(cuò)性的問(wèn)題。所以我們引入了集群的概念,并將其內(nèi)嵌入我們的框架中,成為框架的一部分。 如上圖所示,整個(gè)數(shù)據(jù)層有Group1,Group2,Group3三個(gè)集群組成,這三個(gè)集群就是數(shù)據(jù)水平切分的結(jié)果,當(dāng)然這三個(gè)集群也就組成了一個(gè)包含完整數(shù)據(jù)的DB。每一個(gè)Group包括1個(gè)Master(當(dāng)然Master也可以是多個(gè))和 N個(gè)Slave,這些Master和Slave的數(shù)據(jù)是一致的。比如Group1中的一個(gè)slave發(fā)生了宕機(jī)現(xiàn)象,那么還有兩個(gè)slave是可以用的,這樣的模型總是不會(huì)造成某部分?jǐn)?shù)據(jù)不能訪問(wèn)的問(wèn)題,除非整個(gè) Group里的機(jī)器全部宕掉,但是考慮到這樣的事情發(fā)生的概率非常小(除非是斷電了,否則不易發(fā)生吧)。 在沒有引入集群以前,我們的一次查詢的過(guò)程大致如下:請(qǐng)求數(shù)據(jù)層,并傳遞必要的分庫(kù)區(qū)分字段(通常情況下是user_id)?數(shù)據(jù)層根據(jù)區(qū)分字段Route到具體的DB?在這個(gè)確定的DB內(nèi)進(jìn)行數(shù)據(jù)操作。 這是沒有引入集群的情況,當(dāng)時(shí)引入集群會(huì)是什么樣子的呢?看圖一即可得知,我們的路由器上規(guī)則和策略其實(shí)只能路由到具體的Group,也就是只能路由到一個(gè)虛擬的Group,這個(gè)Group并不是某個(gè)特定的物理服務(wù)器。接下來(lái)需要做的工作就是找到具體的物理的DB服務(wù)器,以進(jìn)行具體的數(shù)據(jù)操作。基于這個(gè)環(huán)節(jié)的需求,我們引入了負(fù)載均衡器的概念(LB)。負(fù)載均衡器的職責(zé)就是定位到一臺(tái)具體的DB服務(wù)器。具體的規(guī)則如下:負(fù)載均衡器會(huì)分析當(dāng)前sql的讀寫特性,如果是寫操作或者是要求實(shí)時(shí)性很強(qiáng)的操作的話,直接將查詢負(fù)載分到Master,如果是讀操作則通過(guò)負(fù)載均衡策略分配一個(gè)Slave。我們的負(fù)載均衡器的主要研究放向也就是負(fù)載分發(fā)策略,通常情況下負(fù)載均衡包括隨機(jī)負(fù)載均衡和加權(quán)負(fù)載均衡 。 隨機(jī)負(fù)載均衡很好理解,就是從N個(gè)Slave中隨機(jī)選取一個(gè)Slave。這樣的隨機(jī)負(fù)載均衡是不考慮機(jī)器性能的,它默認(rèn)為每臺(tái)機(jī)器的性能是一樣的。假如真實(shí)的情況是這樣的,這樣做也是無(wú)可厚非的。假如實(shí)際情況并非如此呢?每個(gè)Slave的機(jī)器物理性能和配置不一樣的情況,再使用隨機(jī)的不考慮性能的負(fù)載均衡,是非常不科學(xué)的,這樣一來(lái)會(huì)給機(jī)器性能差的機(jī)器帶來(lái)不必要的高負(fù)載,甚至帶來(lái)宕機(jī)的危險(xiǎn), 同時(shí)高性能的數(shù)據(jù)庫(kù)服務(wù)器也不能充分發(fā)揮其物理性能。基于此考慮從,我們引入了加權(quán)負(fù)載均衡,也就是在我們的系統(tǒng)內(nèi)部通過(guò)一定的接口,可以給每臺(tái)DB服務(wù)器分配一個(gè)權(quán)值,然后再運(yùn)行時(shí)LB根據(jù)權(quán)值在集群中的比重,分配一定比例的負(fù)載給該DB服務(wù)器。當(dāng)然這樣的概念的引入,無(wú)疑增大了系統(tǒng)的復(fù)雜性和可維護(hù)性。有得必有失,我們也沒有辦法逃過(guò)的。 有了分庫(kù),有了集群,有了負(fù)載均衡器,是不是就萬(wàn)事大吉了呢? 事情遠(yuǎn)沒有我們想象的那么簡(jiǎn)單。雖然有了這些東西,基本上能保證我們的數(shù)據(jù)層可以承受很大的壓力 ,但是這樣的設(shè)計(jì)并不能完全規(guī)避數(shù)據(jù)庫(kù)宕機(jī)的危害。假如Group1中的slave2 宕機(jī)了,那么系統(tǒng)的LB并不能得知,這樣的話其實(shí)是很危險(xiǎn)的,因?yàn)長(zhǎng)B不知道,它還會(huì)以為slave2為可用狀態(tài),所以還是會(huì)給slave2分配負(fù)載。這樣一來(lái),問(wèn)題就出來(lái)了,客戶端很自然的就會(huì)發(fā)生數(shù)據(jù)操作失敗的錯(cuò)誤或者異常。這樣是非常不友好的!怎樣解決這樣的問(wèn)題呢? 我們引入集群節(jié)點(diǎn)的可用性探測(cè)機(jī)制 ,或者是可用性的數(shù)據(jù)推送機(jī)制 。這兩種機(jī)制有什么不同呢?首先說(shuō)探測(cè)機(jī)制吧,顧名思義,探測(cè)即使,就是我的數(shù)據(jù)層客戶端,不定時(shí)對(duì)集群中各個(gè)數(shù)據(jù)庫(kù)進(jìn)行可用性的嘗試,實(shí)現(xiàn)原理就是嘗試性鏈接,或者數(shù)據(jù)庫(kù)端口的嘗試性訪問(wèn),都可以做到,當(dāng)然也可以用JDBC嘗試性鏈接,利用Java的Exception機(jī)制進(jìn)行可用性的判斷,具體的會(huì)在后面的文字中提到。那數(shù)據(jù)推送機(jī)制又是什么呢?其實(shí)這個(gè)就要放在現(xiàn)實(shí)的應(yīng)用場(chǎng)景中來(lái)討論這個(gè)問(wèn)題了,一般情況下應(yīng)用的DB 數(shù)據(jù)庫(kù)宕機(jī)的話我相信DBA肯定是知道的,這個(gè)時(shí)候DBA手動(dòng)的將數(shù)據(jù)庫(kù)的當(dāng)前狀態(tài)通過(guò)程序的方式推送到客戶端,也就是分布式數(shù)據(jù)層的應(yīng)用端,這個(gè)時(shí)候在更新一個(gè)本地的DB狀態(tài)的列表。并告知LB,這個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn)不能使用,請(qǐng)不要給它分配負(fù)載。一個(gè)是主動(dòng)的監(jiān)聽機(jī)制,一個(gè)是被動(dòng)的被告知的機(jī)制。兩者各有所長(zhǎng)。但是都可以達(dá)到同樣的效果。這樣一來(lái)剛才假設(shè)的問(wèn)題就不會(huì)發(fā)生了,即使就是發(fā)生了,那么發(fā)生的概率也會(huì)降到最低。 上面的文字中提到的Master和Slave ,我們并沒有做太多深入的講解。如圖一所示,一個(gè)Group由1個(gè)Master和N個(gè)Slave組成。為什么這么做呢?其中Master負(fù)責(zé)寫操作的負(fù)載,也就是說(shuō)一切寫的操作都在Master上進(jìn)行,而讀的操作則分?jǐn)偟絊lave上進(jìn)行。這樣一來(lái)的可以大大提高讀取的效率。在一般的互聯(lián)網(wǎng)應(yīng)用中,經(jīng)過(guò)一些數(shù)據(jù)調(diào)查得出結(jié)論,讀/寫的比例大概在 10:1左右 ,也就是說(shuō)大量的數(shù)據(jù)操作是集中在讀的操作,這也就是為什么我們會(huì)有多個(gè)Slave的原因。但是為什么要分離讀和寫呢?熟悉DB的研發(fā)人員都知道,寫操作涉及到鎖的問(wèn)題,不管是行鎖還是表鎖還是塊鎖,都是比較降低系統(tǒng)執(zhí)行效率的事情。我們這樣的分離是把寫操作集中在一個(gè)節(jié)點(diǎn)上,而讀操作其其他的N個(gè)節(jié)點(diǎn)上進(jìn)行,從另一個(gè)方面有效的提高了讀的效率,保證了系統(tǒng)的高可用性。讀寫分離也會(huì)引入新的問(wèn)題,比如我的Master上的數(shù)據(jù)怎樣和集群中其他的Slave機(jī)器保持?jǐn)?shù)據(jù)的同步和一致呢?這個(gè)是我們不需要過(guò)多的關(guān)注的問(wèn)題,MySql的Proxy機(jī)制可以幫助我們做到這點(diǎn),由于Proxy機(jī)制與本課題相關(guān)性不是太強(qiáng), 在這里不做詳細(xì)介紹。 綜上所述,本課題中所研究的分布式數(shù)據(jù)層的大體功能就是如此。以上是對(duì)基本原理的一些討論和闡述。接下來(lái)就系統(tǒng)設(shè)計(jì)層面,進(jìn)行深入的剖析和研究。 第4章 系統(tǒng)設(shè)計(jì) 4.1系統(tǒng)實(shí)現(xiàn)層面的選擇 在引言部分中提到,該系統(tǒng)的實(shí)現(xiàn)層面有兩種選擇,一種是基于JDBC層面上的選擇,一種是基于現(xiàn)有數(shù)據(jù)持久層框架層面上的選擇,比如Hibernate,ibatis。兩種層面各有長(zhǎng)處,也各有不足之處。基于JDBC層面上的系統(tǒng)實(shí)現(xiàn),系統(tǒng)開發(fā)難度和后期的使用難度都將大大提高。大大增加了系統(tǒng)的開發(fā)費(fèi)用和維護(hù)費(fèi)用。本課題的定位是在成型的ibatis持久層框架的基礎(chǔ)上進(jìn)行上層的封裝,而不是對(duì)ibatis源碼的直接修改,這樣一來(lái)使本系統(tǒng)不會(huì)對(duì)現(xiàn)有框架有太多的侵入性,從而也增加了使用的靈活性。之所以選擇ibatis,原因如下: (1)ibatis的學(xué)習(xí)成本非常低,熟練的Java Programmer可在非常的短時(shí)間內(nèi)熟練使用ibatis; (2)ibatis是輕量級(jí)的ORM,只是簡(jiǎn)單的完成了RO,OR的映射,其查詢語(yǔ)句也是通過(guò)配置文件sql-map.xml文件在原生sql的層面進(jìn)行簡(jiǎn)單的配置,也就是說(shuō)我們沒有引入諸如Hibernate那樣的HQL的概念,從而增強(qiáng)了 sql的可控性,優(yōu)秀的DBA可以很好的從sql的層面對(duì)sql進(jìn)行優(yōu)化,使數(shù)據(jù)層的應(yīng)用有很強(qiáng)的可控性。Hibernate雖然很強(qiáng)大,但是由于 Hibernate是OR的一個(gè)重型封裝,且引入HQL的概念,不便于DBA團(tuán)隊(duì)對(duì)sql語(yǔ)句的控制和性能的調(diào)優(yōu)。 基于以上兩點(diǎn)理由,本課題在ORM的產(chǎn)品的選擇上選擇了易學(xué)易用且輕量級(jí)的持久層框架ibatis。下面的討論也都是特定于ibatis的基礎(chǔ)上的討論。 4.2其他開源框架的選擇 在一些大型的Java應(yīng)用中,我們通常會(huì)采用Spring這樣的開源框架,尤其是 IoC(DI)這部分,有效的幫助開發(fā)人員管理對(duì)象的依賴關(guān)系和層次,降低系統(tǒng)各層次之間的實(shí)體耦合。Spring的優(yōu)點(diǎn)和用處我相信這是開發(fā)人員眾所周知的,在此不再贅述。本課題的數(shù)據(jù)層也將采用Spring做為IoC(DI)的框架。 4.3系統(tǒng)開發(fā)技術(shù)和工具介紹 開發(fā)語(yǔ)言:Java JDK1.5 集成開發(fā)環(huán)境:Eclipse 3.3.4 Web環(huán)境下測(cè)試服務(wù)器:JBoss 4.2 構(gòu)建工具:淘寶自行研發(fā)的構(gòu)建工具Antx(類似于Maven),當(dāng)然也可以用Maven 依賴的開源Jar:Spring2.0,ibaits,commons-configuration(讀取配置文件),log4j,junit等 第5章 系統(tǒng)分析(待續(xù)。。) 閱讀全文
    類別:默認(rèn)分類 查看評(píng)論
    posted @ 2010-09-29 10:55 neverend 閱讀(169) | 評(píng)論 (0)編輯 收藏

    僅列出標(biāo)題
    共3頁(yè): 上一頁(yè) 1 2 3 下一頁(yè) 
    主站蜘蛛池模板: 国产三级在线观看免费| 日韩一品在线播放视频一品免费| 成熟女人牲交片免费观看视频| 亚洲精品国产自在久久| 久久亚洲春色中文字幕久久久| 亚洲av色香蕉一区二区三区蜜桃| 最近2019中文免费字幕在线观看 | 成人免费午夜无码视频| 亚洲国产成人精品91久久久 | 18gay台湾男同亚洲男同| 亚洲AⅤ男人的天堂在线观看| 国产情侣久久久久aⅴ免费| 午夜神器成在线人成在线人免费| 国产亚洲美女精品久久久2020 | 亚洲中文字幕无码av| 72pao国产成视频永久免费| 福利免费观看午夜体检区| 黑人大战亚洲人精品一区| 亚洲欧美黑人猛交群| 久久免费视频99| 亚洲av区一区二区三| 亚洲国产成人九九综合| 免费人成激情视频在线观看冫 | 欧美三级在线电影免费| 国产成人精品日本亚洲| 免费在线观看亚洲| 美女被免费喷白浆视频| 久久亚洲精品视频| 免费又黄又爽又猛大片午夜 | 亚洲人成激情在线播放| 国产又黄又爽胸又大免费视频| 日本免费高清一本视频| 亚洲视频在线不卡| 女人隐私秘视频黄www免费| 国产精品免费看久久久久| 亚洲成人黄色在线| 免费播放在线日本感人片| 亚洲精品tv久久久久| 亚洲狠狠婷婷综合久久| 亚洲最大免费视频网| 亚洲av无码专区国产乱码在线观看|