Fourinone如何實現並行計算和數據庫引擎

關於並行計算的概念有很是多,硬件落地其實就只有兩種,CPU上的並行計算和GPU上的並行計算,GPU作點積這樣的矢量計算(矩陣計算)有優點,但目前還運行不了操做系統和數據庫,比較多用於研究性質的計算。在咱們生產系統中運用最多的是CPU上的並行計算,其落地方式也只有兩種,多線程和多進程。圍繞多線程、多進程結合通訊技術的靈活設計,它的應用範圍很是普遍,不光用於並行計算,也是大部分的服務器技術、分佈式技術、中間件技術的重要實現技術, java

Fourinone同時提供多線程和多進程的並行計算,而且能實現二者之間的無縫切換,而不須要改一行業務計算的邏輯代碼,計算過程當中還能保證高容錯,一個工人故障會重投任務到其餘工人執行,並有超時終止等支持。 redis

1、Fourinone如何實現多線程並行計算
實現多線程並行計算只須要一個工頭實現類就夠了,除外不須要依賴任何計算服務,這個例子位於下載包的分佈式計算補充demo目錄下,CtorMul .java: 算法

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();
	}
}

直接用java編譯運行CtorMul.java便可完成一個本地多線程並行計算:
javac -cp fourinone.jar; *.java
java -cp fourinone.jar; CtorMul sql

咱們看到CtorMul.java程序main函數裏先new了一個CtorMul實例,而後調用它的giveTask方法,在這個方法裏,工頭本身生成必定數量的線程幫助本身完成計算任務,並在計算結束後程序退出。完成計算任務的函數是doTaskCompete,它有兩個參數,把全部工人和全部任務扔給它,而後堵塞等待全部計算完成,返回一個結果集。 數據庫

多線程並行計算方式的優缺點:
因爲只須要一個工頭實現類就能夠完成多線程並行計算,因此它很是好集成,容易嵌入到你的業務系統中去,可是多線程並行計算有很大侷限性,它首先只能在本地,沒法作分佈式並行計算去利用多臺機器的cpu資源,還有多線程的容錯性較差,因爲多線程工人和主線程工頭都在一個jvm進程裏,一個線程出故障容易致使整個jvm進程掛掉,也比較難切換到其餘線程運行。 安全

2、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任務平臺,那是不可能實現出一個功能強大的並行數據庫引擎的,連作些靈活的機器學習算法並行化都困難,


3、再談並行數據庫引擎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提供的異步處理等功能支持。

相關文章
相關標籤/搜索