2014年9月24日 星期三

使用 HttpURLConnection 時的記憶體問題

以前同事寫的 HttpClient 套件,實作是靠 Java 原生的 HttpURLConnection
不過最近又發生了使用該 HttpClient 套件時,出現 OutOfMemoryError 的訊息
發生原因是因為透過該 HttpClient 傳輸的資料太大,把 JVM 的記憶體撐爆了。

花了一些時間搜尋後,同事發現在 HttpClient 裡面加上 HttpURLConnection.setChunkedStreamingMode(0) 後問題似乎就解決了。
而關於為什麼有這個問題、以及為什麼呼叫這個方法後就可以解決,原因大概可以參考 [1] 的描述。
以下節錄 [1] 文章開頭的兩段話:
post請求的OutputStream實際上不是網絡流,而是寫入內存,在getInputStream中才真正把寫道流裡面的內容作為正文與根據之前的配置生成的http request頭合並成真正的http request,並在此時才真正向服務器發送。

HttpURLConnection.setChunkedStreamingMode函數可以改變這個模式,設置了ChunkedStreamingMode後,不再等待OutputStream關閉後生成完整的http request一次過發送,而是先發送http request頭,正文內容則是網路流的方式實時傳送到服務器。實際上是不告訴服務器http正文的長度,這種模式適用於向服務器傳送較大的或者是不容易獲取長度的數據,如文件。

參考資料:
1、Http学习之使用HttpURLConnection发送post请求深入
2、HttpUrlConnection.setChunkedStreamingMode()

2014年9月23日 星期二

實作 Java 的套件系統(Plugin System):以 jspf 框架為例

在開發比較大一點的系統時,常會有個想法是想要做到可以讓使用者動態下載套件,然後系統就能夠即時把套件套用到系統上
在 Java 上這個概念可以透過 ClassLoader 的技巧來實現。
雖然網路上也有一些文章教導如何自行建立簡單的套件系統,不過現在其實也有一些 Open Source 的專案可以利用了~。

2014年9月18日 星期四

MongoDB 監控:使用 MongoDB Management Service

MongoDB 官方有提供 MongoDB Management Service (MMS) 這個服務
可以用來監控指定的 MongoDB 資料庫,並且畫出還蠻詳細的曲線圖供使用者分析自己的資料庫運作狀況。


MMS 主要有提供監控和備援的能力,其中監控的部份是免費的、備援則是必須付費。
同時 MMS 提供了雲端版的服務和獨立安裝版,前者可以直接把統計資料送到 MongoDB 營運的 MMS 服務,後者則是自己維護一台自有的 MMS 主機。
對前者來說,使用者只需要註冊一個 MMS 的帳號,然後在能夠存取想監控的 MongoDB 的一台主機上安裝監控的代理人程式即可。
不過如果有些監控的功能想使用(例如 profiling 功能,會送出每個 MongoDB 接受的指令到 MMS 上),但又不希望這些資料被送上雲端
就可以改用後者,自己安裝自己的 MMS 囉。

2014年8月13日 星期三

mei 0000:00:16.0: initialization failed.

在伺服器上安裝 ubuntu 14.04 時,遇到安裝完以後出現這個錯誤訊息,然後伺服器就停止開機了。
mei 0000:00:16.0: initialization failed.

可能的原因如 [1] 中原 PO 自己的回應,mei 似乎是 Intel(R) Management Engine Interface 的驅動程式
如果安裝的主機的 CPU 不支援 Intel® vPro™ 技術,就有可能導致 mei 啟動產生問題。

解決方法是讓 ubuntu 啟動時將 mei 加入黑名單。
sudo echo  "blacklist mei" > /etc/modprobe.d/mei.conf

而在開機時出現問題,沒辦法輸入上述指令時,可以透過 ubuntu recovery 模式中選擇 ROOT 開啟 console 介面
不過在 console 介面預設是唯讀模式,必須先掛載 [2] 之後才能進行檔案操作。
mount -o rw,remount /

參考資料:
1、mei 0000:00:16.0: init hw failure
2、Recovery Console always read-only mode

2014年8月12日 星期二

GPG error: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY

在嘗試安裝 Foxwiki 時,遇到手動加入 deb 位址時,apt-get 無法正確存取,解決方式如 [1] 的回應所說。
例如 Foswiki 出現的錯誤訊息如下:
W: GPG error: http://fosiki.com stable Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 379393E0AAEE96F6
則輸入的指令是:
gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv 379393E0AAEE96F6
gpg --export --armor 379393E0AAEE96F6 | sudo apt-key add -

