2017/3/27

梅特卡夫定律 Metcalfe's law


梅特卡夫定律 Metcalfe's law 是一個關於通訊網絡的價值和網絡技術的發展的定律,一個網絡的價值等於該網絡內的節點數的平方,而且該網絡的價值與聯網的用戶數的平方成正比。


這個定律是由 George Gilder 在 1993 年提出,為表彰 3Com 創辦人 Robert Metcalfe 對於 Ethernet 的貢獻而以他的姓氏命名。這個定律基本上是用來估算一個網路公司的潛在價值的,如果使用人數呈現的趨勢增長速度很快,自然會影響到這個服務的影響力,等同於這個網路服務的總價值會比目前帳面上的數字來得高很多。


根據這個定律,一個網絡的用戶數目越多,那麼整個網絡和該網絡內的每台電腦的價值也就越大。如果一個網路中有 n 個人,因為節點之間連線的數量共有 n×(n-1) 條,這個網路對於每個人的價值與網路中其他人的數量成正比,也就是網路對於所有人的總價值與 n×(n-1) 成正比。


90 年代以來,由於 Internet 呈現了這種超乎尋常的指數增長趨勢,而且爆炸性地向經濟和社會各個領域進行廣泛的滲透和擴張。電腦網路的數目越多,對經濟和社會的影響就越大。梅特卡夫法則揭示了互聯網的價值隨著用戶數量的增長而呈指數級速度增長的規則。


新技術只有在有很多人使用它的時候才會變得更有價值。使用某個網路服務的人越多,產品就變得越有價值,因為身邊已經很多人使用了,因而越能吸引更多的人來使用,漸漸地以指數增長的方式,提高了整個網路的總價值。


一個通訊系統中,如果只有一隻電話沒有任何價值,幾部電話的價值也非常有限,成千上萬部電話組成的通訊網路,才會把通訊技術的價值極大化。一項技術的用戶規模,會影響到它的整體價值。一旦形成必要用戶規模,新技術開發者在理論上可以提高對用戶的價格,因為這項技術的應用價值比以前增加了。



不過實際的網路世界並沒有那麼單純,因為人數增長到某個程度,就會開始停滯觸頂,進入和緩期,還會有一些其他的因素會影響這個服務,例如因為人數太多,造成了訊息爆炸的反效果,還有網路服務的使用者,會根據使用的世代不同而有很大的差異,因為新世代接受的是酷炫、沒有爸媽監控的新服務,很難有一個服務可以老少通吃,跨足到多個世代之間。


References


梅特卡夫定律 wiki


Metcalfe’s Law wiki


梅特卡夫法則(Metcalfe’s Law)


