2015年9月23日 星期三

Spark Standalone Cluster 練習

承接上次架設的Spark環境,這次想試試 Spark Cluster, Spark Cluster事實上有分3種模式,但我目前只有單機,所以選擇了了Standalone的方式,以下就是這次的練習。
This is reference link
http://mbonaci.github.io/mbo-spark/

首先找到上次安裝Spark的目錄,是在usr/lib下



接著進入到/sbin的目錄下,因為執行的指令是放在這裡,而不是bin喔

執行指令 ./start-master.sh
接著根據上面的訊息,我們去打開 log file看看
你可以試著在瀏覽器打開會發現如下你會發現已經啟動了一個WebUI在port 8081 (我8080有tomcat)
請注意畫面上7077 port是 sparkMaster的 service port跟WebUI的port是不同的
接著理論上我們應該回到/sbin下執行 ./start-slave.sh指令
但是 我們接著要先做2件事
(1)為了要讓 Master可以管理到 slave,必須透過 ssh-keygen 來達到 trust
(2)假設每次要啟動 slave 都要執行一次執行,那要4台的話就得執行4次有點麻煩,因為可透過config一個檔案後,只需執行1次就可以產生4台 slave

步驟(1)
由於需要使用ssh,所以事先得先安裝好openssh,執行指令 ssh-keygen後
再執行 ssh-copy-id 將檔案複製你的本機下(username@localhost name),如圖
(2)至 /conf目錄下執行 cp spark-env.sh.template spark-env.sh 指令
將範例設定檔複製並更改檔名為 spark-env.sh,這個檔案一般來說執行 spark指令後會先來找此檔案的設定,接著新增一個設定至該檔案執行export SPARK_WORKER_INSTANCES=4指令 如圖



自己可以試著 cat 看看 是否已將設定配置好在 spark-env.sh

########################################################
完成上述的前置作業後,我們可以回到/sbin下準備執行 ./start-slave 指令了,執行該指令必須指定一個 Spark-master service的位置,所以我們執行如下圖
此時回到剛才 master 的 WebUI 重新整理一下 看是否已經可以 monitor到 slave了
#注意一下 剛才指令是使用 ubuntu-i386-2 而不是使用 localhost或是IP,是因為剛才 keygen我是指定這個名稱,這個很重要,否則master會無法看到上面的畫面

#恭喜,此時已經成功建置了一個 Standalone cluster




2015年9月15日 星期二

Spark on Ubuntu 離線安裝(第一次就上手)

日前老闆告訴我客戶有Big Data的需求,想使用Spark...
於是乎我就開始了我第一個學習的旅程
首先 由於客戶的環境是封閉的 也就是說我想安裝的軟體都必須「離線」安裝
參考了一些教學 發現大多數的作業系統是採用 Ubuntu
所以我使用 Ubuntu15.04版,以下是安裝的幾個重點我是使用VM的方式
我自己的電腦是Windows

1.安裝OS的過程中,會出現請你config network,這邊可以先設定好你的static ip,gateway等等

這樣系統啟動的時候你就已經設定好ip了
如果不幸的你略過了這些設定或者設定錯了,你可以參考下面網址
Ubuntu網路設定 或是 Red Hat網路設定 這2個網站的主要是打開2個檔案更改設定
更改完使用 sudo /etc/init.d/networking restart 指令 重新啟動網路服務 就會吃到設定
#如果不幸仍未能成功請重啟OS看看
1.1Ubuntu安裝至後面會請你選要安裝的軟體,請把 OpenSSH勾選安裝起來,如果有需要FTP也可裝,主要是我們需要使用OpenSSH連線及傳送檔案

2.至Spark官網 download 較新的Spark ,Type選 per-built的版本,可以省時間

3.由於 Spark需要使用到JDK,所以可至Download JAVA官方download至自己的電腦(Windows)
#其實OS裝完裡面已有內建的OpenJDK了,但習慣上還是Oracle的據說Complier比較不易出錯
4.使用你的root user登入Ubuntu後建立一個目錄放我們要傳過去的檔案(Spark&JDK),我使用
#傳送檔案我是使用WinSCP工具(可自己搜尋download)

以下是我的一連串的指令


