Nov. 11 20:28~21:53
各位 Java programmers 有沒有這樣的疑問:跑在同一台電腦上的不同程式,要如何交換資料?有時候寫程式寫到有一種『咫尺天涯』的感覺,明明程式都跑在同一台電腦中,要交換個資料卻是那麼的不容易。
這個問題就是作業系統所講的 Inter-process communication (IPC),學過作業系統的鄉民們應該都知道 IPC 是一個很重要的機制,借用 Wikipedia 的資料幫鄉民們複習一下功課,以下為幾種常用的 IPC 方法:
- File
- Signal
- Socket
- Message queue
- Pipe
- Named pipe
- Semaphore
- Shared memory
- Message passing (shared nothing)
- Memory-mapped file
問題來了,如果你用 Java 開發一個系統,這個系統有好幾支獨立的主程式,這些程式跑在同一台電腦上的不同 VM 中。這些程式要採用哪一種 IPC 方式來交換資料效率會比較好,程式也容易寫?
先去除 Java 沒有『直接』支援的方法:
- Signal
- Message queue (JMS 不算...)
- Named pipe
- Semaphore
- Shared memory (JavaSpaces 不算)
對 Teddy 這個『世代』的 programmers 而言,剩下來的方法中,用 socket 可能是最簡單的。但是用 socket 有兩個壞處:
- 需要佔用一個 port,如果電腦有裝防火牆的話,可能會被擋住,不然就是增加設定的麻煩。
- 資料傳輸效率較差。明啊明要交換資料的程式都在同一台電腦上,用 socket 還要把傳輸的資料『打包』與『反打包』,速度自然快不起來。
那用 Memory-mapped file,這速度夠快了吧!ㄟ,雖然 Java NIO 有支援,但是 Teddy 還沒試過如何用這種方法來交換資料,所以... 淘汰。那不然用 File 好了。可是要用檔案來交換資料,還要自己處理『同步』的問題(當同時間有多人想讀寫檔案的時候,必須由應用程式自行定義同步機制,以避免資料錯誤),有點麻煩,程式容易出錯也不好測試。
***
同事甲:那要不要用『資料庫』來交換資料?同步的問題資料庫已經幫我們解決了。
路人甲:裝孝帷,用『資料庫』 overhead 不是更高,要啟動 database server,而且要連到資料庫不也是要建一個 socket,佔用一個 port?
Teddy:Java 有沒有那種類似 Microsoft Access 的資料庫,不需要啟動 database server,可以用『檔案』的方式來開啟資料庫?如果有的話,用『資料庫』來當成 IPC 的方法也許就可行了。
Teddy 找到 H2 這個開放原始碼的資料庫,就具有這種功能。H2 支援三種連線模式:
- Embedded mode (local connections using JDBC)
- Server mode (remote connections using JDBC or ODBC over TCP/IP)
- Mixed mode (local and remote connections at the same time)
其中 embedded mode 不需要啟動 database server,可以直接用以下方式來開啟資料庫。
DriverManager.getConnection("jdbc:h2:data:h2:test", "sa", "sa");
但是問題來了,在 embedded mode 之下,一個資料庫同時間只能被一個 VM (加上 class loader)開啟。H2 會拒絕跑在另一個 VM 的另一支程式用 embedded mode 來開啟同一個資料庫(為了避免資料被搞亂)。
同時間只有一支程式(一個 VM)能夠用 embedded mode 來開啟一個資料庫,那這不就破功了?!還好只要在 connection string 加上 FILE_LOCK=SERIALIZED 就可以允許不同 VM 的程式同時開啟同一個資料庫。
DriverManager.getConnection("jdbc:h2:data:h2:test;FILE_LOCK=SERIALIZED", "sa", "sa");
不過這樣的方便是有代價滴,根據 H2 的文件說明:
This locking mode allows to open multiple connections to the same database. The connections may be opened from multiple processes and from different computers. When writing to the database, access is automatically synchronized internally.
Write operations are slower than when using the server mode, and concurrency is relatively poor. The advantage of this mode is that there is no need to start a server.
在 Teddy 的應用中,只有一個 process 會 write,其餘的 processes 絕大部分時間都只會 read,而且同時間大概只會有 2 到 3 processes ,所以 concurrency is relatively poor 也可以接受啦 。當 Teddy 心中正在『暗爽』的時候,居然看到:
This feature is relatively new. When using it for production, please ensure your use case is well tested (if possible with automated test cases).
反正 open source 的東西,用了本來就要自負風險。對於每天工作累到走路必須靠北邊走的鄉民們,能夠少寫一行程式,就少寫一行。所以,用這種方式來達到 IPC 也不失為另一種『聰明』的選擇,至少達到了:
- 不用建 socket。
- 應用程式不需要自行設計同步機制。
- 資料操作方法簡單(SQL)。
- 速度尚可接受。
最後提醒一點,H2 的 jar 檔需要多站 1.2 MB的空間。
***
友藏內心獨白:以前寫 VB 程式同時間連 access 資料庫有慘痛的資料損毀經驗,希望這個 H2 能夠『有檔頭』一點。