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

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

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

    我的Java路上那些事兒

    快樂(lè)成長(zhǎng)
    posts - 110, comments - 101, trackbacks - 0, articles - 7
      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    1、攔截器是基于java反射機(jī)制的,而過(guò)濾器是基于函數(shù)回調(diào)的。
    2、過(guò)濾器依賴(lài)與servlet容器,而攔截器不依賴(lài)與servlet容器。
    3、攔截器只能對(duì)Action請(qǐng)求起作用,而過(guò)濾器則可以對(duì)幾乎所有請(qǐng)求起作用。
    4、攔截器可以訪(fǎng)問(wèn)Action上下文、值棧里的對(duì)象,而過(guò)濾器不能。
    5、在Action的生命周期中,攔截器可以多次調(diào)用,而過(guò)濾器只能在容器初始化時(shí)被調(diào)用一次。

    過(guò)濾器是在java web中,你傳入的request,response提前過(guò)濾掉一些信息,或者提前設(shè)置一些參數(shù),然后再傳入servlet或者struts的 action進(jìn)行業(yè)務(wù)邏輯,
    比如過(guò)濾掉非法url(不是login.do的地址請(qǐng)求,如果用戶(hù)沒(méi)有登陸都過(guò)濾掉),
    或者在傳入servlet或者 struts的action前統(tǒng)一設(shè)置字符集,
    或者去除掉一些非法字符(聊天室經(jīng)常用到的,一些罵人的話(huà))。。。

    攔截器 可通過(guò)的是符合條件的action。 攔截器本身是一個(gè)普通的Java對(duì)象,它能動(dòng)態(tài)攔截Action調(diào)用,
    Action執(zhí)行前后執(zhí)行攔截器本身提供的各種個(gè)樣的Web項(xiàng)目需求。也可以阻止Action的執(zhí)行,同時(shí)也可以提取
    Action中可以復(fù)用的部分。
    前段時(shí)間參與一個(gè)項(xiàng)目,過(guò)濾器用的是Interceptor 覺(jué)得比以前用的Filter好用很多,現(xiàn)在拿出來(lái)比較一下
    Filter
        該過(guò)濾器的方法是創(chuàng)建一個(gè)類(lèi)XXXFilter實(shí)現(xiàn)此接口,并在該類(lèi)中的doFilter方法中聲明過(guò)濾規(guī)則,然后在配置文件web.xml中聲明他所過(guò)濾的路徑
        <filter>
            <filter-name>XXXFilter</filter-name>
            <filter-class>
                com.web.util.XXXFilter
            </filter-class>
        </filter>
       
        <filter-mapping>
            <filter-name>XXXFilter</filter-name>
            <url-pattern>*.action</url-pattern>
        </filter-mapping>
    Interceptor
         該過(guò)濾器的方法也是創(chuàng)建一個(gè)類(lèi)XXXInterceptor實(shí)現(xiàn)此接口,在該類(lèi)中intercept方法寫(xiě)過(guò)濾規(guī)則,不過(guò)它過(guò)濾路徑的方法和Filter不同,它與strut.xml結(jié)合使用,
       創(chuàng)建一個(gè)strus.xml的子配置文件struts-l99-default.xml,它繼承與struts2的struts-default,此配置文件是其他子配置文件的父類(lèi),只要是繼承與該文件的配置文件所聲明的路徑都會(huì)被它過(guò)濾 如下
     <package name="XXX-default" namespace="/" extends="struts-default">
            <interceptors>
                <interceptor name="authentication" class="com.util.XXXInterceptor" />
               
                <interceptor-stack name="user">
                    <interceptor-ref name="defaultStack" />
                    <interceptor-ref name="authentication" />
                </interceptor-stack>
                <interceptor-stack name="user-submit">
                    <interceptor-ref name="user" />
                    <interceptor-ref name="token" />
                </interceptor-stack>
                <interceptor-stack name="guest">
                    <interceptor-ref name="defaultStack" />
                </interceptor-stack>
                <interceptor-stack name="guest-submit">
                    <interceptor-ref name="defaultStack" />
                    <interceptor-ref name="token" />
                </interceptor-stack>
            </interceptors>
            <default-interceptor-ref name="user" />
       </package>
     比較一,filter基于回調(diào)函數(shù),我們需要實(shí)現(xiàn)的filter接口中doFilter方法就是回調(diào)函數(shù),而interceptor則基于java本身的反射機(jī)制,這是兩者最本質(zhì)的區(qū)別。
     比較二,filter是依賴(lài)于servlet容器的,即只能在servlet容器中執(zhí)行,很顯然沒(méi)有servlet容器就無(wú)法來(lái)回調(diào)doFilter方法。而interceptor與servlet容器無(wú)關(guān)。
     比較三,F(xiàn)ilter的過(guò)濾范圍比Interceptor大,Filter除了過(guò)濾請(qǐng)求外通過(guò)通配符可以保護(hù)頁(yè)面,圖片,文件等等,而Interceptor只能過(guò)濾請(qǐng)求。
     比較四,F(xiàn)ilter的過(guò)濾例外一般是在加載的時(shí)候在init方法聲明,而Interceptor可以通過(guò)在xml聲明是guest請(qǐng)求還是user請(qǐng)求來(lái)辨別是否過(guò)濾。
            </filter-class>
        </filter>
       
        <filter-mapping>
            <filter-name>XXXFilter</filter-name>
            <url-pattern>*.action</url-pattern>
        </filter-mapping>
    Interceptor
         該過(guò)濾器的方法也是創(chuàng)建一個(gè)類(lèi)XXXInterceptor實(shí)現(xiàn)此接口,在該類(lèi)中intercept方法寫(xiě)過(guò)濾規(guī)則,不過(guò)它過(guò)濾路徑的方法和Filter不同,它與strut.xml結(jié)合使用,
       創(chuàng)建一個(gè)strus.xml的子配置文件struts-l99-default.xml,它繼承與struts2的struts-default,此配置文件是其他子配置文件的父類(lèi),只要是繼承與該文件的配置文件所聲明的路徑都會(huì)被它過(guò)濾 如下
     <package name="XXX-default" namespace="/" extends="struts-default">
            <interceptors>
                <interceptor name="authentication" class="com.util.XXXInterceptor" />
               
                <interceptor-stack name="user">
                    <interceptor-ref name="defaultStack" />
                    <interceptor-ref name="authentication" />
                </interceptor-stack>
                <interceptor-stack name="user-submit">
                    <interceptor-ref name="user" />
                    <interceptor-ref name="token" />
                </interceptor-stack>
                <interceptor-stack name="guest">
                    <interceptor-ref name="defaultStack" />
                </interceptor-stack>
                <interceptor-stack name="guest-submit">
                    <interceptor-ref name="defaultStack" />
                    <interceptor-ref name="token" />
                </interceptor-stack>
            </interceptors>
            <default-interceptor-ref name="user" />
       </package>
     比較一,filter基于回調(diào)函數(shù),我們需要實(shí)現(xiàn)的filter接口中doFilter方法就是回調(diào)函數(shù),而interceptor則基于java本身的反射機(jī)制,這是兩者最本質(zhì)的區(qū)別。
     比較二,filter是依賴(lài)于servlet容器的,即只能在servlet容器中執(zhí)行,很顯然沒(méi)有servlet容器就無(wú)法來(lái)回調(diào)doFilter方法。而interceptor與servlet容器無(wú)關(guān)。
     比較三,F(xiàn)ilter的過(guò)濾范圍比Interceptor大,Filter除了過(guò)濾請(qǐng)求外通過(guò)通配符可以保護(hù)頁(yè)面,圖片,文件等等,而Interceptor只能過(guò)濾請(qǐng)求。
     比較四,F(xiàn)ilter的過(guò)濾例外一般是在加載的時(shí)候在init方法聲明,而Interceptor可以通過(guò)在xml聲明是guest請(qǐng)求還是user請(qǐng)求來(lái)辨別是否過(guò)濾。

    posted @ 2012-10-20 14:21 云云 閱讀(444) | 評(píng)論 (0)編輯 收藏

         摘要: java nio從1.4版本就出現(xiàn)了,而且依它優(yōu)異的性能贏得了廣大java開(kāi)發(fā)愛(ài)好者的信賴(lài)。我很納悶,為啥我到現(xiàn)在才接觸,難道我不是愛(ài)好者,難道nio不優(yōu)秀。經(jīng)過(guò)長(zhǎng)達(dá)半分鐘的思考,我意識(shí)到:時(shí)候未到。以前總是寫(xiě)那些老掉牙的web程序,唉,好不容易翻身啦,現(xiàn)在心里好受多了。因?yàn)檎娌幌胱约旱搅?0歲,還在說(shuō),我會(huì)ssh,會(huì)ssi,精通javascript,精通數(shù)據(jù)庫(kù),精通。。。人生苦短,要開(kāi)拓點(diǎn)不是嗎...  閱讀全文

    posted @ 2012-10-17 14:27 云云 閱讀(5690) | 評(píng)論 (0)編輯 收藏

      一致性哈希算法是分布式系統(tǒng)中常用的算法。比如,一個(gè)分布式的存儲(chǔ)系統(tǒng),要將數(shù)據(jù)存儲(chǔ)到具體的節(jié)點(diǎn)上,如果采用普通的hash方法,將數(shù)據(jù)映射到具體的節(jié)點(diǎn)上,如key%N,key是數(shù)據(jù)的key,N是機(jī)器節(jié)點(diǎn)數(shù),如果有一個(gè)機(jī)器加入或退出這個(gè)集群,則所有的數(shù)據(jù)映射都無(wú)效了,如果是持久化存儲(chǔ)則要做數(shù)據(jù)遷移,如果是分布式緩存,則其他緩存就失效了。

        因此,引入了一致性哈希算法:


     

    把數(shù)據(jù)用hash函數(shù)(如MD5),映射到一個(gè)很大的空間里,如圖所示。數(shù)據(jù)的存儲(chǔ)時(shí),先得到一個(gè)hash值,對(duì)應(yīng)到這個(gè)環(huán)中的每個(gè)位置,如k1對(duì)應(yīng)到了圖中所示的位置,然后沿順時(shí)針找到一個(gè)機(jī)器節(jié)點(diǎn)B,將k1存儲(chǔ)到B這個(gè)節(jié)點(diǎn)中。

    如果B節(jié)點(diǎn)宕機(jī)了,則B上的數(shù)據(jù)就會(huì)落到C節(jié)點(diǎn)上,如下圖所示:


     

    這樣,只會(huì)影響C節(jié)點(diǎn),對(duì)其他的節(jié)點(diǎn)A,D的數(shù)據(jù)不會(huì)造成影響。然而,這又會(huì)造成一個(gè)“雪崩”的情況,即C節(jié)點(diǎn)由于承擔(dān)了B節(jié)點(diǎn)的數(shù)據(jù),所以C節(jié)點(diǎn)的負(fù)載會(huì)變高,C節(jié)點(diǎn)很容易也宕機(jī),這樣依次下去,這樣造成整個(gè)集群都掛了。

           為此,引入了“虛擬節(jié)點(diǎn)”的概念:即把想象在這個(gè)環(huán)上有很多“虛擬節(jié)點(diǎn)”,數(shù)據(jù)的存儲(chǔ)是沿著環(huán)的順時(shí)針?lè)较蛘乙粋€(gè)虛擬節(jié)點(diǎn),每個(gè)虛擬節(jié)點(diǎn)都會(huì)關(guān)聯(lián)到一個(gè)真實(shí)節(jié)點(diǎn),如下圖所使用:


    圖中的A1、A2、B1、B2、C1、C2、D1、D2都是虛擬節(jié)點(diǎn),機(jī)器A負(fù)載存儲(chǔ)A1、A2的數(shù)據(jù),機(jī)器B負(fù)載存儲(chǔ)B1、B2的數(shù)據(jù),機(jī)器C負(fù)載存儲(chǔ)C1、C2的數(shù)據(jù)。由于這些虛擬節(jié)點(diǎn)數(shù)量很多,均勻分布,因此不會(huì)造成“雪崩”現(xiàn)象。

     

    Java實(shí)現(xiàn):

    1. public class Shard<S> { // S類(lèi)封裝了機(jī)器節(jié)點(diǎn)的信息 ,如name、password、ip、port等   
    2.   
    3.     private TreeMap<Long, S> nodes; // 虛擬節(jié)點(diǎn)   
    4.     private List<S> shards; // 真實(shí)機(jī)器節(jié)點(diǎn)   
    5.     private final int NODE_NUM = 100// 每個(gè)機(jī)器節(jié)點(diǎn)關(guān)聯(lián)的虛擬節(jié)點(diǎn)個(gè)數(shù)   
    6.   
    7.     public Shard(List<S> shards) {  
    8.         super();  
    9.         this.shards = shards;  
    10.         init();  
    11.     }  
    12.   
    13.     private void init() { // 初始化一致性hash環(huán)   
    14.         nodes = new TreeMap<Long, S>();  
    15.         for (int i = 0; i != shards.size(); ++i) { // 每個(gè)真實(shí)機(jī)器節(jié)點(diǎn)都需要關(guān)聯(lián)虛擬節(jié)點(diǎn)   
    16.             final S shardInfo = shards.get(i);  
    17.   
    18.             for (int n = 0; n < NODE_NUM; n++)  
    19.                 // 一個(gè)真實(shí)機(jī)器節(jié)點(diǎn)關(guān)聯(lián)NODE_NUM個(gè)虛擬節(jié)點(diǎn)   
    20.                 nodes.put(hash("SHARD-" + i + "-NODE-" + n), shardInfo);  
    21.   
    22.         }  
    23.     }  
    24.   
    25.     public S getShardInfo(String key) {  
    26.         SortedMap<Long, S> tail = nodes.tailMap(hash(key)); // 沿環(huán)的順時(shí)針找到一個(gè)虛擬節(jié)點(diǎn)   
    27.         if (tail.size() == 0) {  
    28.             return nodes.get(nodes.firstKey());  
    29.         }  
    30.         return tail.get(tail.firstKey()); // 返回該虛擬節(jié)點(diǎn)對(duì)應(yīng)的真實(shí)機(jī)器節(jié)點(diǎn)的信息   
    31.     }  
    32.   
    33.     /** 
    34.      *  MurMurHash算法,是非加密HASH算法,性能很高, 
    35.      *  比傳統(tǒng)的CRC32,MD5,SHA-1(這兩個(gè)算法都是加密HASH算法,復(fù)雜度本身就很高,帶來(lái)的性能上的損害也不可避免) 
    36.      *  等HASH算法要快很多,而且據(jù)說(shuō)這個(gè)算法的碰撞率很低. 
    37.      *  http://murmurhash.googlepages.com/ 
    38.      */  
    39.     private Long hash(String key) {  
    40.           
    41.         ByteBuffer buf = ByteBuffer.wrap(key.getBytes());  
    42.         int seed = 0x1234ABCD;  
    43.           
    44.         ByteOrder byteOrder = buf.order();  
    45.         buf.order(ByteOrder.LITTLE_ENDIAN);  
    46.   
    47.         long m = 0xc6a4a7935bd1e995L;  
    48.         int r = 47;  
    49.   
    50.         long h = seed ^ (buf.remaining() * m);  
    51.   
    52.         long k;  
    53.         while (buf.remaining() >= 8) {  
    54.             k = buf.getLong();  
    55.   
    56.             k *= m;  
    57.             k ^= k >>> r;  
    58.             k *= m;  
    59.   
    60.             h ^= k;  
    61.             h *= m;  
    62.         }  
    63.   
    64.         if (buf.remaining() > 0) {  
    65.             ByteBuffer finish = ByteBuffer.allocate(8).order(  
    66.                     ByteOrder.LITTLE_ENDIAN);  
    67.             // for big-endian version, do this first:   
    68.             // finish.position(8-buf.remaining());   
    69.             finish.put(buf).rewind();  
    70.             h ^= finish.getLong();  
    71.             h *= m;  
    72.         }  
    73.   
    74.         h ^= h >>> r;  
    75.         h *= m;  
    76.         h ^= h >>> r;  
    77.   
    78.         buf.order(byteOrder);  
    79.         return h;  
    80.     }  
    81.   
    82. }  

    posted @ 2012-10-10 11:32 云云 閱讀(48855) | 評(píng)論 (5)編輯 收藏

    這兩天公司MQ出現(xiàn)一個(gè)怪現(xiàn)象,有三臺(tái)MQ server 其中一臺(tái)死掉后
    consumer不會(huì)到其它兩臺(tái)消費(fèi),這個(gè)問(wèn)題后來(lái)發(fā)現(xiàn)是配置的問(wèn)題
    在brokerURL只配置了一個(gè)brokerURL,所以容器啟動(dòng)時(shí)只會(huì)建立一個(gè)連接
    當(dāng)這個(gè)連接掛掉后 就只能等待這個(gè)連接重啟后才能執(zhí)行。

    jms.brokerUrl=failover\:(tcp\://ip1\:61616?wireFormat.maxInactivityDurationInitalDelay\=30000,tcp\://ip2\:61616?
    wireFormat.maxInactivityDurationInitalDelay\=30000)?
    jms.useAsyncSend\=true&randomize\=true&initialReconnectDelay\=50&maxReconnectAttempts\=1&timeout\=1000&backup=true


    屬性 backup的作用 官方解釋?zhuān)?br />如果backup=true,并且the URIs to use for reconnect from the list provided的數(shù)量大于一個(gè)的情況下,broker將會(huì)維護(hù)著兩個(gè)連接,其中一個(gè)作為備份,在主連接出現(xiàn)故障時(shí)實(shí)現(xiàn)快速切換

    這里的故障不一定是死機(jī) 也可以是消費(fèi)過(guò)慢 消息就發(fā)送到另一臺(tái)server上



    posted @ 2012-09-26 16:52 云云 閱讀(6974) | 評(píng)論 (0)編輯 收藏

    linkedHashMap也是map的實(shí)現(xiàn),使用Iterator遍歷的時(shí)候 最先得到的是先插入的數(shù)據(jù)。
    保證了數(shù)據(jù)插入的順序。

    public class LRUMap<K, V> extends LinkedHashMap<K, V> {

        private static final long serialVersionUID = -3700466745992492679L;

        private int               coreSize;

        public LRUMap(int coreSize) {
            super(coreSize + 1, 1.1f, true);
            this.coreSize = coreSize;
        }

        @Override
        protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
            return size() > coreSize;
        }
    }


    覆蓋removeEldestEntry方法,當(dāng)超過(guò)這個(gè)容量的時(shí)候,
    put進(jìn)新的值方法返回true時(shí),便移除該map中最老的鍵和值

    public LinkedHashMap (int initialCapacity, float loadFactor, boolean accessOrder);

     initialCapacity   初始容量

     loadFactor    加載因子,一般是 0.75f

     accessOrder   false 基于插入順序  true  基于訪(fǎng)問(wèn)順序(get一個(gè)元素后,這個(gè)元素被加到最后,使用了LRU 最近最少被使用的調(diào)度算法)

    如 boolean accessOrder = true; 
          Map<String, String> m = new LinkedHashMap<String, String>(20, .80f,  accessOrder  );
          m.put("1", "my"));

          m.put("2", "map"));

          m.put("3", "test"));

          m.get("1");

          m.get("2");

          Log.d("tag",  m);

         若 accessOrder == true;  輸出 {3=test, 1=my, 2=map}

             accessOrder == false;  輸出 {1=my, 2=map,3=test}






    posted @ 2012-09-05 14:16 云云 閱讀(1032) | 評(píng)論 (2)編輯 收藏

    在網(wǎng)瀏覽的時(shí)候  發(fā)現(xiàn)了這篇文章  很有用  就保留了下來(lái)

    hbase不是數(shù)據(jù)庫(kù),一些數(shù)據(jù)庫(kù)中基本的功能hbase并不具備.
    二級(jí)索引就是其中很重要的一點(diǎn),在數(shù)據(jù)庫(kù)中索引是在平常不過(guò)的功能了.
    而在hbase中,value上的索引只能靠自己來(lái)實(shí)現(xiàn).

    hbase中最簡(jiǎn)單的二級(jí)索引的實(shí)現(xiàn)方式是通過(guò)另外一個(gè)hbase表來(lái)實(shí)現(xiàn).
    下面通過(guò)postput方法,實(shí)現(xiàn)對(duì)表sunwg01的二級(jí)索引.

    舉例說(shuō)下二級(jí)索引實(shí)現(xiàn):
    表sunwg01的f1:k1有如下記錄
    100 tom
    101 mary

    對(duì)于表sunwg01來(lái)說(shuō),可以通過(guò)100,101直接訪(fǎng)問(wèn)記錄,但是如果想要訪(fǎng)問(wèn)mary這條記錄,則只能全表遍歷
    為了解決這個(gè)問(wèn)題,創(chuàng)建了表sunwg02
    表sunwg02中的f1:k1有如下記錄
    tom 100
    mary 101

    現(xiàn)在如果要查找mary這條記錄,可以先查表sunwg02中,找到mary的value的為101

    下面通過(guò)postput方式實(shí)現(xiàn),在put源表的同時(shí)更新索引表的功能。
    詳細(xì)代碼如下:

    import java.io.IOException; import java.util.Iterator; import java.util.List;   import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver; import org.apache.hadoop.hbase.coprocessor.ObserverContext; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; import org.apache.hadoop.hbase.regionserver.wal.WALEdit;   public class postput_test extends BaseRegionObserver {         @Override      public void postPut(final ObserverContext<RegionCoprocessorEnvironment> e,           final Put put, final WALEdit edit, final boolean writeToWAL) throws IOException {             HTable table = new HTable("sunwg02");           List<KeyValue> kv = put.get("f1".getBytes(), "k1".getBytes());           Iterator<KeyValue> kvl = kv.iterator();             while(kvl.hasNext()) {               KeyValue tmp = kvl.next();               Put tput = new Put(tmp.getValue());               tput.add("f1".getBytes(),"k1".getBytes(),tmp.getRow());               table.put(tput);             }           table.close();       } 





    posted @ 2012-08-16 17:30 云云 閱讀(1171) | 評(píng)論 (1)編輯 收藏

    通常在項(xiàng)目中我們都會(huì)把log4j的配置放到classpath里,
    log4j的輸出路徑也就直接寫(xiě)在log4j.xml或log4j.properties中了,
    原本就這樣了不用麻煩什么了,可是在我們公司什么都要配置分離。
    所以 log4j的輸出目錄也就不再開(kāi)發(fā)人員指定了,
    那么如何做到分離呢。
    有的是直接把log4j.xml或properties文件分離,在項(xiàng)目啟動(dòng)時(shí)加載進(jìn)來(lái),
    那么這樣一來(lái) 整個(gè)log4j的配置文件都不由開(kāi)發(fā)人員控制,
    可是通常log4j的配置由運(yùn)維人員配置的東東也就一個(gè)輸出目錄了,
    而log4j的其它配置還是由開(kāi)發(fā)人員控制,
    這時(shí)可以用${},來(lái)指定
    <param name="file" value="${log4j.home}/test.log" />
    log4j.home由容器啟動(dòng)時(shí)指定,jvm中加上   -Dlog4j.home=D:/log
    這樣在Log4j.xml中的${log4j.home}就知道了實(shí)際的輸出目錄了,
    同樣也可以把這個(gè)log4j.home放到分離的properties中,這時(shí)候可以
    在容器啟動(dòng)時(shí)在監(jiān)聽(tīng)器來(lái)解析properties,獲取到log4j.home變量后
    把值設(shè)置到system.env中
    System.setProperties("log4j.home");
    這樣一來(lái) ,log4j一樣可以找到輸出目錄





    posted @ 2012-07-29 14:48 云云 閱讀(4520) | 評(píng)論 (0)編輯 收藏

     光從字面上來(lái)理解,很容易讓一些初學(xué)者先入為主的認(rèn)為:SecondaryNameNode(snn)就是NameNode(nn)的熱備進(jìn)程。其 實(shí)不是。snn是HDFS架構(gòu)中的一個(gè)組成部分,但是經(jīng)常由于名字而被人誤解它真正的用途,其實(shí)它真正的用途,是用來(lái)保存namenode中對(duì)HDFS metadata的信息的備份,并減少namenode重啟的時(shí)間。對(duì)于hadoop進(jìn)程中 ,要配置好并正確的使用 snn,還是需要做一些工作的。hadoop的默認(rèn)配置中讓 snn進(jìn)程默認(rèn)運(yùn)行在了 namenode 的那臺(tái)機(jī)器上,但是這樣的話(huà),如果這臺(tái)機(jī)器出錯(cuò),宕機(jī),對(duì)恢復(fù)HDFS文件系統(tǒng)是很大的災(zāi)難,更好的方式是:將snn的進(jìn)程配置在另外一臺(tái)機(jī)器 上運(yùn)行。
    在hadoop中,namenode負(fù)責(zé)對(duì)HDFS的metadata的持久化存儲(chǔ),并且處理來(lái)自客戶(hù)端的對(duì)HDFS的各種操作的交互反饋。為了保 證交互速度,HDFS文件系統(tǒng)的metadata是被load到namenode機(jī)器的內(nèi)存中的,并且會(huì)將內(nèi)存中的這些數(shù)據(jù)保存到磁盤(pán)進(jìn)行持久化存儲(chǔ)。為 了保證這個(gè)持久化過(guò)程不會(huì)成為HDFS操作的瓶頸,hadoop采取的方式是:沒(méi)有對(duì)任何一次的當(dāng)前文件系統(tǒng)的snapshot進(jìn)行持久化,對(duì)HDFS最 近一段時(shí)間的操作list會(huì)被保存到namenode中的一個(gè)叫Editlog的文件中去。當(dāng)重啟namenode時(shí),除了 load fsImage意外,還會(huì)對(duì)這個(gè)EditLog文件中 記錄的HDFS操作進(jìn)行replay,以恢復(fù)HDFS重啟之前的最終狀態(tài)。
    而SecondaryNameNode,會(huì)周期性的將EditLog中記錄的對(duì)HDFS的操作合并到一個(gè)checkpoint中,然后清空 EditLog。所以namenode的重啟就會(huì)Load最新的一個(gè)checkpoint,并replay EditLog中 記錄的hdfs操作,由于EditLog中記錄的是從 上一次checkpoint以后到現(xiàn)在的操作列表,所以就會(huì)比較小。如果沒(méi)有snn的這個(gè)周期性的合并過(guò)程,那么當(dāng)每次重啟namenode的時(shí)候,就會(huì) 花費(fèi)很長(zhǎng)的時(shí)間。而這樣周期性的合并就能減少重啟的時(shí)間。同時(shí)也能保證HDFS系統(tǒng)的完整性。
    這就是SecondaryNameNode所做的事情。所以snn并不能分擔(dān)namenode上對(duì)HDFS交互性操作的壓力。盡管如此,當(dāng) namenode機(jī)器宕機(jī)或者namenode進(jìn)程出問(wèn)題時(shí),namenode的daemon進(jìn)程可以通過(guò)人工的方式從snn上拷貝一份metadata 來(lái)恢復(fù)HDFS文件系統(tǒng)。
    至于為什么要將SNN進(jìn)程運(yùn)行在一臺(tái)非NameNode的 機(jī)器上,這主要出于兩點(diǎn)考慮:

    1. 可擴(kuò)展性: 創(chuàng)建一個(gè)新的HDFS的snapshot需要將namenode中l(wèi)oad到內(nèi)存的metadata信息全部拷貝一遍,這樣的操作需要的內(nèi)存就需要 和namenode占用的內(nèi)存一樣,由于分配給namenode進(jìn)程的內(nèi)存其實(shí)是對(duì)HDFS文件系統(tǒng)的限制,如果分布式文件系統(tǒng)非常的大,那么 namenode那臺(tái)機(jī)器的內(nèi)存就可能會(huì)被namenode進(jìn)程全部占據(jù)。
    2. 容錯(cuò)性: 當(dāng)snn創(chuàng)建一個(gè)checkpoint的時(shí)候,它會(huì)將checkpoint拷貝成metadata的幾個(gè)拷貝。將這個(gè)操作運(yùn)行到另外一臺(tái)機(jī)器,還可以提供分布式文件系統(tǒng)的容錯(cuò)性。

    配置將SecondaryNameNode運(yùn)行在另外一臺(tái)機(jī)器上
    HDFS的一次運(yùn)行實(shí)例是通過(guò)在namenode機(jī)器上的$HADOOP_HOME/bin/start-dfs.sh( 或者start-all.sh ) 腳本來(lái)啟動(dòng)的。這個(gè)腳本會(huì)在運(yùn)行該腳本的機(jī)器上啟動(dòng) namenode進(jìn)程,而slaves機(jī)器上都會(huì)啟動(dòng)DataNode進(jìn)程,slave機(jī)器的列表保存在 conf/slaves文件中,一行一臺(tái)機(jī)器。并且會(huì)在另外一臺(tái)機(jī)器上啟動(dòng)一個(gè)snn進(jìn)程,這臺(tái)機(jī)器由 conf/masters文件指定。所以,這里需要嚴(yán)格注意,conf/masters 文件中指定的機(jī)器,并不是說(shuō)jobtracker或者namenode進(jìn)程要 運(yùn)行在這臺(tái)機(jī)器上,因?yàn)檫@些進(jìn)程是運(yùn)行在 launch bin/start-dfs.sh或者 bin/start-mapred.sh(start-all.sh)的機(jī)器上的。所以,masters這個(gè)文件名是非常的令人混淆的,應(yīng)該叫做 secondaries會(huì)比較合適。然后,通過(guò)以下步驟:




    1.修改conf/core-site.xml

    增加

    <property> 
    <name>fs.checkpoint.period</name> 
    <value>3600</value> 
    <description>The number of seconds between two periodic checkpoints. </description> 
    </property> 
    <property> 
    <name>fs.checkpoint.size</name> 
    <value>67108864</value> 
    <description>The size of the current edit log (in bytes) that triggers a periodic checkpoint even if the fs.checkpoint.period hasn't expired. </description> 
    </property> 
    
    <property> 
    <name>fs.checkpoint.dir</name> 
    <value>/data/work/hdfs/namesecondary</value> 
    <description>Determines where on the local filesystem the DFS secondary name node should store the temporary images to merge. If this is a comma-delimited list of directories then the image is replicated in all of the directories for redundancy. </description> 
    </property>
    復(fù)制代碼

    fs.checkpoint.period表示多長(zhǎng)時(shí)間記錄一次hdfs的鏡像。默認(rèn)是1小時(shí)。
    fs.checkpoint.size表示一次記錄多大的size,默認(rèn)64M

    2.修改conf/hdfs-site.xml

    增加

    復(fù)制代碼
    <property> 
    <name>dfs.http.address</name> 
    <value>master:50070</value> 
    <description> The address and the base port where the dfs namenode web ui will listen on. If the port is 0 then the server will start on a free port. </description> 
    </property>
    復(fù)制代碼

    0.0.0.0改為namenode的IP地址

    3.重啟hadoop,然后檢查是否啟動(dòng)是否成功

    登錄secondarynamenode所在的機(jī)器,輸入jps查看secondarynamenode進(jìn)程
    進(jìn)入secondarynamenode的目錄/data/work/hdfs/namesecondary
    正確的結(jié)果:
    如果沒(méi)有,請(qǐng)耐心等待,只有到了設(shè)置的checkpoint的時(shí)間或者大小,才會(huì)生成。

    4.恢復(fù)

    制造namenode宕機(jī)的情況
    1) kill 掉namenode的進(jìn)程

    [root@master name]# jps 
    11749 NameNode 
    12339 Jps 
    11905 JobTracker 
    [root@master name]# kill 11749

     

    2)刪除dfs.name.dir所指向的文件夾,這里是/data/work/hdfs/name

    [root@master name]# rm -rf *

    刪除name目錄下的所有內(nèi)容,但是必須保證name這個(gè)目錄是存在的

     

    3)從secondarynamenode遠(yuǎn)程拷貝namesecondary文件到namenode的namesecondary

    [root@master hdfs]# scp -r slave-001:/data/work/hdfs/namesecondary/ ./

    4)啟動(dòng)namenode

    [root@master /data]# hadoop namenode –importCheckpoint

    正常啟動(dòng)以后,屏幕上會(huì)顯示很多l(xiāng)og,這個(gè)時(shí)候namenode就可以正常訪(fǎng)問(wèn)了

    5)檢查

    使用hadoop fsck /user命令檢查文件Block的完整性

    hadoop fsck /

    6)停止namenode,使用crrl+C或者會(huì)話(huà)結(jié)束

    7)刪除namesecondary目錄下的文件(保存干凈)

    [root@master namesecondary]# rm -rf *


    8)正式啟動(dòng)namenode

    [root@master bin]# ./hadoop-daemon.sh start namenode

    恢復(fù)工作完成,檢查hdfs的數(shù)據(jù)

     

    9)balancer

    在使用start-balancer.sh時(shí),
    默認(rèn)使用1M/S(1048576)的速度移動(dòng)數(shù)據(jù)(so slowly...)
    修改hdfs-site.xml配置,這里我們使用的是20m/S

    <property> 
    <name>dfs.balance.bandwidthPerSec</name> 
    <value>20971520</value> 
    <description> Specifies the maximum bandwidth that each datanode can utilize for the balancing purpose in term of the number of bytes per second. </description> 
    </property>

    然后結(jié)果是導(dǎo)致job運(yùn)行變得不穩(wěn)定,出現(xiàn)一些意外的長(zhǎng)map單元,某些reduce時(shí)間處理變長(zhǎng)(整個(gè)集群負(fù)載滿(mǎn)滿(mǎn)的情況下,外加20m/s的balance),據(jù)說(shuō)淘寶的為10m/s,需要調(diào)整后實(shí)驗(yàn),看看情況如何。


    hadoop balancer -threshold 5

    posted @ 2012-07-27 10:59 云云 閱讀(3231) | 評(píng)論 (0)編輯 收藏

    HBase提供了setCaching設(shè)置 cache數(shù)量,但是很多時(shí)候 如果設(shè)置不當(dāng),會(huì)相當(dāng)耗內(nèi)存。
    如果不設(shè)置該值,默認(rèn)是1條。如果設(shè)置該值很大,是可以加快速度,同時(shí)也消耗了太多的內(nèi)存。
    所以 合理的設(shè)置就很重要了。
    當(dāng)設(shè)置了setCaching(n)后,我們的server會(huì)從regin server上讀取出n條數(shù)據(jù)。
    那么client端讀取數(shù)據(jù)的時(shí)候會(huì)直接從server的緩存中返回,
    但是如果每次你只需要讀取100條記錄,但是設(shè)置了setCaching(1000),那么每次
    都會(huì)從region server 多余的拿出900條記錄,這樣會(huì)讓?xiě)?yīng)用的server內(nèi)存吃不消了
    比較好的解決方案就是 設(shè)置setCaching(n)為實(shí)際需要的記錄數(shù)。

    posted @ 2012-07-25 11:12 云云 閱讀(1421) | 評(píng)論 (1)編輯 收藏

    這里面說(shuō)的read既包括get,也包括scan,實(shí)際底層來(lái)看這兩個(gè)操作也是一樣的。
    我們將要討論的是,當(dāng)我們從一張表讀取數(shù)據(jù)的時(shí)候hbase到底是怎么處理的。
    分二種情況來(lái)看,第一種就是表剛創(chuàng)建,所有put的數(shù)據(jù)還在memstore中,并沒(méi)有刷新到hdfs上;第二種情況是,該store已經(jīng)進(jìn)行多次的flush操作,產(chǎn)生了多個(gè)storefile了。
    在具體說(shuō)明兩種情況前,先考慮下表的region的問(wèn)題,如果表只有一個(gè)region,那么沒(méi)有說(shuō)的,肯定是要掃描這個(gè)唯一的region。假設(shè)該表有多個(gè)region,此時(shí).META.表就派上用場(chǎng)了,hbase會(huì)首先根據(jù)你要掃描的數(shù)據(jù)的rowkey來(lái)判斷到底該數(shù)據(jù)放在哪個(gè)region上,該region所在服務(wù)器地址,然后把數(shù)據(jù)讀取的請(qǐng)求發(fā)送給該region server。好了,實(shí)際對(duì)數(shù)據(jù)訪(fǎng)問(wèn)的任務(wù)都會(huì)放在region server上執(zhí)行,為了簡(jiǎn)單起見(jiàn),接下來(lái)的討論都是在單臺(tái)region server上對(duì)單個(gè)region的操作。
    首先來(lái)看第一種情況,表剛創(chuàng)建,所有put的數(shù)據(jù)還在memstore中,并沒(méi)有刷新到hdfs上。這個(gè)時(shí)候數(shù)據(jù)是在memstore中,并沒(méi)有storefile產(chǎn)生,理所當(dāng)然,hbase要查找memstore來(lái)獲得相應(yīng)的數(shù)據(jù)。對(duì)于memstore或者storefile來(lái)說(shuō),內(nèi)存中都有關(guān)于rowkey的索引的,所以對(duì)于通過(guò)rowkey的查詢(xún)速度是非常快速的。通過(guò)查詢(xún)?cè)撍饕椭朗欠翊嬖谛枰榭吹臄?shù)據(jù),已經(jīng)該數(shù)據(jù)在memstore中的位置。通過(guò)索引提供的信息就很容易找得到所需要的數(shù)據(jù)。這種情況很簡(jiǎn)單。
    在來(lái)看第二種情況,該store已經(jīng)進(jìn)行多次的flush操作,產(chǎn)生了多個(gè)storefile了。那么數(shù)據(jù)應(yīng)該從哪里查呢?所有的storefile?別忘記還有memstore。此時(shí)memstore中可能還會(huì)有沒(méi)來(lái)得及flush的數(shù)據(jù)呢。如果此時(shí)該region還有很多的文件,是不是所有的文件都需要查找呢?hbase在查找先會(huì)根據(jù)時(shí)間戳或者查詢(xún)列的信息來(lái)進(jìn)行過(guò)濾,過(guò)濾掉那些肯定不含有所需數(shù)據(jù)的storefile或者memstore,盡量把我們的查詢(xún)目標(biāo)范圍縮小。
    盡管縮小了,但仍可能會(huì)有多個(gè)文件需要掃描的。storefile的內(nèi)部有三維有序的,但是各個(gè)storefile之間并不是有序的。比如,storefile1中可能有rowkey為100到110的記錄,而storefile2可能有rowkey為105到115的數(shù)據(jù),storefile的rowkey的范圍很有可能有交叉。所以查詢(xún)數(shù)據(jù)的過(guò)程也不可能是對(duì)storefile的順序查找。
    hbase會(huì)首先查看每個(gè)storefile的最小的rowkey,然后按照從小到大的順序進(jìn)行排序,結(jié)果放到一個(gè)隊(duì)列中,排序的算法就是按照hbase的三維順序,按照rowkey,column,ts進(jìn)行排序,rowkey和column是升序,而ts是降序。
    實(shí)際上并不是所有滿(mǎn)足時(shí)間戳和列過(guò)濾的文件都會(huì)加到這個(gè)隊(duì)列中,hbase會(huì)首先對(duì)各個(gè)storefile中的數(shù)據(jù)進(jìn)行探測(cè),只會(huì)掃描掃描那些存在比當(dāng)前查詢(xún)的rowkey大的記錄的storefile。舉例來(lái)說(shuō),我當(dāng)前要查找的rowkey為108,storefile1中rowkey范圍為100~104,storefile2中rowkey的范圍為105~110,那么對(duì)于storefile1最大的rowkey為104,小于105,所以不存在比所查rowkey105大的記錄,storefile并不會(huì)被加到該隊(duì)列中。根據(jù)相同的規(guī)則,storefile2則會(huì)被添加到該隊(duì)列中。
    隊(duì)列有了,下面開(kāi)始查詢(xún)數(shù)據(jù),首先通過(guò)poll取出隊(duì)列的頭storefile,會(huì)從storefile讀取一條記錄返回;接下來(lái)呢,該storefile的下條記錄并不一定是查詢(xún)結(jié)果的下一條記錄,因?yàn)殛?duì)列的比較順序是比較的每個(gè)storefile的第一條符合要求的rowkey。所以,hbase會(huì)繼續(xù)從隊(duì)列中剩下的storefile取第一條記錄,把該記錄與頭storefile的第二條記錄做比較,如果前者大,那么返回頭storefile的第二條記錄;如果后者大,則會(huì)把頭storefile放回隊(duì)列重新排序,在重新取隊(duì)列的頭storefile。然后重復(fù)上面的整個(gè)過(guò)程。這個(gè)過(guò)程比較煩,語(yǔ)言描述不清楚,代碼會(huì)更加清晰。
    這段代碼如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public KeyValue next()  throws IOException {
      if(this.current == null) {
        return null;
      }
      KeyValue kvReturn = this.current.next();
      KeyValue kvNext = this.current.peek();
      if (kvNext == null) {
        this.current.close();
        this.current = this.heap.poll();
      } else {
        KeyValueScanner topScanner = this.heap.peek();
        if (topScanner == null ||
            this.comparator.compare(kvNext, topScanner.peek()) >= 0) {
          this.heap.add(this.current);
          this.current = this.heap.poll();
        }
      }
      return kvReturn;
    }



    以上的代碼在KeyValueHeap.java類(lèi)中。
    舉個(gè)例子來(lái)說(shuō)明:表sunwg01,有兩個(gè)storefile,storefile1中包括rowkey100,rowkey110;storefile2中包括rowkey104,rowkey108。我現(xiàn)在執(zhí)行scan ‘sunwg01′掃描表sunwg01中的所有的記錄。
    根據(jù)前面提到的排序規(guī)則,隊(duì)列中會(huì)有2個(gè)元素,按順序分別為storefile1,storefile2。
    1,取出storefile1中的第一條記錄rowkey100,并返回該結(jié)果
    2,取出storefile1中的下一條記錄rowkey110,同時(shí)取出隊(duì)列剩余storefile的第一條記錄rowkey104,經(jīng)過(guò)比較rowkey110大于rowkey104,則將storefile1放回隊(duì)列中
    3,因?yàn)殛?duì)列是有序的隊(duì)列,會(huì)重新對(duì)storefile進(jìn)行排序,因?yàn)榇藭r(shí)storefile1的最小rowkey為110,而storefile2的最小rowkey為104,所以排序的結(jié)果為storefile2,storefile1
    4,重復(fù)上面的過(guò)程,直到查不到記錄為止。
    最后查到的結(jié)果為:rowkey100,rowkey104,rowkey108,rowkey110。
    順便說(shuō)下block cache的事情,當(dāng)從storefile中讀數(shù)據(jù)的時(shí)候會(huì)首先查看block cache中是否有該數(shù)據(jù),如果有則直接查block cache,就沒(méi)必要查詢(xún)hdfs;如果沒(méi)有該數(shù)據(jù),那么就只能去查hdfs了。這也是為了block cache的命中率對(duì)性能有很大影響的原因。
    上面描述了從hbase中read的基本的過(guò)程,還有些細(xì)節(jié)沒(méi)有具體說(shuō),但是大概過(guò)程應(yīng)該是都說(shuō)到了。

    posted @ 2012-07-18 18:04 云云 閱讀(2931) | 評(píng)論 (0)編輯 收藏

    僅列出標(biāo)題
    共12頁(yè): 上一頁(yè) 1 2 3 4 5 6 7 8 9 下一頁(yè) Last 
    主站蜘蛛池模板: 午夜不卡久久精品无码免费| 2022免费国产精品福利在线| 亚洲av乱码一区二区三区按摩| 亚洲国产精品无码久久久秋霞1| 久久精品国产亚洲AV未满十八| 边摸边吃奶边做爽免费视频网站| www成人免费视频| 国产猛男猛女超爽免费视频| 蜜桃AV无码免费看永久| 无码高潮少妇毛多水多水免费| 日日操夜夜操免费视频 | 国产免费阿v精品视频网址| 99精品视频在线观看免费专区 | 麻豆一区二区免费播放网站| 无码国产精品一区二区免费虚拟VR | 亚洲国产精品久久丫| 亚洲国产激情在线一区| 亚洲欧美aⅴ在线资源| 精品亚洲成a人在线观看| 一级女性全黄生活片免费看| 成人免费一区二区三区| 先锋影音资源片午夜在线观看视频免费播放| 叮咚影视在线观看免费完整版 | 亚洲av成人一区二区三区在线播放| 国产天堂亚洲精品| 一级毛片免费在线| 日本免费电影一区二区| 亚洲一级毛片免费在线观看| 成人毛片免费观看视频大全| 国产又黄又爽又刺激的免费网址| 亚洲精品国产福利一二区| 亚洲精品国产字幕久久不卡 | 欧美在线看片A免费观看| 免费高清资源黄网站在线观看| 免费va在线观看| 国产AV无码专区亚洲精品| 亚洲成AV人在线观看天堂无码| 亚洲精品国产免费| 亚洲AV无码AV男人的天堂不卡| 一级毛片在线免费视频| 99精品免费观看|