cd /
sudo mkdir install_source
cd install_source
# tar -zxvf spark-1.4.0-bin-hadoop2.6.tgz
# sudo mv spark-1.4.0-bin-hadoop2.6 /usr/lib
tar -zxvf jre1.8.0_60.gz
# sudo mv jre_1.80_60 /usr/lib
# vi /etc/bash.bashrc

最後重新連線

試著
# echo $JAVA_HOME
# java -version
如果不幸的 home是正常的但version仍是採用內建的OpenSDK

最後試著執行 #Spark-shell 看是否可正常啟動 Spark
啟動後如下圖

恭喜至此你已經安裝成功了

既然已經安裝成功,於是我們想要試著執行第一支範例程式
首先我們先離開spark-shell採用指令
# exit
接著執行指令
#run-example SparkPi 4
如下圖會出現Spark內建的範例程式,計算圓周率以及啟動一個WebUI在4040 port



至於真正的範例程式在
/usr/lib/spark-1.4.0-bin-hadoop2.6/examples/src/main/scala/org/apache/spark/examples
路徑下 檔案 SparkPi.scala
有興趣的可以 vi 一下,觀察裡面的 code你會發現 Spark的寫法比起 Hadoop寫法精簡許多喔!

恭喜你已經完成了第一個 Spark 範例程式的執行嘍^^






2015年6月24日 星期三

使用 GitHub 工具 SourceTree 問題

最近 在學習使用 GitHub, SourceTree是不少人推薦的Client工具
一開始使用都很順暢,但最近由於公司網路問題 導致我必須設定Proxy Server
才可以對外連線

就在此時悲劇發生了,我在SourceTree無法Push新的檔案至我的 BitBucket <Git路徑>
教學請參考 BitBucket & SourceTree教學

我使用 command line的方式來執行 push,但發生如下圖的錯誤


一開始我以為是驗證問題,所以我使用下面指令更改成 http

在重新執行一次 一樣出現類似上面的錯誤,只是443改為80

於是透過網路查詢 發現 若是驗證錯誤 會有類似 Http 401的錯誤
所以當下直覺是網路問題(我用瀏覽器連結都正常,可開啟BitBucket)

最後看到這篇回答,想到有可能是 proxy的問題

於是我修改我的proxy於cmd,如下圖

在重新執行一次 push 指令,就可以成功上傳到至BitBucket了
真是折煞人啊~*

初探 D3.js Multi Line Chart

最近因為客戶有將統計資料繪圖的需求
而開始研究D3.js 之前我大多使用 jQuery or JQWidgets的套件來繪圖
聽說使用D3前懂點 JQuery是好事,廢話不多說來切入今天的主題吧!
----------------------------------------------------------------------------------------
首先 D3是 Data Driven Document,所以data來源格式非常重要
現在大多是使用 JSON格式,且流行用Restful的模式
故我程式的範例也是使用 JSON來呼叫
而客戶又有 Mouserover & Legend的需求,這部分讓D3用起來更Complex

一開始的學習我建議可以參考d3 Line Chart教學
而這個網址是我在JSFiddle建立的範例,修改之前的教學http://jsfiddle.net/YenYu/hxn9L3cz/1/

以下為我的程式碼及預設的測試資料

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>MultiLine Chart</title>
<style>

#chart {
  font: 16px Arial;
  font-weight: 50;
  background: #fff;
}

text { 
  color: #000;
  stroke: #000;
  fill: #000;
}

path {
stroke: DodgerBlue;
stroke-width: 1;
fill: none;
}

.axis line {
  fill: none;
  stroke: lightgray;
  shape-rendering: crispEdges;
}

.x.axis path {
  display: #fafafa;
}

.x.axis .minor {
  stroke-opacity: .5;
}

.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}

.overlay {
  fill: none;
  pointer-events: all;
}

.focus circle {
  fill: none;
  stroke: #0078ff;
}

.legend {
    font-size: 16px;
    font-weight: normal;
}

</style>
</head>
<body>
<div id="chart"></div>
</body>
<!--<script src="http://d3js.org/d3.v3.js"></script> -->
<script src="js/d3.min.js"></script>
<script>

var margin = {top: 50, right: 80, bottom: 50, left: 50},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var parseDate = d3.time.format("%Y%m%d").parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left;


var x = d3.time.scale()
    .range([0, width]);

var y = d3.scale.linear()
    .range([height, 0]);

