posts - 110, comments - 101, trackbacks - 0, articles - 7
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

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

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

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

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

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

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

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

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


           

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

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


           

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

                 為此,引入了“虛擬節(jié)點”的概念:即把想象在這個環(huán)上有很多“虛擬節(jié)點”,數(shù)據(jù)的存儲是沿著環(huán)的順時針方向找一個虛擬節(jié)點,每個虛擬節(jié)點都會關(guān)聯(lián)到一個真實節(jié)點,如下圖所使用:


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

           

          Java實現(xiàn):

          1. public class Shard<S> { // S類封裝了機器節(jié)點的信息 ,如name、password、ip、port等   
          2.   
          3.     private TreeMap<Long, S> nodes; // 虛擬節(jié)點   
          4.     private List<S> shards; // 真實機器節(jié)點   
          5.     private final int NODE_NUM = 100// 每個機器節(jié)點關(guān)聯(lián)的虛擬節(jié)點個數(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) { // 每個真實機器節(jié)點都需要關(guān)聯(lián)虛擬節(jié)點   
          16.             final S shardInfo = shards.get(i);  
          17.   
          18.             for (int n = 0; n < NODE_NUM; n++)  
          19.                 // 一個真實機器節(jié)點關(guān)聯(lián)NODE_NUM個虛擬節(jié)點   
          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)的順時針找到一個虛擬節(jié)點   
          27.         if (tail.size() == 0) {  
          28.             return nodes.get(nodes.firstKey());  
          29.         }  
          30.         return tail.get(tail.firstKey()); // 返回該虛擬節(jié)點對應(yīng)的真實機器節(jié)點的信息   
          31.     }  
          32.   
          33.     /** 
          34.      *  MurMurHash算法,是非加密HASH算法,性能很高, 
          35.      *  比傳統(tǒng)的CRC32,MD5,SHA-1(這兩個算法都是加密HASH算法,復雜度本身就很高,帶來的性能上的損害也不可避免) 
          36.      *  等HASH算法要快很多,而且據(jù)說這個算法的碰撞率很低. 
          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 云云 閱讀(48863) | 評論 (5)編輯 收藏

          這兩天公司MQ出現(xiàn)一個怪現(xiàn)象,有三臺MQ server 其中一臺死掉后
          consumer不會到其它兩臺消費,這個問題后來發(fā)現(xiàn)是配置的問題
          在brokerURL只配置了一個brokerURL,所以容器啟動時只會建立一個連接
          當這個連接掛掉后 就只能等待這個連接重啟后才能執(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的作用 官方解釋:
          如果backup=true,并且the URIs to use for reconnect from the list provided的數(shù)量大于一個的情況下,broker將會維護著兩個連接,其中一個作為備份,在主連接出現(xiàn)故障時實現(xiàn)快速切換

          這里的故障不一定是死機 也可以是消費過慢 消息就發(fā)送到另一臺server上



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

          linkedHashMap也是map的實現(xiàn),使用Iterator遍歷的時候 最先得到的是先插入的數(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方法,當超過這個容量的時候,
          put進新的值方法返回true時,便移除該map中最老的鍵和值

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

           initialCapacity   初始容量

           loadFactor    加載因子,一般是 0.75f

           accessOrder   false 基于插入順序  true  基于訪問順序(get一個元素后,這個元素被加到最后,使用了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 云云 閱讀(1034) | 評論 (2)編輯 收藏

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

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

          hbase中最簡單的二級索引的實現(xiàn)方式是通過另外一個hbase表來實現(xiàn).
          下面通過postput方法,實現(xiàn)對表sunwg01的二級索引.

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

          對于表sunwg01來說,可以通過100,101直接訪問記錄,但是如果想要訪問mary這條記錄,則只能全表遍歷
          為了解決這個問題,創(chuàng)建了表sunwg02
          表sunwg02中的f1:k1有如下記錄
          tom 100
          mary 101

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

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

          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 云云 閱讀(1175) | 評論 (1)編輯 收藏

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





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

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

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

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




          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>
          復制代碼

          fs.checkpoint.period表示多長時間記錄一次hdfs的鏡像。默認是1小時。
          fs.checkpoint.size表示一次記錄多大的size,默認64M

          2.修改conf/hdfs-site.xml

          增加

          復制代碼
          <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>
          復制代碼

          0.0.0.0改為namenode的IP地址

          3.重啟hadoop,然后檢查是否啟動是否成功

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

          4.恢復

          制造namenode宕機的情況
          1) kill 掉namenode的進程

          [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這個目錄是存在的

           

          3)從secondarynamenode遠程拷貝namesecondary文件到namenode的namesecondary

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

          4)啟動namenode

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

          正常啟動以后,屏幕上會顯示很多l(xiāng)og,這個時候namenode就可以正常訪問了

          5)檢查

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

          hadoop fsck /

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

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

          [root@master namesecondary]# rm -rf *


          8)正式啟動namenode

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

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

           

          9)balancer

          在使用start-balancer.sh時,
          默認使用1M/S(1048576)的速度移動數(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é)果是導致job運行變得不穩(wěn)定,出現(xiàn)一些意外的長map單元,某些reduce時間處理變長(整個集群負載滿滿的情況下,外加20m/s的balance),據(jù)說淘寶的為10m/s,需要調(diào)整后實驗,看看情況如何。


          hadoop balancer -threshold 5

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

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

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

          這里面說的read既包括get,也包括scan,實際底層來看這兩個操作也是一樣的。
          我們將要討論的是,當我們從一張表讀取數(shù)據(jù)的時候hbase到底是怎么處理的。
          分二種情況來看,第一種就是表剛創(chuàng)建,所有put的數(shù)據(jù)還在memstore中,并沒有刷新到hdfs上;第二種情況是,該store已經(jīng)進行多次的flush操作,產(chǎn)生了多個storefile了。
          在具體說明兩種情況前,先考慮下表的region的問題,如果表只有一個region,那么沒有說的,肯定是要掃描這個唯一的region。假設(shè)該表有多個region,此時.META.表就派上用場了,hbase會首先根據(jù)你要掃描的數(shù)據(jù)的rowkey來判斷到底該數(shù)據(jù)放在哪個region上,該region所在服務(wù)器地址,然后把數(shù)據(jù)讀取的請求發(fā)送給該region server。好了,實際對數(shù)據(jù)訪問的任務(wù)都會放在region server上執(zhí)行,為了簡單起見,接下來的討論都是在單臺region server上對單個region的操作。
          首先來看第一種情況,表剛創(chuàng)建,所有put的數(shù)據(jù)還在memstore中,并沒有刷新到hdfs上。這個時候數(shù)據(jù)是在memstore中,并沒有storefile產(chǎn)生,理所當然,hbase要查找memstore來獲得相應(yīng)的數(shù)據(jù)。對于memstore或者storefile來說,內(nèi)存中都有關(guān)于rowkey的索引的,所以對于通過rowkey的查詢速度是非常快速的。通過查詢該索引就知道是否存在需要查看的數(shù)據(jù),已經(jīng)該數(shù)據(jù)在memstore中的位置。通過索引提供的信息就很容易找得到所需要的數(shù)據(jù)。這種情況很簡單。
          在來看第二種情況,該store已經(jīng)進行多次的flush操作,產(chǎn)生了多個storefile了。那么數(shù)據(jù)應(yīng)該從哪里查呢?所有的storefile?別忘記還有memstore。此時memstore中可能還會有沒來得及flush的數(shù)據(jù)呢。如果此時該region還有很多的文件,是不是所有的文件都需要查找呢?hbase在查找先會根據(jù)時間戳或者查詢列的信息來進行過濾,過濾掉那些肯定不含有所需數(shù)據(jù)的storefile或者memstore,盡量把我們的查詢目標范圍縮小。
          盡管縮小了,但仍可能會有多個文件需要掃描的。storefile的內(nèi)部有三維有序的,但是各個storefile之間并不是有序的。比如,storefile1中可能有rowkey為100到110的記錄,而storefile2可能有rowkey為105到115的數(shù)據(jù),storefile的rowkey的范圍很有可能有交叉。所以查詢數(shù)據(jù)的過程也不可能是對storefile的順序查找。
          hbase會首先查看每個storefile的最小的rowkey,然后按照從小到大的順序進行排序,結(jié)果放到一個隊列中,排序的算法就是按照hbase的三維順序,按照rowkey,column,ts進行排序,rowkey和column是升序,而ts是降序。
          實際上并不是所有滿足時間戳和列過濾的文件都會加到這個隊列中,hbase會首先對各個storefile中的數(shù)據(jù)進行探測,只會掃描掃描那些存在比當前查詢的rowkey大的記錄的storefile。舉例來說,我當前要查找的rowkey為108,storefile1中rowkey范圍為100~104,storefile2中rowkey的范圍為105~110,那么對于storefile1最大的rowkey為104,小于105,所以不存在比所查rowkey105大的記錄,storefile并不會被加到該隊列中。根據(jù)相同的規(guī)則,storefile2則會被添加到該隊列中。
          隊列有了,下面開始查詢數(shù)據(jù),首先通過poll取出隊列的頭storefile,會從storefile讀取一條記錄返回;接下來呢,該storefile的下條記錄并不一定是查詢結(jié)果的下一條記錄,因為隊列的比較順序是比較的每個storefile的第一條符合要求的rowkey。所以,hbase會繼續(xù)從隊列中剩下的storefile取第一條記錄,把該記錄與頭storefile的第二條記錄做比較,如果前者大,那么返回頭storefile的第二條記錄;如果后者大,則會把頭storefile放回隊列重新排序,在重新取隊列的頭storefile。然后重復上面的整個過程。這個過程比較煩,語言描述不清楚,代碼會更加清晰。
          這段代碼如下:
          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類中。
          舉個例子來說明:表sunwg01,有兩個storefile,storefile1中包括rowkey100,rowkey110;storefile2中包括rowkey104,rowkey108。我現(xiàn)在執(zhí)行scan ‘sunwg01′掃描表sunwg01中的所有的記錄。
          根據(jù)前面提到的排序規(guī)則,隊列中會有2個元素,按順序分別為storefile1,storefile2。
          1,取出storefile1中的第一條記錄rowkey100,并返回該結(jié)果
          2,取出storefile1中的下一條記錄rowkey110,同時取出隊列剩余storefile的第一條記錄rowkey104,經(jīng)過比較rowkey110大于rowkey104,則將storefile1放回隊列中
          3,因為隊列是有序的隊列,會重新對storefile進行排序,因為此時storefile1的最小rowkey為110,而storefile2的最小rowkey為104,所以排序的結(jié)果為storefile2,storefile1
          4,重復上面的過程,直到查不到記錄為止。
          最后查到的結(jié)果為:rowkey100,rowkey104,rowkey108,rowkey110。
          順便說下block cache的事情,當從storefile中讀數(shù)據(jù)的時候會首先查看block cache中是否有該數(shù)據(jù),如果有則直接查block cache,就沒必要查詢hdfs;如果沒有該數(shù)據(jù),那么就只能去查hdfs了。這也是為了block cache的命中率對性能有很大影響的原因。
          上面描述了從hbase中read的基本的過程,還有些細節(jié)沒有具體說,但是大概過程應(yīng)該是都說到了。

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

          僅列出標題
          共12頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 
          主站蜘蛛池模板: 汶上县| 桐城市| 沂南县| 广宁县| 茶陵县| 乐安县| 沧源| 维西| 鄯善县| 梧州市| 泾阳县| 会理县| 阿坝县| 梁河县| 米易县| 临武县| 营口市| 科尔| 平利县| 方城县| 孟州市| 沈阳市| 铜川市| 涡阳县| 子洲县| 德化县| 微博| 余江县| 迭部县| 德惠市| 临颍县| 若尔盖县| 平阳县| 绵阳市| 澄城县| 潼关县| 军事| 星座| 陇西县| 西畴县| 嘉鱼县|