系統回應的結果如下:
root@ubuntu:~# gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv 379393E0AAEE96F6
gpg: directory `/root/.gnupg' created
gpg: new configuration file `/root/.gnupg/gpg.conf' created
gpg: WARNING: options in `/root/.gnupg/gpg.conf' are not yet active during this run
gpg: keyring `/root/.gnupg/secring.gpg' created
gpg: keyring `/root/.gnupg/pubring.gpg' created
gpg: requesting key AAEE96F6 from hkp server keyserver.ubuntu.com
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key AAEE96F6: public key "Fosiki Software Releases (Release signing user) <Releases@fosiki.com>" imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
root@ubuntu:~# gpg --export --armor 379393E0AAEE96F6 | sudo apt-key add -                                                                                                        OK

參考資料:
1、How do I fix the GPG error “NO_PUBKEY”?

2014年8月7日 星期四

OpenStack Nova 使用外部 DHCP 的設定方法

最近試了蠻久的 OpenStack 設定,目前最新版的 icehouse 版本有 Neutron 這個網路套件
不過我們實驗了一段時間,一直沒辦法把 Neutron 設定好
後來改嘗試完全不使用 Neutron,而是使用原本 Nova 自帶的 Nova Network 套件。

其中因為我們暫時的目標是要能夠透過 ssh 直接連上 OpenStack 上的虛擬機器,因此設定選用 FlatManager 這個最基本的網路設定。
補充:FlatManager 在某些方面不太被認同,可以參考 [8] 的討論。

2014年7月24日 星期四

使用 log4j 時,讓 Apache HttpClient 的 log 消失

如果有同時使用 log4j 和 HttpClient,應該很多人都有這個慘痛的經驗~
HttpClient 在執行時會把所有發送和接收的資料全部以 debug 等級的 log 輸出到 log4j
一般在做 JSON 處理時還好,這個 log 大概對於 debug 蠻有幫助的
但如果是在實作檔案上傳或者下載時,印出來的 log 等於是把要上傳或下載的檔案全部輸出到 log4j,是相當驚人的文字量
而且有時候會把 eclipse 弄到當機...。

2014年7月18日 星期五

java.lang.ArrayIndexOutOfBoundsException: 48188

莫名其妙遇到的問題....錯誤訊息如下:

嚴重: StandardWrapper.Throwable
java.lang.ArrayIndexOutOfBoundsException: 48188
        at org.objectweb.asm.ClassReader.readClass(Unknown Source)
        at org.objectweb.asm.ClassReader.accept(Unknown Source)
        at org.objectweb.asm.ClassReader.accept(Unknown Source)
        at com.sun.jersey.spi.scanning.AnnotationScannerListener.onProcess(AnnotationScannerListener.java:136)
        at com.sun.jersey.core.spi.scanning.JarFileScanner.scan(JarFileScanner.java:97)
        at com.sun.jersey.spi.scanning.servlet.WebAppResourcesScanner$1.f(WebAppResourcesScanner.java:94)
        at com.sun.jersey.core.util.Closing.f(Closing.java:71)
        at com.sun.jersey.spi.scanning.servlet.WebAppResourcesScanner.scan(WebAppResourcesScanner.java:92)
        at com.sun.jersey.spi.scanning.servlet.WebAppResourcesScanner.scan(WebAppResourcesScanner.java:79)
        at com.sun.jersey.api.core.ScanningResourceConfig.init(ScanningResourceConfig.java:80)
        at com.sun.jersey.api.core.servlet.WebAppResourceConfig.init(WebAppResourceConfig.java:102)
        at com.sun.jersey.api.core.servlet.WebAppResourceConfig.<init>(WebAppResourceConfig.java:89)
        at com.sun.jersey.api.core.servlet.WebAppResourceConfig.<init>(WebAppResourceConfig.java:74)
        at com.sun.jersey.spi.container.servlet.WebComponent.getWebAppResourceConfig(WebComponent.java:668)
        at com.sun.jersey.spi.container.servlet.ServletContainer.getDefaultResourceConfig(ServletContainer.java:415)
        at com.sun.jersey.spi.container.servlet.ServletContainer.getDefaultResourceConfig(ServletContainer.java:582)
        at com.sun.jersey.spi.container.servlet.WebServletConfig.getDefaultResourceConfig(WebServletConfig.java:87)
        at com.sun.jersey.spi.container.servlet.WebComponent.createResourceConfig(WebComponent.java:699)
        at com.sun.jersey.spi.container.servlet.WebComponent.createResourceConfig(WebComponent.java:674)
        at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:203)
        at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:374)
        at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:557)
        at javax.servlet.GenericServlet.init(GenericServlet.java:158)
        at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1284)
        at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1197)
        at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1087)
        at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5210)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5493)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:632)
        at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1083)
        at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1880)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)

找來找去找不太到相關的資料,好不容易找到 [1],顯示錯誤原因似乎是使用 Maven 時加上了 Jaxen 這個 dependency。
不過這個 dependency 是 dom4j 在操作 XPath 時要用的 ~"~
先記錄一下,也許可能的解法是不要用 XPath 來存取 XML 內容....。

參考資料:
1、较少遇到的错误—严重: StandardWrapper.Throwable—java.lang.ArrayIndexOutOfBoundsException: 48188

2014年7月10日 星期四

透過 Apache jClouds 操作本地檔案系統的 Blob Store

Apache jClouds 是一個可以支援很多不同雲端基礎建設的開源函式庫
其中可以利用它的 Blob Store 的介面,來操作各家雲端基礎建設的儲存服務。
不過其實它也有提供非雲端基礎建設的實作,讓使用者可以適度地把一些沒有要放上雲端的東西,透過它的介面存放在本地的檔案系統。

2014年7月7日 星期一

使用 AES 加密後的資料長度

參考 [1-2],AES 演算法在加密時基本上不會變更檔案長度,所以原始檔案有多長,加密後就有多長。
不過因為 AES 是 block cipher,要加密的對象必須是 16 bytes 的倍數才能正常加密
因此演算法必須搭配 padding 的方法,而 padding 的方法就會影響加密後的長度。

從 [1] 的回應來看,如果 padding 的方法是使用 PKCS5 或 PKCS7 的話,加密後的長度如下:
cipherLen = (clearLen/16 + 1) * 16;

參考資料:
1、Size of data after AES encryption
2、How does PKCS#7 padding work with AES-256, CBC mode?