var color = d3.scale.category10();

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom").orient('bottom').tickSize(-height).tickSubdivide(false);

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var line = d3.svg.line()
    .interpolate("linear")
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.count); });

var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");   

d3.json("http://192.168.73.1:2013/JQuery_Test/data/data2.txt", function(error, data) {

 //color.domain(d3.keys(data,function(d){d.name}));
  
  var unusualSummary = data.map(function(j) {
    return {
      name: j.name,
      values: j.values.map(function(d) {
        return {date: parseDate(d.date), count: d.count};
      })
    };
  });
console.log('data: ' + JSON.stringify(data));
  x.domain([
  d3.min(unusualSummary, function(c) { return d3.min(c.values, function(v) { return v.date; }); }),
    d3.max(unusualSummary, function(c) { return d3.max(c.values, function(v) { return v.date; }); })
  ]);

  y.domain([
    0,d3.max(unusualSummary, function(c) { return d3.max(c.values, function(v) { return parseInt(v.count); }); }) + 1
  ]);

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
      .append("text")
      .attr("x", 850)
      .style("text-anchor", "middle")
      .text("日期 ");

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
      .append("text")
      .attr("transform", "rotate(0)")
      .attr("x", 7)
      .attr("y", -7)
      .attr("dy", ".71em")
      .style("text-anchor", "start")
      .text("次數 ");

  var statstic = svg.selectAll(".statstic")
      .data(unusualSummary)
      .enter().append("g")
      .attr("class", "statstic");

  var lSpace = width/data.length;
      
  data.forEach(function(d,i) {
 
                        statstic.append('path')
                        .attr('d', function(d){return line(d.values,x,y);})
                        .style('stroke', function(d,j) { 
                                return color(d.name);
                        })
                        .attr('stroke-width', 2)
                        .attr('id', 'line_'+d.name)
                        .attr('fill', 'none');
                        console.log('d name part I: ' + d.name);
                         statstic.append("text")
                            .attr("x", (lSpace/2)+i*lSpace)
                            .attr("y", height+30)                     
                            .style("fill", color(d.name))
                            .attr("class","legend")                                                
                            .text(d.name+" ---").style("stroke", color(d.name));
                        
                    });

  var focus = svg.append("g")
      .attr("class", "focus")
      .style("display", "none");

for(var i=0;i<unusualSummary.length;i++){
              focus.append("g")
                .attr("class", "focus"+i)
                .append("circle")
                .attr("r", 6.5);
              svg.select(".focus"+i)
                .append("text")
                .attr("x", 9)
                .attr("dy", ".35em");
          }


 statstic.append("rect")
      .attr("class", "overlay")
      .attr("width", width)
      .attr("height", height)
      .on("mouseover", function() { focus.style("display", null); })
      .on("mouseout", function() { focus.style("display", "none");})
      .on("mousemove", mousemove);
  
  function mousemove() {
//alert('length: ' + unusualSummary.length);
var x0 = x.invert(d3.mouse(this)[0]);               
   for(var k=0;k<unusualSummary.length;k++){
  
   var i  = bisectDate(unusualSummary[k].values, x0, 1);
   
   var d0 = unusualSummary[k].values[i - 1];
   
   var d1 = unusualSummary[k].values[i];
  
   var d = x0 - d0.date > d1.date - x0 ? d1 : d0;
   
var format = d3.time.format('%e %b');
var selectedFocus = svg.selectAll(".focus"+k);
selectedFocus.attr("transform", "translate(" + x(d.date) + "," + y(d.count) + ")");
    selectedFocus.select("text").text(format(d.date)+","+d.count+"次");
    
   
   }
                
    
  }   
  
});
</script>
</html>