梅特卡夫定律 (Metcalfe's Law) 以iphone為例

2017/3/20

WebJars


在實作網頁服務時,常常會使用很多網頁前端的 framework,例如 jQuery, Bootstrap,以往在使用這些 framework 就只能下載這些 framework,然後自己放到開發的 app server 裡面,但這種手工管理的方式,對於套件的版本管理會造成很大的困擾,往往會搞不清楚哪些檔案是那些套件在使用的。


WebJars將這些常用的網頁前端 framework/library 都轉換成 Jar,然後借助 Maven 工具,讓我們可以用簡單的幾行 Maven 設定,就將整個 library include 到專案當中,也不會困擾要怎麼升級套件。只要是 JVM-based 的 web application 都能夠使用 Maven/Gradle/sbt/Ivy 等等 build tool 關聯到某個套件。


目前 WebJars 提供三種套件封裝的方式


  • NPM WebJars


    1. 任何人都可以發布資源
    2. 根據 NPM 鏡像資源即時建立並部署資源
    3. NPM 是 javascript 資源包的一種格式
  • Bower WebJars


    1. 任何人都可以發布資源
    2. 根據 Bower 鏡像資源即時建立並部署資源
    3. Bower 是 javascript css 資源包的一種格式
  • Classic WebJars


    1. 只能由 WebJars 官方團隊發布資源
    2. 人工封裝及部署資源
    3. 手動建立 RequireJs 設定

以 Scala Play 2 為例,我們使用 Classic WebJars 的 SBT/Play2 方式,在 build.sbt 中增加 bootstrap webjar 設定


libraryDependencies ++= Seq(
  "org.webjars" % "bootstrap" % "3.3.7-1"
)

可以在 IDE 中看到增加的 bootstrap 及 jquery 的 jar files。



另外要注意 routes 設定裡面要保留這一行


# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file              controllers.Assets.at(path="/public", file)

接下來就可以在網頁中使用 jquery 跟 bootstrap


http://localhost:9000/assets/lib/jquery/jquery.js

http://localhost:9000/assets/lib/bootstrap/css/bootstrap.css

從檔案管理員中可以看到整個 library 的資料很完整,bootstrap 也包含了 js extensions。



以往的 WebJars 網址會看到 library 的版本資訊,但現在這樣看起來是沒有版本資訊,這對於 library 更新的工作來說,會更節省一些時間。


References


WebJars介紹


WebJars servlet 3 使用示例


使用Maven匯入Webjars的bootstrap


Spring boot中使用WebJars


JavaWeb開發分享:WebJars


使用WebJar管理css、JavaScript文件


webjars 官方文件

2017/3/13

False Sharing 偽共享


在 multicore 的 CPU 電腦中,為了在多核心的狀況下,讓程式跑得更快,會把資料放在 cache 中,在 cache system 裡面儲存的記憶體的基本單位稱為 cache lines,通常 cache line 都是 2 的指數次方,也就是 32 ~ 256 bytes,最常見的 cache line size 為 64 bytes。


false sharing 發生在多核心執行不同的 threads 時,不同的thread修改到存在同一個 cache line 裡面不同的變數,因為頻繁地發生 cache invalidate,因此造成在多核心的狀況下,反而削弱了程式的效能。


為了避免這個問題,解決方式就是不要讓兩個以上的 threads 寫入同一個變數,或是 cache line。



這個圖片說明了 false sharing 發生的狀況,core 1 想要更新 X,core 2 想要更新 Y,但 X 與 Y 存放在同一個 cache line 中,每一個 thread 都需要競爭 cache line 的使用權,去更新變數的內容,當 core 1 取得 cache line 使用權,就會造成 core 2 的 cache invalidated,多次來來回回之後,影響了效能。


False Sharing


False Sharing-上面那篇的翻譯


提供了一個 java 的範例,文章中刻意製造了多個 threads,並實際計算在 multicore 的狀況下,耗費的時間,使用了連續七個沒有使用到的 long 變數,利用這個方法來避免讓多個 VolatileLong 放在同一個 cache line 裡面。


What is @Contended and False Sharing ?


The end for false sharing in Java?


Java 8 根據上面的方式,提供了一個新的 annotation @Contended,他可以用在兩個連續的變數之間,經過 compiler 自動加上 padding variables,用以避免這兩個變數被配置在同一個 cache line。


References


今天就以False-sharing就做為一天的結束吧


https://en.wikipedia.org/wiki/False_sharing


Avoiding and Identifying False Sharing Among Threads

2017/3/6

Digital Twin 數字化雙生


對Gartner發佈2017年十大技術趨勢的分析 文章中,討論一些新的技術趨勢,我們注意到其中兩個項目,(1) blockchain 區塊鏈 (2) Digital Twins
數字化雙生。


Blockchain:Internet問世以來最具破壞力的發明: 在啟動交易的一方,先建立一個資訊區塊(block),然後這個區塊會由網路上的幾千部、甚至幾百萬部電腦進行驗證。每一筆交易資訊都和它本身的變動歷史連結,並透過幾百萬部電腦來驗證,所以可以解決現有交易模式的信用問題。但目前在 blockchain 還在研究的過程,應該還需要一些時間才會在真實的環境上應用。


Digital Twin 數字化雙生是沒有聽過的名詞,數字化雙生(Digital Twin)是事物或系統的多元軟件模型,它依賴於傳感器數據來理解其處境,響應變化,改進操作和增加價值。


公司將使用數字化雙生主動修復和規劃設備服務、規劃製造流程、操作工廠、預測設備故障或提高運營效率,以及執行增強的產品開發。因此,數字化雙生最終將成為技術人員和傳統監測設備和控制(例如,壓力計,壓力閥)的組合的代理。


Digital Twin 可說是 IOT 未來,IOT 的重點強調收集資料,收集很多週邊環境的資料,收集很多週邊設備的資料,收集資料後可以進行分析與統計。


而 Digital Twin 在數位世界建造了一個真實世界的化身,這個化身可能會用到許多真實環境的資料,讓這個數位化身更貼近真實世界的原形,也可能用 3D 的方式,讓使用者可以使用這個虛擬化身,就像是在使用真實世紀的設備一樣。


Digital Twin 就是一種虛實融合的技術,建造一個分身的用途,無非是為了節省成本,不管是生產、測試、研發等等產品開發過程中,所耗費的成本,正因為真實世界的裝置或設備太過於昂貴,我們才需要一個虛擬的分身,可以不斷地進行分析、測試,並能隨時在損壞後就馬上復原回來。


都談Digital Twin,大咖各有解讀 提出了兩家不同公司,對 Ditigial Twin 有不同的理解。達索通過打造3D體驗平台實現Digital Twin的建立與交互,從而為具有極端複雜系統的客戶提供支持。PTC則致力於在虛擬世界與現實世界之間建立一個實時的連接,使PLM系統形成閉環,從而為客戶提供更具有競爭性和變革性的業務解決方案。


工業4.0術語:Digital Twin 數字孿生 提供了一個美國國防部的實例:到了2035年,當航空公司接收一架飛機的時候,將同時還驗收另外一套數字模型。每個飛機尾號,都伴隨著一套高度詳細的數字模型。」


每一台飛機都會伴隨著一個虛擬空間的飛機分身,透過傳感器實現與飛機真實狀態完全同步,每次飛行後,根據結構現有情況和過往載荷,即時分析評估是否需要維修,能否承受下次的任務載重等。


網宇實體系統(Cyber-Physical System, CPS) 本質就是 big data 運算,在真實實物跟數位分身之間的橋樑,CPS系統的本質就是人、機、物的融合計算,使用者、機器分身跟實物之間,三個角色的互動關聯。CPS 有著網際網路的、基於個性化服務的、基於數據決策的、基於高效節能的四大特質。


CPS 的實例1: MIT 的 Distributed Robot Garden,這個花園裡有一群的機器人負責照顧番茄。這個系統結合了感測網路(每一株植物上都有感測器會去監控植物狀態)、導航、機器人控制和無線網路。


CPS 的實例2: CarTel 計畫,這個計畫裡,有一隊的計程車會蒐集波士頓的即時交通資訊,路徑規劃就可以使用即時的交通資訊和歷史資訊規劃出最快的交通路徑。

2017/2/20

Spark tutorial


要使用 Spark 之前,一般會先遇到 scala 這個語言的熟悉度的問題,當有了一定的語言程度後,再來就是 scala IDE 的選擇,目前的狀況,還是IDEA 會比 scala IDE for Eclipse 好用。接下來就是下載跟安裝 spark,然後進行 WordCount 的範例練習,以下記錄怎麼安裝與設定 stand alone 的 spark 開發環境。


要下載哪一個 spark 套件


當我們連結到 Download Apache Spark 時,首先遇到的問題,就是要下載哪一個 spark release 套件。


基本的原則如下:


如果要直接下載已經編譯好的 binary 套件,我們可以根據 Hadoop 的版本決定要下載哪一個,但如果像我們一樣,不打算安裝 Hadoop 就直接測試,就直接選最新版的 spark-1.6.1-bin-hadoop2.6.tgz 就好了,下載後解壓縮,馬上就可以使用 spark-shell,或直接取得 all-in-one 的 spark-assembly-1.6.1-hadoop2.6.0.jar 套件。


如果我們要編譯 source code,就下載預設的 1.6.1(Mar 09 2016) spark release,Package type 選擇 Source Code:spark-1.6.1.tgz


由於目前 spark 預設是使用 scala 2.10 版,使用預先編譯的 spark 就必須要使用 scala 2.10 版,如果像要改成 2.11,就一定要自己重新編譯 spark,目前 spark 的 JDBC component 還不支援 scala 2.11。


Building for Scala 2.11 有兩行指令說明如何將 spark 由 2.10 調整為 2.11,我們同時把 hadoop 版本改為 2.6。


./dev/change-scala-version.sh 2.11
mvn -Pyarn -Phadoop-2.6 -Dscala-2.11 -DskipTests clean package

編譯 spark 要花的時間很久,以我現在的環境花了 40 分鐘。


[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 39:33 min
[INFO] Finished at: 2016-04-29T09:23:03+08:00
[INFO] Final Memory: 452M/2703M

也可以使用 sbt 來編譯 spark,編譯後會得到 spark-assembly 的 jar。


sbt/sbt assembly

如果要修改 spark souce code,可以啟用增量編譯模式,避免每一次修改都要花很久的時間重新編譯。


export SPARK_PREPEND_CLASSES=true
sbt/sbt compile

unset SPARK_PREPEND_CLASSES

在 compile 前面加上 ~ 可以避免每一次都重開一次新的 sbt console


sbt/sbt ~ compile

可以用 sbt 或是 mvn 指令查閱 dependency map


sbt/sbt dependency-tree

mvn -DskipTests install
mvb dependency:tree

如果要設定 spark source 的開發環境,可以用以下的指令產生 IDEA project file


git clone https://github.com/apache/spark
sbt/sbt gen-idea

Spark 開發環境 in IDEA


  1. 在 IDEA 建立新的 scala project: sparktest

  2. 在 project 中建立一個 lib 目錄,把 spark-assembly-1.6.1-hadoop2.6.0.jar 放在那個目錄中

  3. 在 File -> Project Structure -> Libraries 點 "+",然後把 lib 目錄加入 project 中

  4. 取得一個文字檔的測試資料 pg5000.txt ,將檔案放在新建立的 data 目錄中

  5. 將 RunWordCount.scala 放在 src 目錄中,程式會計算 pg5000.txt 裡面每一個字出現的數量


    import org.apache.log4j.Logger
    import org.apache.log4j.Level
    import org.apache.spark.{ SparkConf, SparkContext }
    import org.apache.spark.rdd.RDD
    
    object RunWordCount {
      def main(args: Array[String]): Unit = {
    
        // 以這兩行設定不顯示 spark 內部的訊息
        Logger.getLogger("org").setLevel(Level.OFF)
        System.setProperty("spark.ui.showConsoleProgress", "false")
    
        // 清除 output folder
        FileUtils.deleteDirectory(new File("data/output"))
    
        println("執行RunWordCount")
    
        // 設定 application 提交到 MASTER 指向的 cluster 或是 local 執行的模式
        // local[4] 代表是在本地以 四核心的 CPU 執行
        val sc = new SparkContext(new SparkConf().setAppName("wordCount").setMaster("local[4]"))
    
        println("讀取文字檔...")
        val textFile = sc.textFile("data/pg5000.txt") 
    
        println("開始建立RDD...")
        // flapMap 是取出文字檔的每一行資料,並以 " " 進行 split,分成一個一個的 word
        // map 是將每一個 word 轉換成 (word, 1) 的 tuple
        // reduceByKey 會根據 word 這個 key,將後面的 1 加總起來,就會得到 (word, 數量) 的結果
        val countsRDD = textFile.flatMap(line => line.split(" "))
          .map(word => (word, 1))
          .reduceByKey(_ + _) 
    
        println("儲存結果至文字檔...")
        try {
          countsRDD.saveAsTextFile("data/output") 
          println("存檔成功")
        } catch {
          case e: Exception => println("輸出目錄已經存在,請先刪除原有目錄");
        }
    
      }
    }
  6. 我們可以直接在 IDEA 就執行這個測試程式


    執行RunWordCount
    Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
    16/04/29 16:28:50 INFO Slf4jLogger: Slf4jLogger started
    16/04/29 16:28:50 INFO Remoting: Starting remoting
    16/04/29 16:28:50 INFO Remoting: Remoting started; listening on addresses :[akka.tcp://sparkDriverActorSystem@192.168.1.151:56205]
    讀取文字檔...
    開始建立RDD...
    儲存結果至文字檔...
    存檔成功
    
    Process finished with exit code 0
  7. 最後產生的結果有三個檔案,其中 part-00000 及 part-00001 裡面存了每一個 word 的發生次數


    _SUCCESS
    part-00000
    part-00001

會產生兩個檔案的原因是因為,spark 本身是平行運算的工具,所以會自動產生多個 partitions。


如果需要將結果整合成一個檔案,就必須使用 coalesce,在程式的最後面,用 countsRDD.coalesce(1).saveAsTextFile 將結果輸出到新目錄,也會得到一個檔案的結果。


try {
      countsRDD.coalesce(1).saveAsTextFile("data/output2")
      println("存檔成功")
    } catch {
      case e: Exception => println("輸出目錄已經存在,請先刪除原有目錄");
    }

匯出程式


  1. 在 IDEA 選擇 "File" -> "Project Structure" -> "Artifact"

  2. 點擊 "+" -> "JAR" -> "From modules with dependencies"

  3. Main Class 填成 "RunWordCount",輸出目錄的最後面改為 "out"

  4. 選擇 "Build" -> "Build Artifacts",就能在 out 目錄取得 sparktest.jar 檔

  5. 這樣就能在另一台機器執行 sparktest


java -jar sparktest.jar

References


HADOOP+SPARK大數據巨量分析與機器學習整合開發實戰


Spark大資料分析實戰