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

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

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

    Chan Chen Coding...

    2014年2月14日 #

    SPARK環境搭建-WINDOWS版本

    轉載: Spark環境搭建-WIndows版本

    這段時間在看Scala語言方面的資料,接觸到了Spark,于是昨天下午在公司,把Spark的環境搭建起來了。安裝的時候陪到了一個問題,在網上沒有找到解決方案,于是自己查了一下原因。現在做一下筆記。

    1. spark的下載文件可以在官方找到,地址:http://spark.incubator.apache.org/downloads.html ,這次裝的是截至目前為止,最新的版本:0.9

    2. 下載完以后,直接解壓到指定的路徑,例如,d:/programs

    3. 安裝scala,并制定Scala_Home路徑,scala安裝請查看官網

    4. 按照Spark官方的安裝指南,在解壓的目錄下,運行

    sbt/sbt package

    命令就可以。

    但是這是針對linux和OS X系統的,在windows下運行這條命令,會報錯:

    not a valid command

    這個問題是因為,spark知道的sbt腳本無法在windows下運行,只要在網上下載一個windows版本的sbt,然后將里面的文件拷貝到Spark目錄下的sbt (http://www.scala-sbt.org/),然后在運行命令,安裝就會成功。

     
    試試spark-shell
     1 scala> val textFile = sc.textFile("README.md")
     2 14/02/14 16:38:12 INFO MemoryStore: ensureFreeSpace(35480) called with curMem=177376, maxMem=308713881
     3 14/02/14 16:38:12 INFO MemoryStore: Block broadcast_5 stored as values to memory (estimated size 34.6 KB, free 294.2 MB)
     4 
     5 textFile: org.apache.spark.rdd.RDD[String] = MappedRDD[16] at textFile at <console>:12
     6 
     7 scala> textFile.count
     8 14/02/14 16:38:14 INFO FileInputFormat: Total input paths to process : 1
     9 14/02/14 16:38:14 INFO SparkContext: Starting job: count at <console>:15
    10 14/02/14 16:38:14 INFO DAGScheduler: Got job 7 (count at <console>:15) with 1 output partitions (allowLocal=false)
    11 14/02/14 16:38:14 INFO DAGScheduler: Final stage: Stage 7 (count at <console>:15)
    12 14/02/14 16:38:14 INFO DAGScheduler: Parents of final stage: List()
    13 14/02/14 16:38:14 INFO DAGScheduler: Missing parents: List()
    14 14/02/14 16:38:14 INFO DAGScheduler: Submitting Stage 7 (MappedRDD[16] at textFile at <console>:12), which has no missin
    15 g parents
    16 14/02/14 16:38:14 INFO DAGScheduler: Submitting 1 missing tasks from Stage 7 (MappedRDD[16] at textFile at <console>:12)
    17 
    18 14/02/14 16:38:14 INFO TaskSchedulerImpl: Adding task set 7.0 with 1 tasks
    19 14/02/14 16:38:14 INFO TaskSetManager: Starting task 7.0:0 as TID 5 on executor localhost: localhost (PROCESS_LOCAL)
    20 14/02/14 16:38:14 INFO TaskSetManager: Serialized task 7.0:0 as 1560 bytes in 1 ms
    21 14/02/14 16:38:14 INFO Executor: Running task ID 5
    22 14/02/14 16:38:14 INFO BlockManager: Found block broadcast_5 locally
    23 14/02/14 16:38:14 INFO HadoopRDD: Input split: file:/D:/program/spark-0.9.0-incubating/README.md:0+4491
    24 14/02/14 16:38:14 INFO Executor: Serialized size of result for 5 is 563
    25 14/02/14 16:38:14 INFO Executor: Sending result for 5 directly to driver
    26 14/02/14 16:38:14 INFO Executor: Finished task ID 5
    27 14/02/14 16:38:14 INFO TaskSetManager: Finished TID 5 in 6 ms on localhost (progress: 0/1)
    28 14/02/14 16:38:14 INFO DAGScheduler: Completed ResultTask(70)
    29 14/02/14 16:38:14 INFO TaskSchedulerImpl: Remove TaskSet 7.0 from pool
    30 14/02/14 16:38:14 INFO DAGScheduler: Stage 7 (count at <console>:15) finished in 0.009 s
    31 14/02/14 16:38:14 INFO SparkContext: Job finished: count at <console>:15, took 0.012329265 s
    32 res10: Long = 119
    33 
    34 scala> textFile.first
    35 14/02/14 16:38:24 INFO SparkContext: Starting job: first at <console>:15
    36 14/02/14 16:38:24 INFO DAGScheduler: Got job 8 (first at <console>:15) with 1 output partitions (allowLocal=true)
    37 14/02/14 16:38:24 INFO DAGScheduler: Final stage: Stage 8 (first at <console>:15)
    38 14/02/14 16:38:24 INFO DAGScheduler: Parents of final stage: List()
    39 14/02/14 16:38:24 INFO DAGScheduler: Missing parents: List()
    40 14/02/14 16:38:24 INFO DAGScheduler: Computing the requested partition locally
    41 14/02/14 16:38:24 INFO HadoopRDD: Input split: file:/D:/program/spark-0.9.0-incubating/README.md:0+4491
    42 14/02/14 16:38:24 INFO SparkContext: Job finished: first at <console>:15, took 0.002671379 s
    43 res11: String = # Apache Spark
    44 
    45 scala> val linesWithSpark = textFile.filter(line => line.contains("Spark"))
    46 linesWithSpark: org.apache.spark.rdd.RDD[String] = FilteredRDD[17] at filter at <console>:14
    47 
    48 scala> textFile.filter(line=> line.contains("spark")).count
    49 14/02/14 16:38:37 INFO SparkContext: Starting job: count at <console>:15
    50 14/02/14 16:38:37 INFO DAGScheduler: Got job 9 (count at <console>:15) with 1 output partitions (allowLocal=false)
    51 14/02/14 16:38:37 INFO DAGScheduler: Final stage: Stage 9 (count at <console>:15)
    52 14/02/14 16:38:37 INFO DAGScheduler: Parents of final stage: List()
    53 14/02/14 16:38:37 INFO DAGScheduler: Missing parents: List()
    54 14/02/14 16:38:37 INFO DAGScheduler: Submitting Stage 9 (FilteredRDD[18] at filter at <console>:15), which has no missin
    55 g parents
    56 14/02/14 16:38:37 INFO DAGScheduler: Submitting 1 missing tasks from Stage 9 (FilteredRDD[18] at filter at <console>:15)
    57 
    58 14/02/14 16:38:37 INFO TaskSchedulerImpl: Adding task set 9.0 with 1 tasks
    59 14/02/14 16:38:37 INFO TaskSetManager: Starting task 9.0:0 as TID 6 on executor localhost: localhost (PROCESS_LOCAL)
    60 14/02/14 16:38:37 INFO TaskSetManager: Serialized task 9.0:0 as 1642 bytes in 0 ms
    61 14/02/14 16:38:37 INFO Executor: Running task ID 6
    62 14/02/14 16:38:37 INFO BlockManager: Found block broadcast_5 locally
    63 14/02/14 16:38:37 INFO HadoopRDD: Input split: file:/D:/program/spark-0.9.0-incubating/README.md:0+4491
    64 14/02/14 16:38:37 INFO Executor: Serialized size of result for 6 is 563
    65 14/02/14 16:38:37 INFO Executor: Sending result for 6 directly to driver
    66 14/02/14 16:38:37 INFO Executor: Finished task ID 6
    67 14/02/14 16:38:37 INFO TaskSetManager: Finished TID 6 in 10 ms on localhost (progress: 0/1)
    68 14/02/14 16:38:37 INFO DAGScheduler: Completed ResultTask(90)
    69 14/02/14 16:38:37 INFO TaskSchedulerImpl: Remove TaskSet 9.0 from pool
    70 14/02/14 16:38:37 INFO DAGScheduler: Stage 9 (count at <console>:15) finished in 0.010 s
    71 14/02/14 16:38:37 INFO SparkContext: Job finished: count at <console>:15, took 0.020335125 s
    72 res12: Long = 7

    另外Spark官網提供了入門的四段視頻,但是國內被墻了,無法觀看youtube,我把這四段視頻放到了土豆網,大家可以看看。

    Spark Screencast 1 – 搭建Spark環境

    Spark Screencast 2 – Spark文檔總覽

    Spark Screencast 3 – 轉換和緩存

    Spark Screencast 4 – Scala獨立任務

    posted @ 2014-02-14 16:21 Chan Chen 閱讀(3034) | 評論 (0)編輯 收藏

    2013年5月23日 #

    top命令的Load average 含義及性能參考基值

    $ uptime
    11:12:26 up 3:44, 4 users, load average: 0.38, 0.31, 0.19

    系統平均負載被定義為在特定時間間隔內運行隊列中的平均進程樹。如果一個進程滿足以下條件則其就會位于運行隊列中:

    • 它沒有在等待I/O操作的結果
    • 它沒有主動進入等待狀態(也就是沒有調用'wait')
    • 沒有被停止(例如:等待終止)

    上面的輸出,load average后面分別是1分鐘、5分鐘、15分鐘的負載情況。數據是每隔5秒鐘檢查一次活躍的進程數,然后根據這個數值算出來的。如果這個數除以CPU 的數目,結果高于5的時候就表明系統在超負荷運轉了。


     
    Linux系統Load average負載詳細解釋   我們知道判斷一個系統的負載可以使用top,uptime等命令去查看,它分別記錄了一分鐘、五分鐘、以及十五分鐘的系統平均負載
      例如我的某臺服務器:
      $ uptime
      09:50:21 up 200 days, 15:07, 1 user, load average: 0.27, 0.33, 0.37
      大部分的人都認為這個數字越小越好,其實有很多關聯的提示信息,今天看到這個好文,應該可以給大家說清楚很多問題,轉一下:
      原文鏈接: http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages
      你可能對于 Linux 的負載均值(load averages)已有了充分的了解。負載均值在 uptime 或者 top 命令中可以看到,它們可能會顯示成這個樣子:
      load average: 0.09, 0.05, 0.01
      很多人會這樣理解負載均值:三個數分別代表不同時間段的系統平均負載(一分鐘、五 分鐘、以及十五分鐘),它們的數字當然是越小越好。數字越高,說明服務器的負載越 大,這也可能是服務器出現某種問題的信號。
      而事實不完全如此,是什么因素構成了負載均值的大小,以及如何區分它們目前的狀況是 “好”還是“糟糕”?什么時候應該注意哪些不正常的數值?
      回答這些問題之前,首先需要了解下這些數值背后的些知識。我們先用最簡單的例子說明, 一臺只配備一塊單核處理器的服務器。
      行車過橋
      一只單核的處理器可以形象得比喻成一條單車道。設想下,你現在需要收取這條道路的過橋 費 — 忙于處理那些將要過橋的車輛。你首先當然需要了解些信息,例如車輛的載重、以及 還有多少車輛正在等待過橋。如果前面沒有車輛在等待,那么你可以告訴后面的司機通過。 如果車輛眾多,那么需要告知他們可能需要稍等一會。
      因此,需要些特定的代號表示目前的車流情況,例如:
      0.00 表示目前橋面上沒有任何的車流。 實際上這種情況與 0.00 和 1.00 之間是相同的,總而言之很通暢,過往的車輛可以絲毫不用等待的通過。
      1.00 表示剛好是在這座橋的承受范圍內。 這種情況不算糟糕,只是車流會有些堵,不過這種情況可能會造成交通越來越慢。
      超過 1.00,那么說明這座橋已經超出負荷,交通嚴重的擁堵。 那么情況有多糟糕? 例如 2.00 的情況說明車流已經超出了橋所能承受的一倍,那么將有多余過橋一倍的車輛正在焦急的等待。3.00 的話情況就更不妙了,說明這座橋基本上已經快承受不了,還有超出橋負載兩倍多的車輛正在等待。
      上面的情況和處理器的負載情況非常相似。一輛汽車的過橋時間就好比是處理器處理某線程 的實際時間。Unix 系統定義的進程運行時長為所有處理器內核的處理時間加上線程 在隊列中等待的時間。
      和收過橋費的管理員一樣,你當然希望你的汽車(操作)不會被焦急的等待。所以,理想狀態 下,都希望負載平均值小于 1.00 。當然不排除部分峰值會超過 1.00,但長此以往保持這 個狀態,就說明會有問題,這時候你應該會很焦急。
      “所以你說的理想負荷為 1.00 ?”
      嗯,這種情況其實并不完全正確。負荷 1.00 說明系統已經沒有剩余的資源了。在實際情況中 ,有經驗的系統管理員都會將這條線劃在 0.70:
      “需要進行調查法則”: 如果長期你的系統負載在 0.70 上下,那么你需要在事情變得更糟糕之前,花些時間了解其原因。
      “現在就要修復法則”:1.00 。 如果你的服務器系統負載長期徘徊于 1.00,那么就應該馬上解決這個問題。否則,你將半夜接到你上司的電話,這可不是件令人愉快的事情。
      “凌晨三點半鍛煉身體法則”:5.00。 如果你的服務器負載超過了 5.00 這個數字,那么你將失去你的睡眠,還得在會議中說明這情況發生的原因,總之千萬不要讓它發生。

    posted @ 2013-05-23 17:47 Chan Chen 閱讀(336) | 評論 (0)編輯 收藏

    2013年5月22日 #

    Java CyclicBarrier介紹

    Refer to: http://my.oschina.net/redhouse/blog/60739

    CyclicBarrier 
    (周期障礙)類可以幫助同步,它允許一組線程等待整個線程組到達公共屏障點。CyclicBarrier 是使用整型變量構造的,其確定組中的線程數。當一個線程到達屏障時(通過調用 CyclicBarrier.await()),它會被阻塞,直到所有線程都到達屏障,然后在該點允許所有線程繼續執行。與CountDownLatch不同的是,CyclicBarrier 所有公共線程都到達后,可以繼續執行下一個目標點,而CountDownLatch第一次到達指定點后,也就是記數器減制零,就無法再次執行下一目標工作。下面主要演義CyclicBarrier 的用法:

    package com.test;

    import java.text.SimpleDateFormat;

    import java.util.Date;

    import java.util.concurrent.BrokenBarrierException;

    import java.util.concurrent.CyclicBarrier;

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

    public class TestCyclicBarrier {

    private static int[] timeWalk = { 5, 8, 15, 15, 10 };  // 徒步需要的時間

    private static int[] timeSelf = { 1, 3, 4, 4, 5 };           // 自駕游

    private static int[] timeBus = { 2, 4, 6, 6, 7 };           // 旅游大巴

    static String now() {

                SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

                return sdf.format(new Date()) + ": ";

    }

    static class Tour implements Runnable {

                private   int[]     times;

                private   CyclicBarrier    barrier;

                private   String   tourName;

    public Tour(CyclicBarrier barrier, String tourName, int[] times) {

                this.times = times;

                this.tourName = tourName;

                this.barrier = barrier;

    }

    public void run() {

            try {

                     Thread.sleep(times[0] * 1000);

                      System.out.println(now() + tourName + " 合肥");

                      barrier.await();

                      Thread.sleep(times[1] * 1000);

                      System.out.println(now() + tourName + " 南京");

                       barrier.await();

                      Thread.sleep(times[4] * 1000);

                       System.out.println(now() + tourName + " 上海");

                       barrier.await();

                       System.out.println(tourName + "飛機 合肥");

             } catch (InterruptedException e) {

                       e.printStackTrace();

              } catch (BrokenBarrierException e) {

                        e.printStackTrace();

              }

        }

    }

     

    public static void main(String[] args) {

                  CyclicBarrier barrier = new CyclicBarrier(3);

                   ExecutorService exec = Executors.newFixedThreadPool(3);

                   exec.submit(new Tour(barrier, "徒步", timeWalk));

                   exec.submit(new Tour(barrier, "自駕", timeSelf));

                   exec.submit(new Tour(barrier, "大巴", timeBus));

                  exec.shutdown();

      }

    }

    最后執行結果如下:

    16:24:35: 自駕 合肥

    16:24:36: 大巴 合肥

    16:24:39: 徒步 合肥


    16:24:42: 自駕 南京

    16:24:43: 大巴 南京

    16:24:47: 徒步 南京


    16:24:52: 自駕 上海

    16:24:54: 大巴 上海

    16:24:57: 徒步 上海


    徒步飛機 合肥

    自駕飛機 合肥

    大巴飛機 合肥

    posted @ 2013-05-22 09:57 Chan Chen 閱讀(362) | 評論 (0)編輯 收藏

    2013年5月21日 #

    IE6的連接數限制問題

    先描述一下問題: 
    有一個管理Job的UI,選中一些Job可以Run,每次只能啟動一個。還有一個UI通過Timer定時發Ajax請求服務端,查詢并顯示Job的運行狀況(進度)。 

    奇怪的問題出現了: 
    1)在FireFox和IE8運行正常(貌似正常,稍后再解釋)。其他瀏覽器未測試。 
    2)IE6,7及更早版本,Timer無法檢測到多于1個的Job運行。 

    先檢查了一遍代碼,Timer的控制沒有問題。不行就使用Fiddler吧。剛好是IE的問題。 

    觀察HTTP發現一個現象,運行Job的HTTP似乎沒有成功,因為Body是-1,之后是每隔一秒的Timer發起的HTTP。如果再啟動一個Job,發現Timer停止了!! 

    等待第一個Job運行成功之后,Timer又恢復了(重新發送Ajax請求)!! 

    似乎是運行Job的請求阻塞了(實際上該請求長時間沒有返回,因為運行Job需要幾分鐘甚至更多時間)。 

    為啥不使用DWR3.0的Push技術?后來跟同事討論明白,這不過是把Timer從客戶端轉移到了服務端。 

    記起來了,俺好像讀DWR源代碼的時候(當時對如何實現推非常感興趣),見過一段代碼分析Browser的類型和連接數,有的情況還拋出了異常。 

    明白了,肯定是IE6有連接數限制問題,后來得知,默認情況下,它不支持同時超過2個連接。哈哈。這就對了。 

    RunJob占用了一個(幾分鐘不等), 
    Timer占用了一個(很短暫)。 

    剛好2個。 
    Java代碼  收藏代碼
    1. public class BrowserDetect  
    2. {  
    3.     /** 
    4.      * How many connections can this browser open simultaneously? 
    5.      * @param request The request so we can get at the user-agent header 
    6.      * @return The number of connections that we think this browser can take 
    7.      */  
    8.     public static int getConnectionLimit(HttpServletRequest request)  
    9.     {  
    10.         if (atLeast(request, UserAgent.IE, 8))  
    11.         {  
    12.             return 6;  
    13.         }  
    14.         if (atLeast(request, UserAgent.Firefox, 3))  
    15.         {  
    16.             return 6;  
    17.         }  
    18.         else if (atLeast(request, UserAgent.AppleWebKit, 8))  
    19.         {  
    20.             return 4;  
    21.         }  
    22.         else if (atLeast(request, UserAgent.Opera, 9))  
    23.         {  
    24.             return 4;  
    25.         }  
    26.         else  
    27.         {  
    28.             return 2;  
    29.         }  
    30.     }  
    31. //....  
    32. }  


    接下來就是查資料做試驗,驗證該問題是否正確。通過在注冊表設置Internet Settings參數,實現了更多連接。例如10個。 

    但是Job可能很多,不可能無限制增加連接數,所以RunJob不應長期占用連接,它應該把Job插入隊列并立即返回。 

    至此問題的源頭終于找到了,Fiddler又幫了大忙。 

    讀源代碼是了解技術運作細節的最好方法,此外還能學到好的編程習慣。

    posted @ 2013-05-21 15:19 Chan Chen 閱讀(237) | 評論 (0)編輯 收藏

    2013年5月15日 #

    Java 枚舉7常見種用法

    DK1.5引入了新的類型——枚舉。在 Java 中它雖然算個“小”功能,卻給我的開發帶來了“大”方便。

    用法一:常量

    JDK1.5 之前,我們定義常量都是: public static fianl.... 。現在好了,有了枚舉,可以把相關的常量分組到一個枚舉類型里,而且枚舉提供了比常量更多的方法。

     

    Java代碼  收藏代碼
    1. public enum Color {  
    2.   RED, GREEN, BLANK, YELLOW  
    3. }  
     

    用法二:switch

    JDK1.6之前的switch語句只支持int,char,enum類型,使用枚舉,能讓我們的代碼可讀性更強。

     

    Java代碼  收藏代碼
    1. enum Signal {  
    2.     GREEN, YELLOW, RED  
    3. }  
    4. public class TrafficLight {  
    5.     Signal color = Signal.RED;  
    6.     public void change() {  
    7.         switch (color) {  
    8.         case RED:  
    9.             color = Signal.GREEN;  
    10.             break;  
    11.         case YELLOW:  
    12.             color = Signal.RED;  
    13.             break;  
    14.         case GREEN:  
    15.             color = Signal.YELLOW;  
    16.             break;  
    17.         }  
    18.     }  
    19. }  
     

    用法三:向枚舉中添加新方法

    如果打算自定義自己的方法,那么必須在enum實例序列的最后添加一個分號。而且 Java 要求必須先定義 enum實例。

     

    Java代碼  收藏代碼
    1. public enum Color {  
    2.     RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);  
    3.     // 成員變量  
    4.     private String name;  
    5.     private int index;  
    6.     // 構造方法  
    7.     private Color(String name, int index) {  
    8.         this.name = name;  
    9.         this.index = index;  
    10.     }  
    11.     // 普通方法  
    12.     public static String getName(int index) {  
    13.         for (Color c : Color.values()) {  
    14.             if (c.getIndex() == index) {  
    15.                 return c.name;  
    16.             }  
    17.         }  
    18.         return null;  
    19.     }  
    20.     // get set 方法  
    21.     public String getName() {  
    22.         return name;  
    23.     }  
    24.     public void setName(String name) {  
    25.         this.name = name;  
    26.     }  
    27.     public int getIndex() {  
    28.         return index;  
    29.     }  
    30.     public void setIndex(int index) {  
    31.         this.index = index;  
    32.     }  
    33. }  
     

    用法四:覆蓋枚舉的方法

    下面給出一個toString()方法覆蓋的例子。

     

    Java代碼  收藏代碼
    1. public enum Color {  
    2.     RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);  
    3.     // 成員變量  
    4.     private String name;  
    5.     private int index;  
    6.     // 構造方法  
    7.     private Color(String name, int index) {  
    8.         this.name = name;  
    9.         this.index = index;  
    10.     }  
    11.     //覆蓋方法  
    12.     @Override  
    13.     public String toString() {  
    14.         return this.index+"_"+this.name;  
    15.     }  
    16. }  
     

    用法五:實現接口

    所有的枚舉都繼承自java.lang.Enum類。由于Java 不支持多繼承,所以枚舉對象不能再繼承其他類。

     

    Java代碼  收藏代碼
    1. public interface Behaviour {  
    2.     void print();  
    3.     String getInfo();  
    4. }  
    5. public enum Color implements Behaviour{  
    6.     RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);  
    7.     // 成員變量  
    8.     private String name;  
    9.     private int index;  
    10.     // 構造方法  
    11.     private Color(String name, int index) {  
    12.         this.name = name;  
    13.         this.index = index;  
    14.     }  
    15. //接口方法  
    16.     @Override  
    17.     public String getInfo() {  
    18.         return this.name;  
    19.     }  
    20.     //接口方法  
    21.     @Override  
    22.     public void print() {  
    23.         System.out.println(this.index+":"+this.name);  
    24.     }  
    25. }  
     

    用法六:使用接口組織枚舉

     

    Java代碼  收藏代碼
    1. public interface Food {  
    2.     enum Coffee implements Food{  
    3.         BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  
    4.     }  
    5.     enum Dessert implements Food{  
    6.         FRUIT, CAKE, GELATO  
    7.     }  
    8. }  
     

    用法七:關于枚舉集合的使用

    java.util.EnumSet和java.util.EnumMap是兩個枚舉集合。EnumSet保證集合中的元素不重復;EnumMap中的key是enum類型,而value則可以是任意類型。關于這個兩個集合的使用就不在這里贅述,可以參考JDK文檔。

    關于枚舉的實現細節和原理請參考:

    posted @ 2013-05-15 19:57 Chan Chen 閱讀(248) | 評論 (0)編輯 收藏

    2013年5月9日 #

    JVM參數設定

    在Linux或其他UNIX和類UNIX環境下,ps命令想必大家都不陌生,我相信也有不少同學寫過 ps aux | grep java | grep -v grep | awk '{print $2}' 這樣的管道命令來找出Java進程的pid。常言道,Java并非真的"跨平臺",它自己就是平臺。作為平臺,當然也有些基本的工具,讓我們可以用更簡單、更統一,同時又是非侵入的方式來查詢進程相關信息。今天我們就來認識一下其中的兩個。

    jps

    顧名思義,它對應到UNIX的ps命令。用法如下:

    jps [ options ] [ hostid ]

    其中,options可以用 -q (安靜) -m (輸出傳遞給main方法的參數) -l (顯示完整路徑) -v (顯示傳遞給JVM的命令行參數) -V (顯示通過flag文件傳遞給JVM的參數) -J (和其他Java工具類似用于傳遞參數給命令本身要調用的java進程);hostid是主機id,默認localhost。

    jstat

    用于輸出給定java進程的統計信息。用法如下:

    jstat -options 可以列出當前JVM版本支持的選項,常見的有 -class (類加載器) -compiler (JIT) -gc (GC堆狀態) -gccapacity (各區大小) -gccause (最近一次GC統計和原因) -gcnew (新區統計) -gcnewcapacity (新區大小) -gcold (老區統計) -gcoldcapacity (老區大小) -gcpermcapacity (永久區大小) -gcutil (GC統計匯總) -printcompilation (HotSpot編譯統計)

    假定你要監控的Java進程號是12345,那么
    jstat -gcutil -t 12345 200 300 即可每200毫秒連續打印300次帶有時間戳的GC統計信息。

    簡單解釋一下: -gcutil是傳入的option;必選,-t是打印時間戳,是以目標JVM啟動時間為起點計算的,可選;12345是vmid/pid,和我們從jps拿到的是一樣的,必選;200是監控時間間隔,可選,不提供就意味著單次輸出;300是最大輸出次數,可選,不提供且監控時間間隔有值的話,就是無限期打印下去。



    jstat

           1. jstat -gc pid

                可以顯示gc的信息,查看gc的次數,及時間。

                其中最后五項,分別是young gc的次數,young gc的時間,full gc的次數,full gc的時間,gc的總時間。

          2.jstat -gccapacity pid

                可以顯示,VM內存中三代(young,old,perm)對象的使用和占用大小,

                如:PGCMN顯示的是最小perm的內存使用量,PGCMX顯示的是perm的內存最大使用量,

                PGC是當前新生成的perm內存占用量,PC是但前perm內存占用量。

                其他的可以根據這個類推, OC是old內純的占用量。

         3.jstat -gcutil pid

                統計gc信息統計。

         4.jstat -gcnew pid

               年輕代對象的信息。

         5.jstat -gcnewcapacity pid

               年輕代對象的信息及其占用量。

         6.jstat -gcold pid

              old代對象的信息。

         7.stat -gcoldcapacity pid

              old代對象的信息及其占用量。

         8.jstat -gcpermcapacity pid

              perm對象的信息及其占用量。

         9.jstat -class pid

              顯示加載class的數量,及所占空間等信息。
         10.jstat -compiler pid

              顯示VM實時編譯的數量等信息。

         11.stat -printcompilation pid

              當前VM執行的信息。

            一些術語的中文解釋:

             S0C:年輕代中第一個survivor(幸存區)的容量 (字節)
             S1C:年輕代中第二個survivor(幸存區)的容量 (字節)
             S0U:年輕代中第一個survivor(幸存區)目前已使用空間 (字節)
             S1U:年輕代中第二個survivor(幸存區)目前已使用空間 (字節)
               EC:年輕代中Eden(伊甸園)的容量 (字節)
               EU:年輕代中Eden(伊甸園)目前已使用空間 (字節)
               OC:Old代的容量 (字節)
               OU:Old代目前已使用空間 (字節)
               PC:Perm(持久代)的容量 (字節)
               PU:Perm(持久代)目前已使用空間 (字節)
             YGC:從應用程序啟動到采樣時年輕代中gc次數
           YGCT:從應用程序啟動到采樣時年輕代中gc所用時間(s)
             FGC:從應用程序啟動到采樣時old代(全gc)gc次數
           FGCT:從應用程序啟動到采樣時old代(全gc)gc所用時間(s)
             GCT:從應用程序啟動到采樣時gc用的總時間(s)

        NGCMN:年輕代(young)中初始化(最小)的大小 (字節)

        NGCMX:年輕代(young)的最大容量 (字節)

            NGC:年輕代(young)中當前的容量 (字節)

       OGCMN:old代中初始化(最小)的大小 (字節) 

       OGCMX:old代的最大容量 (字節)

           OGC:old代當前新生成的容量 (字節)

       PGCMN:perm代中初始化(最小)的大小 (字節) 

       PGCMX:perm代的最大容量 (字節)   

           PGC:perm代當前新生成的容量 (字節)

              S0:年輕代中第一個survivor(幸存區)已使用的占當前容量百分比

             S1:年輕代中第二個survivor(幸存區)已使用的占當前容量百分比

               E:年輕代中Eden(伊甸園)已使用的占當前容量百分比

               O:old代已使用的占當前容量百分比

               P:perm代已使用的占當前容量百分比

      S0CMX:年輕代中第一個survivor(幸存區)的最大容量 (字節)

     S1CMX :年輕代中第二個survivor(幸存區)的最大容量 (字節)

        ECMX:年輕代中Eden(伊甸園)的最大容量 (字節)

           DSS:當前需要survivor(幸存區)的容量 (字節)(Eden區已滿)

              TT: 持有次數限制

           MTT : 最大持有次數限制








    虛擬機中的共劃分為三個代:年輕代(Young Generation)、年老點(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java類的類信息,與垃圾收集要收集的Java對象關系不大。年輕代和年老代的劃分是對垃圾收集影響比較大的。

      年輕代:

      所有新生成的對象首先都是放在年輕代的。年輕代的目標就是盡可能快速的收集掉那些生命周期短的對象。年輕代分三個區。一個Eden區,兩個 Survivor區(一般而言)。大部分對象在Eden區中生成。當Eden區滿時,還存活的對象將被復制到Survivor區(兩個中的一個),當這個 Survivor區滿時,此區的存活對象將被復制到另外一個Survivor區,當這個Survivor去也滿了的時候,從第一個Survivor區復制過來的并且此時還存活的對象,將被復制“年老區(Tenured)”。需要注意,Survivor的兩個區是對稱的,沒先后關系,所以同一個區中可能同時存在從Eden復制過來對象,和從前一個Survivor復制過來的對象,而復制到年老區的只有從第一個Survivor去過來的對象。而且,Survivor區總有一個是空的。同時,根據程序需要,Survivor區是可以配置為多個的(多于兩個),這樣可以增加對象在年輕代中的存在時間,減少被放到年老代的可能。

      年老代:

      在年輕代中經歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認為年老代中存放的都是一些生命周期較長的對象。

      持久代:

      用于存放靜態文件,如今Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候需要設置一個比較大的持久代空間來存放這些運行過程中新增的類。持久代大小通過-XX:MaxPermSize=<N>進行設置。



    什么情況下觸發垃圾回收:

        由于對象進行了分代處理,因此垃圾回收區域、時間也不一樣。GC有兩種類型:Scavenge GC和Full GC。

        Scavenge GC

        一般情況下,當新對象生成,并且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活對象,并且把尚且存活的對象移動到Survivor區。然后整理Survivor的兩個區。這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。因為大部分對象都是從Eden區開始的,同時Eden區不會分配的很大,所以Eden區的GC會頻繁進行。因而,一般在這里需要使用速度快、效率高的算法,使Eden去能盡快空閑出來。

        Full GC

        對整個堆進行整理,包括Young、Tenured和Perm。Full GC因為需要對整個對進行回收,所以比Scavenge GC要慢,因此應該盡可能減少Full GC的次數。在對JVM調優的過程中,很大一部分工作就是對于FullGC的調節。有如下原因可能導致Full GC:

    -server -Xmx3000m -Xms3000m -Xmn1200m -Xss256k -XX:SurvivorRatio=8 -XX:PermSize=96m -XX:MaxPermSize=96m -XX:+CMSParallelRemarkEnabled -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection  
    -XX:+CMSClassUnloadingEnabled  -XX:+DisableExplicitGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/app_admin/logs/oom.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps  -Xloggc:/home/app_admin/logs/gc.log
    -Xmx3000m設置JVM最大可用內存為3000M。

     

    -Xms3000m設置JVM促使內存為3000M。可設置與-Xmx相同,避免每次gc后JVM重新分配內存。

    -Xmn1200m設置年輕代大小為1200m。整個堆大小=年輕代大小+年老代大小。增大年輕代后,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8。

    -Xss256k 設置每個線程的堆棧大小。JDK5.0以后每個線程堆棧大小為1024k,以前每個線程堆棧大小為256K。根據應用的線程所需內存大小進行調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,經驗值在3000~5000左右。

    -XX:PermSize=96m  -XX:MaxPermSize=96m:設置持久代大小為64m,根據應用自身class文件大小進行設置,運行時空余量在10%------20%左右。

    -XX:+UseConcMarkSweepGC設置年老代為并發收集。

    -XX:+UseParNewGC:設置年輕代為并行收集。可與CMS收集同時使用。JDK5.0以上,JVM會根據系統配置自行設置,所以無需再設置此值。

    -XX:-CMSParallelRemarkEnabled :If the -XX:+UseParNewGC option is in use the remark pauses may be decreased with the -XX:+CMSParallelRemarkEnabled option.

    -XX:+UseCMSCompactAtFullCollection打開對年老代的壓縮。可能會影響性能,但是可以消除碎片(-XX:CMSFullGCsBeforeCompaction=5:由于并發收集器不對內存空間進行壓縮、整理,所以運行一段時間以后會產生"碎片",使得運行效率降低。此值設置運行多少次GC以后對內存空間進行壓縮、整理, 避免每次壓縮性能消耗)

    *-XX:+CMSClassUnloadingEnabled:*Perm Gen的使用到達一定的比率(默認為92% ) 出發cms回收

    -XX:+DisableExplicitGC:屏蔽system.gc(), 這種顯示調用垃圾回收

    -XX:+HeapDumpOnOutOfMemoryError:內存溢出打印堆棧信息

    -XX:HeapDumpPath=/home/app_admin/logs/oom.log:heapdump的日志文件路徑

    -XX:+PrintGCDetails:打印gc日志詳情

    -XX:+PrintGCDateStamps:打印gc時的具體時間

    -Xloggc:/home/app_admin/logs/gc.log:gc打印日志文件的路徑

    JVM內存結構

    •      Method Area------方法區,被Class Loader所裝載的class文件以及相關的方法信息、域信息、靜態變量等都存放在這個區域內。該區域是所有Java線程所共享的。(設置方法區內存大小:-XX:PermSize -XX:MaxPermSize)

    •      Heap------堆區,這個區域就是用來存放java對象的,通常GC也是針對該區域。一個Java虛擬機實例只有一個堆,并直接由java虛擬機進行管理,在虛擬機啟動時創建。該區域可以被所有Java線程所共享。(設置堆內存大小:-Xms  -Xmx -Xmn)

    •      Stack------棧區,用來存放JVM的內存局部變量和操作數棧。通常虛擬機對它的操作比較簡單(以幀為單位的壓棧和出棧),速度也很快。每個線程都有自己的棧,且棧可以不連續。(設置棧內存大小:-Xss)

    •      Program Counter Register------每一個線程都有自己的一個PC寄存器,用于存放下一條被執行的指令的地址。每個線程的PC寄存器在線程啟動時產生。

    •      Native Method Stack------保存本地方法進入區域的地址。(設置棧內存大小:-Xss)
      






    GC日志格式說明:

    [GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] <starting occupancy3> -> <ending occupancy3>, <pause time3> secs]

    <collector>GC收集器的名稱

    <starting occupancy1> 新生代在GC前占用的內存

    <ending occupancy1> 新生代在GC后占用的內存

    <pause time1> 新生代局部收集時jvm暫停處理的時間

    <starting occupancy3> JVM Heap 在GC前占用的內存

    <ending occupancy3> JVM Heap 在GC后占用的內存

    <pause time3> GC過程中jvm暫停處理的總時間

    YGC收集信息

    2012-2-7T19:24:29.040+0800: 10429.503: [GC [PSYoungGen: 484520K->2577K(495936K)] 734774K->254308K(3129664K), 0.0118730 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]

    FGC收集信息

    2012-2-7T19:38:37.391+0800: 10804.897: [Full GC (System) [PSYoungGen: 684K->0K(468416K)] [PSOldGen: 342164K->257451K(1060864K)] 342849K->257451K(1529280K) [PSPermGen: 123775K->122206K(237248K)], 1.1808050 secs] [Times: user=0.99 sys=0.18, real=1.18 secs] 

    JVM運行期分析工具

    jps 虛擬機進程狀況工具

    jinfo java配置信息工具

    jstat 虛擬機統計信息監視工具

    jmap java內存映射工具

    jhat 虛擬機堆轉儲快照分析工具

    jstack java堆棧跟蹤工具 

    posted @ 2013-05-09 18:17 Chan Chen| 編輯 收藏

    Curl命令使用整理

    Refer to: http://www.cnblogs.com/wangkangluo1/archive/2012/04/17/2453975.html

    可以看作命令行瀏覽器

    1、開啟gzip請求
    curl -I http://www.sina.com.cn/ -H Accept-Encoding:gzip,defalte

    2、監控網頁的響應時間
    curl -o /dev/null -s -w "time_connect: %{time_connect}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n" "http://www.kklinux.com"

    3. 監控站點可用性
    curl -o /dev/null -s -w %{http_code} "http://www.kklinux.com"

    4、以http1.0協議請求(默認為http1.1) 
    curl -0 .............. 
          1)讀取網頁 
      $ curl linuxidc.com">http://www.linuxidc.com 
      2)保存網頁 
      $ curl http://www.linuxidc.com > page.html $ curl -o page.html http://www.linuxidc.com 
      3)使用的proxy服務器及其端口:-x 
      $ curl -x 123.45.67.89:1080 -o page.html http://www.linuxidc.com 
      4)使用cookie來記錄session信息 
      $ curl -x 123.45.67.89:1080 -o page.html -D cookie0001.txt http://www.linuxidc.com 
    option: -D 是把http的response里面的cookie信息存到一個特別的文件中去,這樣,當頁面被存到page.html的同時,cookie信息也被存到了cookie0001.txt里面了 
        5)那么,下一次訪問的時候,如何繼續使用上次留下的cookie信息呢? 
      使用option來把上次的cookie信息追加到http request里面去:-b 
      $ curl -x 123.45.67.89:1080 -o page1.html -D cookie0002.txt -b cookie0001.txt http://www.linuxidc.com 

    6)瀏覽器信息~~~~ 
    隨意指定自己這次訪問所宣稱的自己的瀏覽器信息: -A
    curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x 123.45.67.89:1080 -o page.html -D cookie0001.txt http://www.yahoo.com 
    這樣,服務器端接到訪問的要求,會認為你是一個運行在Windows 2000上的IE6.0,嘿嘿嘿,其實也許你用的是蘋果機呢! 
    而"Mozilla/4.73 [en] (X11; U; Linux 2.2; 15 i686"則可以告訴對方你是一臺PC上跑著的Linux,用的是Netscape 4.73,呵呵呵 

    7)
    另外一個服務器端常用的限制方法,就是檢查http訪問的referer。比如你先訪問首頁,再訪問里面所指定的下載頁,這第二次訪問的referer地址就是第一次訪問成功后的頁面地 
    址。這樣,服務器端只要發現對下載頁面某次訪問的referer地址不 是首頁的地址,就可以斷定那是個盜連了~~~~~ 
    討厭討厭~~~我就是要盜連~~~~~!!
    幸好curl給我們提供了設定referer的option: -e
    curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x 123.45.67.89:1080 -e "mail.yahoo.com" -o page.html -D cookie0001.txt http://www.yahoo.com 
    這樣,就可以騙對方的服務器,你是從mail.yahoo.com點擊某個鏈接過來的了,呵呵呵 

    8)curl 下載文件 
    剛才講過了,下載頁面到一個文件里,可以使用 -o ,下載文件也是一樣。
    比如, curl -o 1.jpg http://cgi2.tky.3web.ne.jp/~zzh/screen1.JPG
    這里教大家一個新的option: -O
    大寫的O,這么用: curl -O http://cgi2.tky.3web.ne.jp/~zzh/screen1.JPG
    這樣,就可以按照服務器上的文件名,自動存在本地了! 
    再來一個更好用的。
    如果screen1.JPG以外還有screen2.JPG、screen3.JPG、....、screen10.JPG需要下載,難不成還要讓我們寫一個script來完成這些操作?
    不干!
    在curl里面,這么寫就可以了:
    curl -O http://cgi2.tky.3web.ne.jp/~zzh/screen[1-10].JPG 
    呵呵呵,厲害吧?!~~~ 
    9)
    再來,我們繼續講解下載!
    curl -O http://cgi2.tky.3web.ne.jp/~{zzh,nick}/[001-201].JPG 
    這樣產生的下載,就是
    ~zzh/001.JPG
    ~zzh/002.JPG
    ...
    ~zzh/201.JPG
    ~nick/001.JPG
    ~nick/002.JPG
    ...
    ~nick/201.JPG 
    夠方便的了吧?哈哈哈 
    咦?高興得太早了。
    由于zzh/nick下的文件名都是001,002...,201,下載下來的文件重名,后面的把前面的文件都給覆蓋掉了~~~ 
    沒關系,我們還有更狠的!
    curl -o #2_#1.jpg http://cgi2.tky.3web.ne.jp/~{zzh,nick}/[001-201].JPG 
    --這是.....自定義文件名的下載?
    --對頭,呵呵! 
    #1是變量,指的是{zzh,nick}這部分,第一次取值zzh,第二次取值nick
    #2代表的變量,則是第二段可變部分---[001-201],取值從001逐一加到201
    這樣,自定義出來下載下來的文件名,就變成了這樣:
    原來: ~zzh/001.JPG ---> 下載后: 001-zzh.JPG
    原來: ~nick/001.JPG ---> 下載后: 001-nick.JPG 
    這樣一來,就不怕文件重名啦,呵呵 

    9)
    繼續講下載
    我們平時在windows平臺上,flashget這樣的工具可以幫我們分塊并行下載,還可以斷線續傳。
    curl在這些方面也不輸給誰,嘿嘿 
    比如我們下載screen1.JPG中,突然掉線了,我們就可以這樣開始續傳
    curl -c -O http://cgi2.tky.3wb.ne.jp/~zzh/screen1.JPG 
    當然,你不要拿個flashget下載了一半的文件來糊弄我~~~~別的下載軟件的半截文件可不一定能用哦~~~ 
    分塊下載,我們使用這個option就可以了: -r
    舉例說明
    比如我們有一個http://cgi2.tky.3web.ne.jp/~zzh/zhao1.mp3 要下載(趙老師的電話朗誦 :D )
    我們就可以用這樣的命令:
    curl -r 0-10240 -o "zhao.part1" http:/cgi2.tky.3web.ne.jp/~zzh/zhao1.mp3 &\
    curl -r 10241-20480 -o "zhao.part1" http:/cgi2.tky.3web.ne.jp/~zzh/zhao1.mp3 &\
    curl -r 20481-40960 -o "zhao.part1" http:/cgi2.tky.3web.ne.jp/~zzh/zhao1.mp3 &\
    curl -r 40961- -o "zhao.part1" http:/cgi2.tky.3web.ne.jp/~zzh/zhao1.mp3 
    這樣就可以分塊下載啦。
    不過你需要自己把這些破碎的文件合并起來
    如果你用UNIX或蘋果,用 cat zhao.part* > zhao.mp3就可以
    如果用的是Windows,用copy /b 來解決吧,呵呵 
    上面講的都是http協議的下載,其實ftp也一樣可以用。
    用法嘛,
    curl -u name:passwd ftp://ip:port/path/file
    或者大家熟悉的
    curl ftp://name:passwd@ip:port/path/file 
      
    10)上傳的option是 -T 
    比如我們向ftp傳一個文件: curl -T localfile -u name:passwd ftp://upload_site:port/path/ 
    當然,向http服務器上傳文件也可以
    比如 curl -T localfile http://cgi2.tky.3web.ne.jp/~zzh/abc.cgi
    注意,這時候,使用的協議是HTTP的PUT method 
    剛才說到PUT,嘿嘿,自然讓老服想起來了其他幾種methos還沒講呢!
    GET和POST都不能忘哦。 
    http提交一個表單,比較常用的是POST模式和GET模式 
    GET模式什么option都不用,只需要把變量寫在url里面就可以了
    比如:
    curl http://www.yahoo.com/login.cgi?user=nickwolfe&password=12345 
    而POST模式的option則是 -d 
    比如,curl -d "user=nickwolfe&password=12345" http://www.yahoo.com/login.cgi

    就相當于向這個站點發出一次登陸申請~~~~~ 
    到底該用GET模式還是POST模式,要看對面服務器的程序設定。 
    一點需要注意的是,POST模式下的文件上的文件上傳,比如
    <form method="POST" enctype="multipar/form-data" action="http://cgi2.tky.3web.ne.jp/~zzh/up_file.cgi">
    <input type=file name=upload>
    <input type=submit name=nick value="go">
    </form>
    這樣一個HTTP表單,我們要用curl進行模擬,就該是這樣的語法:
    curl -F upload=@localfile -F nick=go http://cgi2.tky.3web.ne.jp/~zzh/up_file.cgi 
    羅羅嗦嗦講了這么多,其實curl還有很多很多技巧和用法
    比如 https的時候使用本地證書,就可以這樣
    curl -E localcert.pem https://remote_server 
    再比如,你還可以用curl通過dict協議去查字典~~~~~
    curl dict://dict.org/d:computer 

    今天為了檢查所有刺猬主機上所有域名是否有備案.在使用wget不爽的情況下,找到了curl這個命令行流量器命令.發現其對post的調用還是蠻好的.特別有利于對提交信息及變 
    更參數進行較驗.對于我想將幾十萬域名到miibeian.gov.cn進行驗證是否有備案信息非常有用.發現這篇文章很不錯,特為轉貼. 
    我的目標:
    curl -d "cxfs=1&ym=xieyy.cn" http://www.miibeian.gov.cn/baxx_cx_servlet 
    在出來的信息中進行過濾,提取備案號信息,并設置一個標識位.將域名,備案號及標識位入庫 

    用curl命令,post提交帶空格的數據 
    今天偶然遇到一個情況,我想用curl登入一個網頁,無意間發現要post的數據里帶空格。比如用戶名為"abcdef",密碼為"abc def",其中有一個空格,按照我以前的方式提交: 
    curl -D cookie -d "username=abcdef&password=abc def" http://login.xxx.com/提示登入失敗。 

    于是查看curl手冊man curl。找到: 
    d/--data (HTTP) Sends the speci?ed data in a POST request to the HTTP server, in a way that can emulate as if a user has ?lled in a HTML form and pressed the 
    submit button. Note that the data is sent exactly as speci?ed with no extra processing (with all newlines cut off). The data is expected to be "url-encoded". 
    This will cause curl to pass the data to the server using the content-type application/x-www-form-urlencoded. Compare to -F/--form. If this option is used 
    more than once on the same command line, the data pieces speci?ed will be merged together with a separating &-letter. Thus, using ’-d name=daniel -d 
    skill=lousy’ would generate a post chunk that looks like ’name=daniel&skill=lousy’. 
    于是改用: 
    curl -D cookie -d "username=abcdef" -d "password=abc efg" http://login.xxx.com/這樣就能成功登入了。 

    (責任編輯:飄飛的夜)
     

    Curl是Linux下一個很強大的http命令行工具,其功能十分強大。

    1) 二話不說,先從這里開始吧!

    $ curl http://www.linuxidc.com

    回車之后,www.linuxidc.com 的html就稀里嘩啦地顯示在屏幕上了    ~

    2) 嗯,要想把讀過來頁面存下來,是不是要這樣呢?

    $ curl http://www.linuxidc.com > page.html

    當然可以,但不用這么麻煩的!

    用curl的內置option就好,存下http的結果,用這個option: -o

    $ curl -o page.html http://www.linuxidc.com

    這樣,你就可以看到屏幕上出現一個下載頁面進度指示。等進展到100%,自然就 OK咯

    3) 什么什么?!訪問不到?肯定是你的proxy沒有設定了。

    使用curl的時候,用這個option可以指定http訪問所使用的proxy服務器及其端口: -x

    $ curl -x 123.45.67.89:1080 -o page.html http://www.linuxidc.com

    4) 訪問有些網站的時候比較討厭,他使用cookie來記錄session信息。

    像IE/NN這樣的瀏覽器,當然可以輕易處理cookie信息,但我們的curl呢?.....

    我們來學習這個option: -D <— 這個是把http的response里面的cookie信息存到一個特別的文件中去

    $ curl -x 123.45.67.89:1080 -o page.html -D cookie0001.txt http://www.linuxidc.com

    這樣,當頁面被存到page.html的同時,cookie信息也被存到了cookie0001.txt里面了

    5)那么,下一次訪問的時候,如何繼續使用上次留下的cookie信息呢?要知道,很多網站都是靠監視你的cookie信息,來判斷你是不是不按規矩訪問他們的網站的。

    這次我們使用這個option來把上次的cookie信息追加到http request里面去: -b

    $ curl -x 123.45.67.89:1080 -o page1.html -D cookie0002.txt -b cookie0001.txt http://www.linuxidc.com

    這樣,我們就可以幾乎模擬所有的IE操作,去訪問網頁了!

    6)稍微等等    ~我好像忘記什么了    ~

    對了!是瀏覽器信息

    有些討厭的網站總要我們使用某些特定的瀏覽器去訪問他們,有時候更過分的是,還要使用某些特定的版本    NND,哪里有時間為了它去找這些怪異的瀏覽器呢!?

    好在curl給我們提供了一個有用的option,可以讓我們隨意指定自己這次訪問所宣稱的自己的瀏覽器信息: -A

    $ curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x 123.45.67.89:1080 -o page.html -D cookie0001.txt http://www.linuxidc.com

    這樣,服務器端接到訪問的要求,會認為你是一個運行在Windows 2000上的 IE6.0,嘿嘿嘿,其實也許你用的是蘋果機呢!

    而"Mozilla/4.73 [en] (X11; U; Linux 2.2; 15 i686"則可以告訴對方你是一臺 PC上跑著的Linux,用的是Netscape 4.73,呵呵呵

    7)另外一個服務器端常用的限制方法,就是檢查http訪問的referer。比如你先訪問首頁,再訪問里面所指定的下載頁,這第二次訪問的 referer地址就是第一次訪問成功后的頁面地址。這樣,服務器端只要發現對下載頁面某次訪問的referer地址不是首頁的地址,就可以斷定那是個盜 連了    ~

    討厭討厭 ~我就是要盜連    ~!!

    幸好curl給我們提供了設定referer的option: -e

    $ curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x 123.45.67.89:1080 -e "mail.linuxidc.com" -o page.html -D cookie0001.txt http://www.linuxidc.com

    這樣,就可以騙對方的服務器,你是從mail.linuxidc.com點擊某個鏈接過來的了,呵呵呵

    8)寫著寫著發現漏掉什么重要的東西了!——- 利用curl 下載文件

    剛才講過了,下載頁面到一個文件里,可以使用 -o ,下載文件也是一樣。比如,

    $ curl -o 1.jpg http://cgi2.tky.3web.ne.jp/~zzh/screen1.JPG

    這里教大家一個新的option: -O 大寫的O,這么用:

    $ curl -O http://cgi2.tky.3web.ne.jp/~zzh/screen1.JPG

    這樣,就可以按照服務器上的文件名,自動存在本地了!

    再來一個更好用的。

    如果screen1.JPG以外還有screen2.JPG、screen3.JPG、....、screen10.JPG需要下載,難不成還要讓我們寫一個script來完成這些操作?

    不干!

    在curl里面,這么寫就可以了:

    $ curl -O http://cgi2.tky.3web.ne.jp/~zzh/screen[1-10].JPG

    呵呵呵,厲害吧?! ~

    9)再來,我們繼續講解下載!

    $ curl -O http://cgi2.tky.3web.ne.jp/~{zzh,nick}/[001-201].JPG

    這樣產生的下載,就是

    ~zzh/001.JPG

    ~zzh/002.JPG

    ...

    ~zzh/201.JPG

    ~nick/001.JPG

    ~nick/002.JPG

    ...

    ~nick/201.JPG

    夠方便的了吧?哈哈哈

    咦?高興得太早了。

    由于zzh/nick下的文件名都是001,002...,201,下載下來的文件重名,后面的把前面的文件都給覆蓋掉了 ~

    沒關系,我們還有更狠的!

    $ curl -o #2_#1.jpg http://cgi2.tky.3web.ne.jp/~{zzh,nick}/[001-201].JPG

    —這是.....自定義文件名的下載? —對頭,呵呵!

    這樣,自定義出來下載下來的文件名,就變成了這樣:原來: ~zzh/001.JPG —-> 下載后: 001-zzh.JPG 原來: ~nick/001.JPG —-> 下載后: 001-nick.JPG

    這樣一來,就不怕文件重名啦,呵呵

    posted @ 2013-05-09 11:52 Chan Chen 閱讀(382) | 評論 (0)編輯 收藏

    2013年5月5日 #

    Java Web Application 遠程調試

    最近在開發java web application的時候,因為很多原因,無法對自己開發的項目在本地進行調試,常常需要進行遠程調試,之前一直通過打logger的方式進行,每次都要重新部署,相當的痛苦,今天下午研究了以下,如果進行遠程調試。

    開發的web application是部署在tomcat上面的,那么問題就轉化為如何調試tomcat。其實調試tomcat,本質上就是調試JVM。JVM的強大,從J2SE1.4.2開始,就實現了JPDA (Java Platform Debug Architecture)。

    tomcat默認情況下,是沒有啟用jpda的,如果要啟用,需要傳入參數
    -Xdebug -Xrunjdwp:transport=dt_socket, address=8000,server=y,suspend=y

    那么問題是這些參數如何在tomcat啟動的使用傳入呢?這是時候,需要了解tomcat的啟動腳本,在TOMCAT_HOME/bin

    目錄下,有三個腳本catalina.sh, startup.sh, 和 shutdown.sh。如果查看startup.sh和shutdown.sh,都是通過catalina.sh來啟動的。腳本如下:

    EXECUTABLE=catalina.sh

    exec "$PRGDIR"/"$EXECUTABLE" start "$@"
    于是,我們可以查看下catalina.sh的腳本是如何實現的。

    #   JPDA_TRANSPORT  (Optional) JPDA transport used when the "jpda start"
    #                   command is executed. The default is "dt_socket".
    #
    #   JPDA_ADDRESS    (Optional) Java runtime options used when the "jpda start"
    #                   command is executed. The default is 8000.
    #
    #   JPDA_SUSPEND    (Optional) Java runtime options used when the "jpda start"
    #                   command is executed. Specifies whether JVM should suspend
    #                   execution immediately after startup. Default is "n".
    #
    #   JPDA_OPTS       (Optional) Java runtime options used when the "jpda start"
    #                   command is executed. If used, JPDA_TRANSPORT, JPDA_ADDRESS,
    #                   and JPDA_SUSPEND are ignored. Thus, all required jpda
    #                   options MUST be specified. The default is:
    #
    #                   -agentlib:jdwp=transport=$JPDA_TRANSPORT,
    #                       address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND

    if [ "$1" = "jpda" ] ; then
      if [ -z "$JPDA_TRANSPORT" ]; then
        JPDA_TRANSPORT="dt_socket"
      fi  
      if [ -z "$JPDA_ADDRESS" ]; then
        JPDA_ADDRESS="8000"
      fi  
      if [ -z "$JPDA_SUSPEND" ]; then
        JPDA_SUSPEND="n"
      fi  
      if [ -z "$JPDA_OPTS" ]; then
        JPDA_OPTS="-agentlib:jdwp=transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND"
      fi  
      CATALINA_OPTS="$CATALINA_OPTS $JPDA_OPTS"
      shift
    fi

    通過這個代碼,我們可以看出,其實要啟動jpda, 最主要的是要對JPDA_SUSPEND的值進行設置,由N改為Y。

    借鑒start.sh的啟動,在linux下,我們可以自己創建一個jpda.sh的腳本,用來啟動開啟debug模式的tomcat,具體腳本如下,黑體為修改部分。

    os400=false
    darwin=false
    case "`uname`" in
    CYGWIN*) cygwin=true;;
    OS400*) os400=true;;
    Darwin*) darwin=true;;
    esac

    # resolve links - $0 may be a softlink
    PRG="$0"

    while [ -h "$PRG" ] ; do
      ls=`ls -ld "$PRG"`
      link=`expr "$ls" : '.*-> \(.*\)$'`
      if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
      else
        PRG=`dirname "$PRG"`/"$link"
      fi
    done
     
    PRGDIR=`dirname "$PRG"`
    EXECUTABLE=catalina.sh

    # Check that target executable exists
    if $os400; then
      # -x will Only work on the os400 if the files are: 
      # 1. owned by the user
      # 2. owned by the PRIMARY group of the user
      # this will not work if the user belongs in secondary groups
      eval
    else
      if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
        echo "Cannot find $PRGDIR/$EXECUTABLE"
        echo "The file is absent or does not have execute permission"
        echo "This file is needed to run this program"
        exit 1
      fi
    fi 

    export JPDA_SUSPEND=y

    exec "$PRGDIR"/"$EXECUTABLE" jpda start "$@"

     

    在Eclipse中遠程調試Tomcat

    首先將Tomcat 5.5.26的源代碼分為container connectors jasper servletapi build五個項目,導入到Eclipse中。啟動相關的代碼主要在container中,就以它為當前項目,打開”Debug Configurations“對話框。

    然后創建一個”Remote Java Application“,Connection Type選擇”Standard (Socket Attach)“,Host填寫localhost(Tomcat所在的主機地址),Port填寫8000。最后點擊”Apply“保存。

    Eclipse的Debug Configurations對話框中配置遠程調試

     

    首先確保已經執行了jpda.bat,Tomcat正在等待調試器連接;然后執行上述的Debug Configuration,Eclipse就可以連上Tomcat。

     

    Tomcat的啟動是從Bootstrap的main方法開始,我在第一行代碼處設置了斷點,Tomcat的啟動就停在了這一行:

     

    斷點調試Tomcat的啟動過程

     

    接著,讓Tomcat繼續執行,我們可以看到,控制臺輸出了啟動信息。

    Tomcat在JPDA模式下繼續啟動

    posted @ 2013-05-05 16:49 Chan Chen 閱讀(1627) | 評論 (0)編輯 收藏

    spring mvc singleton的驗證

    用了Spring MVC有一個多月了,之前雖然有接觸過一些,但是一直沒有在實際工作中使用。今天和同事聊起,談到Spring MVC中的Controller是單例實現的,于是就寫了一段代碼驗證一些。

    1. 如果是單例的,那么在Controller類中的實例變量應該是共享的,如果不共享,則說明不是單例。
    直接代碼:
    @Controller
    public class DemoAction {

        private int  i = 0;

        @RequestMapping(value = "/singleton")
        @ResponseBody
        public String singleton(HttpServletRequest request, HttpServletResponse response) throws InterruptedException {
            int addInt = Integer.parseInt(request.getParameter("int"));
            i = i + addInt;
            return String.valueOf(i);
        }
    }

    分別三次請求: localhost:8080/projectname/singleton?int=5
    得到的返回結果如下。
    第一次: i=5
    第二次: i=10
    第三次: i=15

    重結果可以得知,i的狀態是共享的,因此Controller是單例的。

    -------------------------------------------------------------------------------------------------------------------------
    2. 如果是單例,那么多個線程請求同一個Controller類中的同一個方法,線程是否會堵塞?
    驗證代碼如下:
        @RequestMapping(value = "/switcher")
        @ResponseBody
        public String switcher(HttpServletRequest request, HttpServletResponse response)
                throws InterruptedException {
            String switcher = request.getParameter("switcher");
            if (switcher.equals("on")) {
                Thread.currentThread().sleep(10000);
                return "switch on";
            } else {
                return switcher;
            }
        }

    驗證方法:
    分別發送兩個請求,
    第一個請求:localhost:8080/projectname/singleton?switcher=on
    第二個請求:localhost:8080/projectname/singleton?switcher=everything

    驗證結果:
    第一個請求發出去以后,本地服務器等待10s,然后返回結果“switch on”,
    在本地服務器等待的者10s當中,第二期的請求,直接返回結果“everything”。說明之間的線程是不互相影響的。
    -------------------------------------------------------------------------------------------------------------------------
    3.既然Controller是單例的,那么Service是單例的嗎?驗證方法和Controller的單例是一樣的。
    驗證代碼:
    Controller:
    @Controller
    public class DemoAction {

        @Resource
        private DemoService demoService;

        @RequestMapping(value = "/service")
        @ResponseBody
        public String service(HttpServletRequest request, HttpServletResponse response)
                throws InterruptedException {
            int result = demoService.addService(5);
            return String.valueOf(result);
        }
    }
        
    Service:
    @Service
    public class DemoService {
        private int i = 0;
        public int addService(int num){
            i = i + num;
            return i;
        }
    }

    分別三次請求: localhost:8080/projectname/service
    得到的返回結果如下。
    第一次: i=5
    第二次: i=10
    第三次: i=15

    重結果可以得知,i的狀態是共享的,因此Service默認是單例的。
    -------------------------------------------------------------------------------------------------------------------------
    相同的驗證方法,可以得出@Repository的DAO也是默認單例。





    posted @ 2013-05-05 13:49 Chan Chen 閱讀(671) | 評論 (0)編輯 收藏

    2013年5月4日 #

    Java MVC 比較

         摘要: Spring MVC PK Struts2 我們用struts2時采用的傳統的配置文件的方式,并沒有使用傳說中的0配置。spring3 mvc可以認為已經100%零配置了(除了配置spring mvc-servlet.xml外)。 Spring MVC和Struts2的區別: 1. 機制:spring mvc的入口是servlet,而struts2是filter(...  閱讀全文

    posted @ 2013-05-04 16:21 Chan Chen 閱讀(510) | 評論 (0)編輯 收藏

    僅列出標題  
    主站蜘蛛池模板: a毛看片免费观看视频| 亚洲资源最新版在线观看| 亚洲第一综合天堂另类专| 精品女同一区二区三区免费站| 爱情岛论坛网亚洲品质自拍| 最新亚洲人成网站在线观看 | 韩国免费三片在线视频| 亚洲成人网在线观看| 1000部拍拍拍18勿入免费凤凰福利 | 黄色大片免费网站| 亚洲国产一级在线观看| 精品国产免费一区二区三区| 亚洲精品乱码久久久久66| aaa毛片免费观看| 久久激情亚洲精品无码?V| 亚洲爆乳无码精品AAA片蜜桃| 国产三级在线免费| 国产成人毛片亚洲精品| 亚洲欧美日韩中文二区| 亚洲精品免费在线视频| 亚洲国产美女精品久久久久∴| 亚洲.国产.欧美一区二区三区| 亚洲欧洲精品成人久久曰| 91视频精品全国免费观看| 日韩精品人妻系列无码专区免费 | 一个人看的www免费视频在线观看 一个人免费视频观看在线www | 草久免费在线观看网站| 好男人视频在线观看免费看片| 久久亚洲美女精品国产精品| 一本久久免费视频| 亚洲AⅤ视频一区二区三区| 亚洲欧美日韩国产精品一区| 一二三四免费观看在线电影 | 亚洲国产精品一区第二页| 亚洲国产精品久久久久| 免费无码又爽又刺激网站 | 日日摸夜夜添夜夜免费视频| 国外成人免费高清激情视频| 亚洲a级片在线观看| 亚洲成人免费电影| 亚洲免费在线观看视频|