我的Data範例如下,請自己在WebContent下建一個js的目錄放置js檔及測試檔
[
  {
    "name":"系統A", 
"values":[{"date":"20111001", "count":"1"},
         {"date":"20111002", "count":"2"},
              {"date":"20111003", "count":"3"},
              {"date":"20111004", "count":"4"},
              {"date":"20111005", "count":"5"},
              {"date":"20111006", "count":"6"}]
  },
  {
    "name":"系統B", 
"values":[{"date":"20111001", "count":"2"},
              {"date":"20111002", "count":"4"},   
              {"date":"20111003", "count":"6"},
              {"date":"20111004", "count":"8"},
              {"date":"20111005", "count":"10"},
              {"date":"20111006", "count":"12"}]
  },
  {
    "name":"系統C", 
"values":[{"date":"20111001", "count":"3"},
              {"date":"20111002", "count":"6"},   
              {"date":"20111003", "count":"9"},
              {"date":"20111004", "count":"12"},
              {"date":"20111005", "count":"15"},
              {"date":"20111006", "count":"18"}]
  },
  {
    "name":"系統D", 
"values":[{"date":"20111001", "count":"4"},
              {"date":"20111002", "count":"8"},   
              {"date":"20111003", "count":"12"},
              {"date":"20111004", "count":"16"},
              {"date":"20111005", "count":"20"},
              {"date":"20111006", "count":"30"}]
  }

]  

最後呈現的結果為




2015年3月2日 星期一

測試檔案上傳及下載的WebService with Java

最近為了撰寫有關檔案upload and download的WS先試寫了Sample Code with Java

WebService 程式如下

     @WebMethod
      public void upload(@WebParam(name = "fileName")String fileName, byte[] imageBytes) {
       
      String filePath = "d:/MsgServerUpload/" + fileName;
       
      try {
          FileOutputStream fos = new FileOutputStream(filePath);
          BufferedOutputStream outputStream = new BufferedOutputStream(fos);
          outputStream.write(imageBytes);
          outputStream.close();
           
          System.out.println("Received file: " + filePath);
           
      } catch (IOException ex) {
        System.out.println("Exception from here");
          System.err.println(ex);
          throw new WebServiceException(ex);
      }
}
 
     @WebMethod
      public byte[] download(String fileName) {
      String filePath = "d:/MsgServerDownload/" + fileName;
      System.out.println("Sending file: " + filePath);
       
      try {
          File file = new File(filePath);
          FileInputStream fis = new FileInputStream(file);
          BufferedInputStream inputStream = new BufferedInputStream(fis);
          byte[] fileBytes = new byte[(int) file.length()];
          inputStream.read(fileBytes);
          inputStream.close();
           
          return fileBytes;
      } catch (IOException ex) {
          System.err.println(ex);
          throw new WebServiceException(ex);
      }      
  }

請容許我稍微解釋一下這2個Method的路徑,d:/MsgServerUpload/ 是指 user在呼叫WS後,會將使用者上傳的的檔案放在Web Server的該路徑下,也就是說上傳的檔案都會放在這裡啦!
那d:/MsgServerDownload/當然是我在Server上放的要供使用者download的目錄
也就是,使用者upload or download的路徑我都事先預設好了,當然你的Web Server下要有該目錄喔!

接著我們可以寫個Java版的測試WS是否可呼叫成功
完整的程式碼如下,我用的方式必須先將WS利用NetBean開WS Build成WSClient.jar才能呼叫API

package com.sti.ws.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.namespace.QName;

import com.sti.web.msg.webservice.Exception_Exception;
import com.sti.web.msg.webservice.MSGWebService;
import com.sti.web.msg.webservice.MSGWebService_Service;


public class TestWS {

    public static void main(String[] args) {
   MSGWebService msgws = getMsgWS();
   try {
    String fileName = "test.txt";
   
       String filePath = "d:/YourLocalFileFolder/" + fileName;
       File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream inputStream = new BufferedInputStream(fis);
            byte[] imageBytes = new byte[(int) file.length()];
            inputStream.read(imageBytes);
             
            msgws.upload(file.getName(), imageBytes);
            
            inputStream.close();
            System.out.println("File uploaded: " + filePath);
        } catch (IOException ex) {
        ex.printStackTrace();
            System.err.println(ex);
        }
   
   
   try {
   //指定要download的檔名
   String fileName = "test1.txt";
   //要求download到哪裡
        String filePath = "d:/YourLocalDownloadFolder/" + fileName;
        byte[] fileBytes = msgws.download(fileName);
         
      
            FileOutputStream fos = new FileOutputStream(filePath);
            BufferedOutputStream outputStream = new BufferedOutputStream(fos);
            outputStream.write(fileBytes);
            outputStream.close();
             
            System.out.println("File downloaded: " + filePath);
        } catch (IOException ex) {
            System.err.println(ex);
        }*/
   
   
    }

private final static String MSGWS_WSDL_LOCATION;
private final static String MSGWS_QName;
private final static String MSGWS_qname;

static {
MSGWS_WSDL_LOCATION = "http://192.168.73.1:7001/YourWebService?wsdl";
MSGWS_QName = "http://webservice.msg.web.sti.com/";
MSGWS_qname = "MSGWebService";
}

public static MSGWebService getMsgWS() {
if(MSGWS_WSDL_LOCATION == null || "".equals(MSGWS_WSDL_LOCATION)) {
} else {
try {
URL url = new URL(MSGWS_WSDL_LOCATION);
QName qname = new QName(MSGWS_QName, MSGWS_qname);
MSGWebService service = new MSGWebService_Service(url, qname).getMSGWebServicePort();
System.out.println("OK");
return service;
} catch(MalformedURLException me) {
System.out.println("Fail");
me.printStackTrace();
System.out.println(me.getMessage());
}
}
return null;
}

}

