Fourinone如何實現并行計算和數據庫引擎
import com.fourinone.Contractor; import com.fourinone.WareHouse; import com.fourinone.WorkerLocal;public class CtorMul extends Contractor { public WareHouse giveTask(WareHouse inhouse) { /WorkerLocal[] wks = getWaitingWorkers("WorkerMul"); System.out.println("wks.length:"+wks.length);/
//生成5個多線程工人,并設置業務實現類 WorkerLocal[] wks = getLocalWorkers(5); for(int j=0;j<wks.length;j++) wks[j].setWorker(new WorkerMul()); //生成15個計算任務 WareHouse[] tasks = new WareHouse[15]; for(int i=0;i<15;i++){ tasks[i]=new WareHouse("taskId",i+""); } //讓多個工人并行爭搶處理多個任務,并且高容錯,堵塞直到返回所有任務結果。 WareHouse[] result = doTaskCompete(wks, tasks); for(int i=0;i<result.length;i++){ System.out.println(i+":"+result[i]); } return inhouse; } public static void main(String[] args) { CtorMul cd = new CtorMul(); cd.giveTask(null); cd.exit(); }
}</pre>
直接用java編譯運行CtorMul.java即可完成一個本地多線程并行計算:
javac -cp fourinone.jar; *.java
java -cp fourinone.jar; CtorMul
我們看到CtorMul.java程序main函數里先new了一個CtorMul實例,然后調用它的giveTask方法,在這個方法里,工頭自己生成一定數量的線程幫助自己完成計算任務,并在計算結束后程序退出。完成計算任務的函數是doTaskCompete,它有兩個參數,把所有工人和所有任務扔給它,然后堵塞等待所有計算完成,返回一個結果集。
![]()
多線程并行計算方式的優缺點:由于只需要一個工頭實現類就可以完成多線程并行計算,所以它非常好集成,容易嵌入到你的業務系統中去,但是多線程并行計算有很大局限性,它首先只能在本地,無法做分布式并行計算去利用多臺機器的cpu資源,還有多線程的容錯性較差,由于多線程工人和主線程工頭都在一個jvm進程里,一個線程出故障容易導致整個jvm進程掛掉,也比較難切換到其他線程運行。
二、Fourinone如何實現多進程并行計算如何將上面的多線程并行計算無縫切換成一個多機的分布式多進程并行計算,我們把CtorMul.java里面引用到的WorkerMul.java工人實現類打開:
import com.fourinone.MigrantWorker; import com.fourinone.WareHouse; public class WorkerMul extends MigrantWorker { public WareHouse doTask(WareHouse inhouse) { String taskId = inhouse.getString("taskId"); System.out.print("taskId"+taskId+"任務處理中..."); try{Thread.sleep(3000L);}catch(Exception ex){} System.out.println("taskId"+taskId+"處理完成。"); return new WareHouse("result", "ok"); } public static void main(String[] args) { WorkerMul wd = new WorkerMul(); wd.waitWorking(args[0],Integer.parseInt(args[1]),"WorkerMul"); } }這個工人實現類的doTask接口里,只是簡單打印了任務編號和sleep了3秒模擬處理任務,然后返回。但是我們注意到它有個main函數的,上面的多線程并行計算只是new了WorkerMul 的實例作為業務實現類傳入,但是并沒有運行工人的main函數讓它啟動起來,我們可以讓WorkerMul 獨立啟動,它就是一個工人服務進程,可以在多臺機器上啟動多個這樣的工人進程,并監聽在不同的ip和端口。
我們再觀察到前面的CtorMul .java第一段的代碼注釋掉了,根據Fourinone的架構設計,我們知道工人服務進程啟動后,會到職介者(ParkServer)去注冊,ParkServer實現了ZooKeeper的所有功能和領導者選舉算法,然后工頭通過getWaitingWorkers獲取到線上工人,并遠程調用工人完成計算任務,詳細可以參考:多機并行計算指南。
我們把CtorMul .java第一段的代碼的注釋取消,改把第二段用于本地多線程的代碼注釋掉,其他代碼不用變。然后我們啟動兩個工人做多進程并行計算,重新編譯后運行順序如下:
java -cp fourinone.jar; ParkServerDemo
java -cp fourinone.jar; WorkerMul localhost 6001
java -cp fourinone.jar; WorkerMul localhost 6002
java -cp fourinone.jar; CtorMul
![]()
可以看到我們把并行計算從多線程切換到了多進程,但是工人的任務實現邏輯doTask仍然一行代碼不改動。多進程方式需要獨立運行多個工人和職介者服務,比多線程方式要麻煩和復雜,但是它能帶來更強大的分布式計算擴充能力和更好的容錯穩定性, 我們在運行過程中,可以Ctrl+C把其中一個正在計算的工人關掉,會發現工頭拋出調用異常,但是計算并未中止,而是將該任務重投到另一個工人上去做,只要集群還剩一個工人,計算就不會受影響,只是計算效率會降低,時間會延長。
總結:有人問Fourinone為什么不設計成Hadoop,Spark,Storm這樣的動態任務投放方式,實際上Fourinone現在的方式要更靈活,如果要事先定義好DAG那樣的任務流程圖出來,并考慮如何分配資源,做到最后會發現都走到資源隔離管理的路上去了,那還不如開始去做Docker。從這點上看Fourinone的并行計算,更接近MPI,但是相對于MPI抽象歸納出了并行計算的角色、方法和模式。并且Fourinone也沒有Hadoop和Spark的shuffle機制的煩惱,如果Fourinone做成一個資源隔離框架+DAG任務平臺,那是不可能實現出一個功能強大的并行數據庫引擎的,連做些靈活的機器學習算法并行化都困難,
三、再談并行數據庫引擎CoolHash
關于CoolHash,最好大家能直接它啟動起來,然后各種測,與其談太多架構算法,不如邊測試邊觀察數據,通過數據去思考。下面是coolhash運行界面,不需要安裝,啟動很簡單。
![]()
運行機器可以是普通的筆記本或者臺式機,操作系統不限,CoolHash能竭盡利用你機器的最大性能,當然生產線上還是要運行在pc server上,從8核的虛擬機到24核的實體機都是可以的,不需要ssd,有更好。相信大家對相同機器配置下,關系型數據庫、內存數據庫的基本性能都有所了解,可以對比下性能的差異。
每個數據庫廠商出示的測試報告都是宣稱自己最好,所以不要去相信宣傳的,比如作者親身經歷的couchdb單機能力就沒有redis快,客戶方把couchdb公司的人請來最后也是一樣的結果。用戶親手測試的結果更有說服力,看到底能不能在單機上做到百萬的TPS,達到硬件的極限,用戶一定要做到自己心里有數,如果你對測試結果有什么疑問,可以直接到Fourinone技術群里去提問。
想強調的一點,CoolHash是持久化的,幾乎同時把數據從內存刷到硬盤,所以它的容量是硬盤容量,不是內存容量,這點和redis很不一樣,也就是數據容量超過內存大小時,還是運行穩定的,而且性能不下降(準確的說是不高于所在硬盤分區容量的70%-80%,操作系統建議不要超過這個安全比例),redis是嚴禁數據容量接近內存一半的,因為redis碰到刷硬盤的瞬間占用內存會膨脹一倍。
有人問,我一次寫入200萬數據,為什么CoolHash里只有100萬,是不是丟了數據?那是因為CoolHashMap默認最大容量為1百萬條數據,可根據內存大小調整HASHCAPACITY配置項,在配置文件里改下就可以了。數據庫引擎是嚴禁有任何數據丟失錯亂問題的。
網上有人詆毀CoolHash不支持高并發,最好的辦法就是親自檢驗,不用理會噴子。下載包里自帶了并發測試程序:
CoolHashTestRun.java是多個客戶端進程高并發大數據量讀寫測試
ThreadClient.java是多個客戶端線程高并發大數據量讀寫測試
在CoolHash的最初版本只支持多進程的客戶端,出于安全隔離性考慮限制了一個jvm里模擬多線程客戶端訪問,但是這跟數據庫服務端引擎沒有關系的, 引擎一直都是支持高并發訪問的。現在多線程客戶端也都開通了。
CoolHash更重要的能力還不僅是高性能讀寫,靈活檢索能力是衡量數據庫引擎能力的標志,它能支持key和value的同時模糊檢索,并且可支持高并發檢索,而且都是毫秒級完成,數據量比較大時才幾秒。為了提升檢索能力,可以設計好你的key,用點做分隔符設計一個樹型key,比如user.10010.name,然后用user.*.name來檢索。
傳統關系化結構數據如何轉換設計成CoolHash的樹型key/value結構,可以參考下面這個圖:
除外還有key指針的設計去解決join關聯的問題,CoolHash的很多特性都是其他k/v nosql數據庫沒有的,都來源于作者長期工作實踐中的經驗總結,一個追求創新的數據庫引擎總是會面臨有人對它的各種質疑,技術上有爭論才好,被各大公司都測過,吵過,質疑過,嘗試過,反思過才是對一個開源軟件最好的鞭策和發展。
回到生產場景上,如果僅僅是從技術上驗證一個東西,其實是簡單的,可以先測試,再上poc項目,再上小型生產系統,可以先只做數據同步,再分擔讀寫檢索壓力,運行穩定再上中型生產系統,這樣一步步從小到大應用下去就很容易通過時間去檢驗一項技術。實際上,CoolHash在線上跑了幾個月也從未出過問題,每天10-20G的數據寫入(覆蓋),增量2-3G,整體容量超過幾百g,超出內存大小運行,一直很穩定。
CoolHash的并行處理到底是多線程模式還是多進程模式?是多進程模式,上面是CoolHash的并行架構示意圖,每個數據工人都是一個獨立進程,多個jvm進程共同作業,這是因為對底層存儲結構、內存、mmap等控制上,多線程操作容易出問題的,多進程更安全可靠。CoolHash是在單機上采用多進程并行模式,只有單機引擎能力上去了,整體分布式集群的能力才會提升。如果你需要基于CoolHash做分布式數據庫,可以參考自帶例子AsynClient.java提供的異步處理等功能支持。
來自: http://fourinone.iteye.com/blog/2280209