我在範例測試程式裡,將我Local下的 test.txt檔案上傳,上傳成功後,您會發現你的Web Server下的d:/MsgServerUpload/有你剛才上傳的檔案,
而在download的範例程式,我假設在Web Server的d:/MsgServerDownload/目錄下
有一個檔案叫做 test1.txt,注意你必須先做好一個檔案放至此目錄下
接著指定我要download到我Local的d:/YourLocalDownloadFolder/ 路徑下就會出現一個叫做test1.txt的檔案了

為什麼我要分開目錄呢,是為了區別來自於不同的程式,你可以把WS程式的目錄指向同一個,也就是說自己Local上傳的檔案,也可以透過WS自己DownLoad回來。

Cheers




2014年12月18日 星期四

解決 Splunk Forwader 傳送 WLS Log to Splunk Server 中文亂碼問題

這個問題困擾了我很久,雖然有比較不好的解法(效率較差,such as FTP)
但現在單純修改 Splunk Forwarder內的設定即可

一開始看官網,很容易會以為是要修改 Splunk Server上的設定
實際上是要修改 Splunk Forwarder的設定即可
首先至 Splunk Forwarder安裝的目錄下 /etc/system/default
複製一份 props.conf 至 /etc/system/local [這是 Splunk 官方的建議]
就是以後修改,以修改此 props.conf為主,不要修改 default.conf

在檔案的最下方,新增如下2行(注意大小寫)

[wls_log]
CHARSET = BIG5

*****這兩行的意思是,傳輸 sourcetype=wls_log的檔案,將編碼設定 BIG5*****

將Splunk Forwarder停止
登入至Splunk Server,刪除先前由此台WLS Log Server所傳進來的檔案

sourcetype=wls_log | delete  (注意,admin必須事先設定擁有刪除的權限)

重新啟動 Splunk Server

啟動 Splunk Forwarder

建立一筆有中文的 Log, 至Splunk Server查詢吧!

2014年11月30日 星期日

Using Oracle jrockit jConsole monitor WebLogic with remoto server

最近在研究使用jmx來monitor WebLogic
首先我使用的WebLogic版本是10.3.3,安裝時設定成 Production mode
若有安裝過的話,通常 Oracle建議 Production mode使用 jrockit ,developer mode則用 jdk
因此我們現在應該是透過 jrockit 來 monitor,首先找到 jConsole的執行檔
它位於你安裝 jrockit 所在的目錄下/bin裡面

找到後,你可以直接點二下執行,但這是採用 Local 的方式去monitor,會抓取你目前的 java instance,這邊我們不討論。

那麼該如何使用 remote 的方式去 monitor 呢?
首先至你想要 monitor 的 WLS Server 開啟 WLS Admin Console-->伺服器-->your server name-->通訊協定-->啟用 IIOP(勾選)-->點選進階後設定 IIOP預設帳密,如圖


接著在你的 cmd 下 使用指令呼叫 jConsole吧!
我這邊示範是基本的呼叫方式,呼叫完後一樣會出現 jConsole的視窗
請在上面打上
service:jmx:iiop://hostname:port/jndi/weblogic.management.mbeanservers.runtime
請自行替換你的 hostname and port,下面就是你剛剛設定的IIOP帳密
如圖:

如果看到上圖畫面,就代表你成功嘍!,接著你就可以點選你想要看的資訊了。