數(shù)據(jù)庫(kù)作為業(yè)務(wù)的核心,在整個(gè)基礎(chǔ)軟件棧中是非常重要的一環(huán)。近幾年社區(qū)也是新的方案和思想層出不窮,接下來(lái)我將總結(jié)一下近幾年一些主流的開(kāi)源數(shù)據(jù)庫(kù)方案,其背后的設(shè)計(jì)思想以及適用場(chǎng)景。本人才疏學(xué)淺如有遺漏或者錯(cuò)誤請(qǐng)見(jiàn)諒。本次分享聚焦于數(shù)據(jù)庫(kù)既結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)OLTP及NoSQL領(lǐng)域,不會(huì)涉及OLAP、對(duì)象存儲(chǔ)、分布式文件系統(tǒng)。
很長(zhǎng)時(shí)間以來(lái),關(guān)系型數(shù)據(jù)庫(kù)一直是大公司的專(zhuān)利,市場(chǎng)被Oracle/DB2等企業(yè)數(shù)據(jù)庫(kù)牢牢把持。但是隨著互聯(lián)網(wǎng)的崛起、開(kāi)源社區(qū)的發(fā)展,上世紀(jì)九十年代MySQL1.0的發(fā)布,標(biāo)志著關(guān)系型數(shù)據(jù)庫(kù)的領(lǐng)域社區(qū)終于有可選擇的方案。
第一個(gè)介紹的單機(jī)RDBMS就是MySQL。相信大多數(shù)朋友都已經(jīng)對(duì)MySQL非常熟悉,基本上MySQL的成長(zhǎng)史就是互聯(lián)網(wǎng)的成長(zhǎng)史。我接觸的第一個(gè)MySQL版本是MySQL4.0,到后來(lái)的MySQL5.5更是經(jīng)典——基本所有的互聯(lián)網(wǎng)公司都在使用。
MySQL也普及了「可插拔」引擎這一概念,針對(duì)不同的業(yè)務(wù)場(chǎng)景選用不同的存儲(chǔ)引擎是MySQLtuning的一個(gè)重要的方式。比如對(duì)于有事務(wù)需求的場(chǎng)景使用InnoDB:對(duì)于并發(fā)讀取的場(chǎng)景MyISAM可能比較合適:但是現(xiàn)在我推薦絕大多數(shù)情況還是使用InnoDB,畢竟5.6后已經(jīng)成為了官方的默認(rèn)引擎。大多數(shù)朋友都基本知道什么場(chǎng)景適用MySQL(幾乎所有需要持久化結(jié)構(gòu)化數(shù)據(jù)的場(chǎng)景),我就不贅述了。
另外值得一提的是MySQL5.6中引入了多線(xiàn)程復(fù)制和GTID,使得故障恢復(fù)和主從的運(yùn)維變得比較方便。另外,5.7(目前處于GA版本)是MySQL的一個(gè)重大更新,主要是讀寫(xiě)性能和復(fù)制性能上有了長(zhǎng)足的進(jìn)步(在5.6版本中實(shí)現(xiàn)了SCHEMA級(jí)別的并行復(fù)制,不過(guò)意義不大,倒是MariaDB的多線(xiàn)程并行復(fù)制大放異彩,有不少人因?yàn)檫@個(gè)特性選擇MariaDB。MySQL5.7MTS支持兩種模式,一種是和5.6一樣,另一種則是基于binloggroupcommit實(shí)現(xiàn)的多線(xiàn)程復(fù)制,也就是MASTER上同時(shí)提交的binlog在SLAVE端也可以同時(shí)被apply,實(shí)現(xiàn)并行復(fù)制)。
如果有單機(jī)數(shù)據(jù)庫(kù)技術(shù)選型的朋友,基本上只需要考慮5.7或者M(jìn)ariaDB就好了,而且5.6、5.7由Oracle接手后,性能和穩(wěn)定性上都有了明顯的提升。
PostgreSQL的歷史也非常悠久,其前身是UCB的Ingres,主持這個(gè)項(xiàng)目的MichaelStronebraker于2015年獲得圖靈獎(jiǎng)。后來(lái)項(xiàng)目更名為Post-Ingres,項(xiàng)目基于BSDlicense下開(kāi)源。1995年幾個(gè)UCB的學(xué)生為Post-Ingres開(kāi)發(fā)了SQL的接口,正式發(fā)布了PostgreSQL95,隨后一步步在開(kāi)源社區(qū)中成長(zhǎng)起來(lái)。
和MySQL一樣,PostgreSQL也是一個(gè)單機(jī)的關(guān)系型數(shù)據(jù)庫(kù),但是與MySQL方便用戶(hù)過(guò)度擴(kuò)展的SQL文法不一樣的是,PostgreSQL的SQL支持非常強(qiáng)大,不管是內(nèi)置類(lèi)型、JSON支持、GIS類(lèi)型以及對(duì)于復(fù)雜查詢(xún)的支持,PL/SQL等都比MySQL強(qiáng)大得多。而且從代碼質(zhì)量上來(lái)看,PostgreSQL的代碼質(zhì)量是優(yōu)于MySQL的,另外PostgreSQL的SQL優(yōu)化器比MySQL強(qiáng)大很多,幾乎所有稍微復(fù)雜的查詢(xún)(當(dāng)然,我沒(méi)有對(duì)比MySQL5.7,也可能這個(gè)信息outdated了)PostgreSQL的表現(xiàn)都優(yōu)于MySQL。
從近幾年的趨勢(shì)上來(lái)看,PostgreSQL的勢(shì)頭也很強(qiáng)勁,我認(rèn)為PostgreSQL的不足之處在于沒(méi)有MySQL這樣強(qiáng)大的社區(qū)和群眾基礎(chǔ)。MySQL經(jīng)過(guò)那么多年的發(fā)展,積累了很多的運(yùn)維工具和最佳實(shí)踐,但是PostgreSQL作為后起之秀,擁有更優(yōu)秀的設(shè)計(jì)和更豐富的功能。PostgreSQL9以后的版本也足夠穩(wěn)定,在做新項(xiàng)目技術(shù)選型的時(shí)候,是一個(gè)很好的選擇。另外也有很多新的數(shù)據(jù)庫(kù)項(xiàng)目是基于PostgreSQL源碼的基礎(chǔ)上進(jìn)行二次開(kāi)發(fā),比如Greenplum等。
我認(rèn)為,單機(jī)數(shù)據(jù)庫(kù)的時(shí)代很快就會(huì)過(guò)去。榨取摩爾定律帶來(lái)的硬件紅利總是有上限的,現(xiàn)代業(yè)務(wù)的數(shù)據(jù)規(guī)模、流量以及現(xiàn)代的數(shù)據(jù)科學(xué)對(duì)于數(shù)據(jù)庫(kù)的要求單機(jī)已經(jīng)很難滿(mǎn)足。網(wǎng)卡磁盤(pán)IO和CPU總有瓶頸,線(xiàn)上敏感的業(yè)務(wù)系統(tǒng)可能還得承擔(dān)SPOF(單點(diǎn)故障)的風(fēng)險(xiǎn),主從復(fù)制模型在主掛掉時(shí)到底切還是不切?切了以后數(shù)據(jù)如何恢復(fù)?如果只是出現(xiàn)主從機(jī)器網(wǎng)絡(luò)分區(qū)問(wèn)題呢?甚至是監(jiān)控環(huán)境出現(xiàn)網(wǎng)絡(luò)分區(qū)問(wèn)題呢?這些都是問(wèn)題。
所以我的觀點(diǎn)是,無(wú)論單機(jī)性能多棒(很多令人乍舌的評(píng)測(cè)數(shù)據(jù)都是針對(duì)特定場(chǎng)景的優(yōu)化,另外甚至有些都是本機(jī)不走網(wǎng)絡(luò),而大多數(shù)情況數(shù)據(jù)庫(kù)出現(xiàn)的第一個(gè)瓶頸其實(shí)是網(wǎng)卡和并發(fā)連接……),隨著互聯(lián)網(wǎng)的蓬勃發(fā)展,移動(dòng)互聯(lián)網(wǎng)的出現(xiàn)使得數(shù)據(jù)庫(kù)系統(tǒng)迎來(lái)了第一次分布式的洗禮。
Google應(yīng)該是第一個(gè)將分布式存儲(chǔ)技術(shù)應(yīng)用到大規(guī)模生產(chǎn)環(huán)境的公司,同時(shí)也是在分布式系統(tǒng)上積累最深的公司,可以說(shuō)目前工業(yè)界的分布式系統(tǒng)的工程實(shí)踐及思想大都來(lái)源于Google。比如2003年的GFS開(kāi)創(chuàng)了分布式文件系統(tǒng),2006年的Bigtable論文開(kāi)創(chuàng)了分布式鍵值系統(tǒng),直接催生的就是Hadoop的生態(tài):至于2012年發(fā)表論文的Spanner和F1更是一個(gè)指明未來(lái)關(guān)系型數(shù)據(jù)庫(kù)發(fā)展方向的里程碑式的項(xiàng)目,這個(gè)我們后續(xù)會(huì)說(shuō)。
另一個(gè)公司是Amazon。2007年發(fā)表的Dynamo的論文嘗試引入了最終一致性的概念,WRN的模型及向量時(shí)鐘的應(yīng)用,同時(shí)將一致性HASH、merkletree等當(dāng)時(shí)一些很新潮的技術(shù)整合起來(lái),正式標(biāo)志著NoSQL的誕生——對(duì)后來(lái)業(yè)界的影響也是很大,包括后來(lái)的Cassandra、RiakDB、Voldemort等數(shù)據(jù)庫(kù)都是基于Dynamo的設(shè)計(jì)發(fā)展起來(lái)的。
另外這個(gè)時(shí)期(2006年前后持續(xù)至今)一個(gè)比較重要的思潮就是數(shù)據(jù)庫(kù)(持久化)和緩存開(kāi)始有明確的分離——我覺(jué)得這個(gè)趨勢(shì)是從memcached開(kāi)始的。隨著業(yè)務(wù)的并發(fā)越來(lái)越高,對(duì)于低延遲的要求也越來(lái)越高:另外一個(gè)原因是隨著內(nèi)存越來(lái)越便宜,基于內(nèi)存的存儲(chǔ)方案漸漸開(kāi)始普及。當(dāng)然內(nèi)存緩存方案也經(jīng)歷了一個(gè)從單機(jī)到分布式的過(guò)程,但是這個(gè)過(guò)程相比關(guān)系型數(shù)據(jù)庫(kù)的進(jìn)化要快得多。
這是因?yàn)镹oSQL的另外一個(gè)重要的標(biāo)志——數(shù)據(jù)模型的變化——大多NoSQL都拋棄了關(guān)系模型,選擇更簡(jiǎn)單的鍵值或者文檔類(lèi)型進(jìn)行存儲(chǔ)。數(shù)據(jù)結(jié)構(gòu)和查詢(xún)接口都相對(duì)簡(jiǎn)單,沒(méi)有了SQL的包袱,實(shí)現(xiàn)的難度會(huì)降低很多。
另外NoSQL的設(shè)計(jì)幾乎都選擇犧牲掉復(fù)雜SQL的支持及ACID事務(wù)換取彈性擴(kuò)展能力,也是從當(dāng)時(shí)互聯(lián)網(wǎng)的實(shí)際情況出發(fā):業(yè)務(wù)模型簡(jiǎn)單、爆發(fā)性增長(zhǎng)帶來(lái)的海量并發(fā)及數(shù)據(jù)總量爆炸、歷史包袱小、工程師強(qiáng)悍,等。其中最重要的還是業(yè)務(wù)模型相對(duì)簡(jiǎn)單。
在開(kāi)始介紹具體的開(kāi)源的完整方案前,我想介紹一下嵌入式存儲(chǔ)引擎?zhèn)儭?/div>
隨著NoSQL的發(fā)展,不僅僅緩存和持久化存儲(chǔ)開(kāi)始細(xì)分,再往后的存儲(chǔ)引擎也開(kāi)始分化并走上前臺(tái)。之前很難想象一個(gè)存儲(chǔ)引擎獨(dú)立于數(shù)據(jù)庫(kù)直接對(duì)外提供服務(wù),就像你不會(huì)直接拿著InnoDB或者M(jìn)yISAM甚至一個(gè)B-tree出來(lái)用一樣(當(dāng)然,bdb這樣鼎鼎大名的除外)。人們基于這些開(kāi)源的存儲(chǔ)引擎進(jìn)行進(jìn)一步的封裝,比如加上網(wǎng)絡(luò)協(xié)議層、加上復(fù)制機(jī)制等等,一步步構(gòu)建出完整的風(fēng)格各異的NoSQL產(chǎn)品。
這里我挑選幾個(gè)比較著名存儲(chǔ)引擎介紹一下。
TC
我最早接觸的是TokyoCabinet(TC)。TC相信很多人也都聽(tīng)說(shuō)過(guò),TC是由日本最大的社交網(wǎng)站Mixi開(kāi)發(fā)并開(kāi)源的一個(gè)混合Key-Value存儲(chǔ)引擎,其中包括HASHTable和B+Tree的實(shí)現(xiàn)。但是這個(gè)引擎的一個(gè)缺陷是隨著數(shù)據(jù)量的膨脹,性能的下降會(huì)非常明顯,而且現(xiàn)在也基本不怎么維護(hù)了,所以入坑請(qǐng)慎重。于TC配合使用的TokyoTyrant(TT)是一個(gè)網(wǎng)絡(luò)庫(kù),為T(mén)C提供網(wǎng)絡(luò)的接口使其變成一個(gè)數(shù)據(jù)庫(kù)服務(wù),TT+TC應(yīng)該是比較早的NoSQL的一個(gè)嘗試。
LevelDB
在2011年,Google開(kāi)源了Bigtable的底層存儲(chǔ)擎:LevelDB。LevelDB是一個(gè)使用C++開(kāi)發(fā)的嵌入式的Key-Value存儲(chǔ)引擎,數(shù)據(jù)結(jié)構(gòu)采用了LSM-Tree,具體LSM-Tree的算法分析可以很容易在網(wǎng)上搜索到,我就不贅述了。其特點(diǎn)是,對(duì)于寫(xiě)入極其友好,LSM的設(shè)計(jì)避免了大量的隨機(jī)寫(xiě)入:對(duì)于特定的讀也能達(dá)到不錯(cuò)的性能(熱數(shù)據(jù)在內(nèi)存中):另外LSM-Tree和B-tree一樣是支持有序Scan的:而且LevelDB是出自JeffDean之手,他的事跡做分布式系統(tǒng)的朋友一定都知道,不知道的可以去Google搜一下。
LevelDB擁有極好的寫(xiě)性能,線(xiàn)程安全,BaTChWrite和Snapshot等特性,使其很容易的在上層構(gòu)建MVCC系統(tǒng)或者事務(wù)模型,對(duì)于數(shù)據(jù)庫(kù)來(lái)說(shuō)非常重要。
另外值得一說(shuō)的是,F(xiàn)acebook維護(hù)了一個(gè)活躍的LevelDB的分支,名為RocksDB。RocksDB在LevelDB上做了很多的改進(jìn),比如多線(xiàn)程Compactor、分層自定義壓縮、多MemTable等。另外RocksDB對(duì)外暴露了很多Configration,可以根據(jù)不同業(yè)務(wù)的形態(tài)進(jìn)行調(diào)優(yōu):同時(shí)Facebook在內(nèi)部正在用RocksDB來(lái)實(shí)現(xiàn)一個(gè)全新的MySQL存儲(chǔ)引擎:MyRocks,值得關(guān)注。RocksDB的社區(qū)響應(yīng)速度很快也很友好,實(shí)際上PingCAP也是RocksDB的社區(qū)貢獻(xiàn)者。我建議新的項(xiàng)目如果在LevelDB和RocksDB之間糾結(jié)的話(huà),請(qǐng)果斷選擇RocksDB。
B-tree家族
當(dāng)然,除了LSM-Tree外,B-tree的家族也還是有很多不錯(cuò)的引擎。首先大多數(shù)傳統(tǒng)的單機(jī)數(shù)據(jù)庫(kù)的存儲(chǔ)引擎都選擇了B+Tree,B+Tree對(duì)磁盤(pán)的讀比較友好,第三方存儲(chǔ)引擎比較著名的純B+Tree實(shí)現(xiàn)是LMDB。首先LMDB選擇在內(nèi)存映像文件(mmap)實(shí)現(xiàn)B+Tree,同時(shí)使用了Copy-On-Write實(shí)現(xiàn)了MVCC實(shí)現(xiàn)并發(fā)事務(wù)無(wú)鎖讀的能力,對(duì)于高并發(fā)讀的場(chǎng)景比較友好:同時(shí)因?yàn)槭褂玫氖莔map所以擁有跨進(jìn)程讀取的能力。因?yàn)槲也](méi)有在生產(chǎn)環(huán)境中使用過(guò)LMDB,所以并不能給出LMDB的一些缺陷,見(jiàn)諒。
混合引擎
還有一部分的存儲(chǔ)引擎選擇了多種引擎混合,比如最著名的應(yīng)該是WiredTiger,大概是去年被MongoDB收購(gòu),現(xiàn)在成為了MongoDB的默認(rèn)存儲(chǔ)引擎。WiredTiger內(nèi)部有LSM-Tree和B-tree兩種實(shí)現(xiàn)提供一套接口,根據(jù)業(yè)務(wù)的情況可自由選擇。另外一些特殊數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)引擎在某些特殊場(chǎng)合下非常搶眼,比如極高壓縮比TokuDB,采用了名為分形樹(shù)的數(shù)據(jù)結(jié)構(gòu),在維持一個(gè)可接受的讀寫(xiě)壓力的情況下,能擁有10倍以上的壓縮率。
NoSQL
說(shuō)完了幾個(gè)比較著名的存儲(chǔ)引擎,我們來(lái)講講比較著名的NoSQL。在我的定義中,NoSQL是NotOnlySQL的縮寫(xiě),所以可能包含的范圍有內(nèi)存數(shù)據(jù)庫(kù),持久化數(shù)據(jù)庫(kù)等?傊褪呛蛦螜C(jī)的關(guān)系型數(shù)據(jù)庫(kù)不一樣的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)系統(tǒng)。
我們先從緩存開(kāi)始。
memcached
前面提到了memcached應(yīng)該是第一個(gè)大規(guī)模在業(yè)界使用的緩存數(shù)據(jù)庫(kù),memcached的實(shí)現(xiàn)極其簡(jiǎn)單,相當(dāng)于將內(nèi)存用作大的HASHTable,只能在上面get/set/計(jì)數(shù)器等操作,在此之上用libevent封裝了一層網(wǎng)絡(luò)層和文本協(xié)議(也有簡(jiǎn)單的二進(jìn)制協(xié)議),雖然支持一些CAS的操作,但是總體上來(lái)看,還是非常簡(jiǎn)單的。
但是memcached的內(nèi)存利用率并不太高,這個(gè)因?yàn)閙emcached為了避免頻繁申請(qǐng)內(nèi)存導(dǎo)致的內(nèi)存碎片的問(wèn)題,采用了自己實(shí)現(xiàn)的slaballocator的方式。即內(nèi)存的分配都是一塊一塊的,最終存儲(chǔ)在固定長(zhǎng)度的chunk上,內(nèi)存最小的分配單元是chunk,另外libevent的性能也并沒(méi)有優(yōu)化到極致,但是不妨礙memcached成為當(dāng)時(shí)的開(kāi)源緩存事實(shí)標(biāo)準(zhǔn)(另外,八卦一下,memcached的作者BradFitzpatrick,現(xiàn)在在Google,大家如果用Golang的話(huà),Go的官方HTTP包就是這哥們寫(xiě)的,是個(gè)很高產(chǎn)的工程師)。
Redis
如果我沒(méi)記錯(cuò)的話(huà),在2009年前后,一位意大利的工程師Antirez,開(kāi)源了Redis。從此徹底顛覆了緩存的市場(chǎng),到現(xiàn)在大多數(shù)緩存的業(yè)務(wù)都已用上Redis,memcached基本退出了歷史舞臺(tái)。Redis最大的特點(diǎn)是擁有豐富的數(shù)據(jù)結(jié)構(gòu)支持,不僅僅是簡(jiǎn)單的Key-Value,包括隊(duì)列、集合、SortedSet等等,提供了非常豐富的表達(dá)力,而且Redis還提供sub/pub等超出數(shù)據(jù)庫(kù)范疇的便捷功能,使得幾乎一夜之間大家紛紛投入Redis的懷抱。
Twemproxy
但是隨著Redis漸漸的普及,而且越用越狠,另外內(nèi)存也越來(lái)越便宜,人們開(kāi)始尋求擴(kuò)展單機(jī)Redis的方案,最早的嘗試是twitter開(kāi)源的twemproxy,twemproxy是一個(gè)Redis中間件,基本只有最簡(jiǎn)單的數(shù)據(jù)路由功能,并沒(méi)有動(dòng)態(tài)的伸縮能力,但是還是受到了很多公司的追捧,因?yàn)榇_實(shí)沒(méi)方案。隨后的RedisCluster也是難產(chǎn)了好久,時(shí)隔好幾年,中間出了7個(gè)RC版本,最后才發(fā)布:
2014年底,我們開(kāi)源了Codis,解決了Redis中間件的數(shù)據(jù)彈性伸縮問(wèn)題,目前廣泛應(yīng)用于國(guó)內(nèi)各大互聯(lián)網(wǎng)公司中,這個(gè)在網(wǎng)上也有很多文章介紹,我也就不展開(kāi)了。所以在緩存上面,開(kāi)源社區(qū)現(xiàn)在倒是非常統(tǒng)一,就是Redis極其周邊的擴(kuò)展方案。
MongoDB
在NoSQL的大家庭中,MongoDB其實(shí)是一個(gè)異類(lèi),大多NoSQL舍棄掉SQL是為了追求更極致的性能和可擴(kuò)展能力,而MongoDB主動(dòng)選擇了文檔作為對(duì)外的接口,非常像JSON的格式。Schema-less的特性對(duì)于很多輕量級(jí)業(yè)務(wù)和快速變更了互聯(lián)網(wǎng)業(yè)務(wù)意義很大,而且MongoDB的易用性很好,基本做到了開(kāi)箱即用,開(kāi)發(fā)者不需要費(fèi)心研究數(shù)據(jù)的表結(jié)構(gòu),只需要往里存就好了,這確實(shí)籠絡(luò)了一大批開(kāi)發(fā)者。
盡管MongoDB早期的版本各種不穩(wěn)定,性能也不太好(早期的Mongo并沒(méi)有存儲(chǔ)引擎,直接使用了mmap文件),集群模式還全是問(wèn)題(比如至今還未解決的Cluster同步帶寬占用過(guò)多的問(wèn)題),但是因?yàn)榇_實(shí)太方便了,在早期的項(xiàng)目快速迭代中,Mongo是一個(gè)不錯(cuò)的選擇。
但是這也正是它的問(wèn)題,我不止一次聽(tīng)到當(dāng)項(xiàng)目變得龐大或者「嚴(yán)肅」的時(shí)候,團(tuán)隊(duì)最后還是回歸了關(guān)系型數(shù)據(jù)庫(kù)。Anyway,在2014年底MongoDB收購(gòu)了WiredTiger后,在2.8版本中正式亮相,同時(shí)3.0版本后更是作為默認(rèn)存儲(chǔ)引擎提供,性能和穩(wěn)定性有了非常大的提升。
但是,從另一方面講,Schema-less到底對(duì)軟件工程是好事還是壞事這個(gè)問(wèn)題還是有待商榷。我個(gè)人是站在Schema這邊的,不過(guò)在一些小項(xiàng)目或者需要快速開(kāi)發(fā)的項(xiàng)目中使用Mongo確實(shí)能提升很多的開(kāi)發(fā)效率,這是毋庸置疑的。
HBase
說(shuō)到NoSQL不得不提的是HBase,HBase作為Hadoop旗下的重要產(chǎn)品,GoogleBigtable的正統(tǒng)開(kāi)源實(shí)現(xiàn),是不是有一種欽定的感覺(jué):)。提到HBase就不得不提一下Bigtable,Bigtable是Google內(nèi)部廣泛使用的分布式數(shù)據(jù)庫(kù),接口也不是簡(jiǎn)單的Key-Value,按照論文的說(shuō)法叫:multi-dimensionalsortedmap,也就是Value是按照列劃分的。Bigtable構(gòu)建在GFS之上,彌補(bǔ)了分布式文件系統(tǒng)對(duì)于海量、小的、結(jié)構(gòu)化數(shù)據(jù)的插入、更新、隨機(jī)讀請(qǐng)求的缺陷。
HBase就是這么一個(gè)系統(tǒng)的實(shí)現(xiàn),底層依賴(lài)HDFS。HBase本身并不實(shí)際存儲(chǔ)數(shù)據(jù),持久化的日志和SSTfile(HBase也是LSM-Tree的結(jié)構(gòu))直接存儲(chǔ)在HDFS上,RegionServer(RS)維護(hù)了MemTable以提供快速的查詢(xún),寫(xiě)入都是寫(xiě)日志,后臺(tái)進(jìn)行Compact,避免了直接隨機(jī)讀寫(xiě)HDFS。
數(shù)據(jù)通過(guò)Region在邏輯上進(jìn)行分割,負(fù)載均衡通過(guò)調(diào)節(jié)各個(gè)RegionServer負(fù)責(zé)的Region區(qū)間實(shí)現(xiàn)。當(dāng)某Region太大時(shí),這個(gè)Region會(huì)分裂,后續(xù)可能由不同的RS負(fù)責(zé),但是前面提到了,HBase本身并不存儲(chǔ)數(shù)據(jù),這里的Region僅是邏輯上的,數(shù)據(jù)還是以文件的形式存儲(chǔ)在HDFS上,所以HBase并不關(guān)心Replication、水平擴(kuò)展和數(shù)據(jù)的分布,統(tǒng)統(tǒng)交給HDFS解決。
和Bigtable一樣,HBase提供行級(jí)的一致性,嚴(yán)格來(lái)說(shuō)在CAP理論中它是一個(gè)CP的系統(tǒng),但遺憾的是并沒(méi)有更進(jìn)一步提供ACID的跨行事務(wù)。HBase的好處就不用說(shuō)了,顯而易見(jiàn),通過(guò)擴(kuò)展RS可以幾乎線(xiàn)性提升系統(tǒng)的吞吐,及HDFS本身就具有的水平擴(kuò)展能力。
但是缺點(diǎn)仍然是有的。
首先,Hadoop的軟件棧是Java,JVM的GCTuning是一個(gè)非常煩人的事情,即使已經(jīng)調(diào)得很好了,平均延遲也得幾十毫秒:
另外在架構(gòu)設(shè)計(jì)上,HBase本身并不存儲(chǔ)數(shù)據(jù),所以可能造成客戶(hù)端請(qǐng)求的RS并不知道數(shù)據(jù)到底存在哪臺(tái)HDFSDataNode上,憑空多了一次RPC:
第三,HBase和Bigtable一樣,并不支持跨行事務(wù),在Google內(nèi)部不停的有團(tuán)隊(duì)基于Bigtable來(lái)做分布式事務(wù)的支持,比如MegaStore、Percolator。后來(lái)JeffDean有次接受采訪也提到非常后悔沒(méi)有在Bigtable中加入跨行事務(wù),不過(guò)還好這個(gè)遺憾在Spanner中得到了彌補(bǔ),這個(gè)一會(huì)兒說(shuō)。
總體來(lái)說(shuō),HBase還是一個(gè)非常健壯且久經(jīng)考驗(yàn)的系統(tǒng),但是需要你有對(duì)于Java和Hadoop比較深入的了解后,才能玩轉(zhuǎn),這也是Hadoop生態(tài)的一個(gè)問(wèn)題,易用性真是不是太好,而且社區(qū)演進(jìn)速度相對(duì)緩慢,也是因?yàn)闅v史包袱過(guò)重的緣故吧。
Cassandra
提到Cassandra(C*),雖然也是Dynamo的開(kāi)源實(shí)現(xiàn),但就沒(méi)有這種欽定的感覺(jué)了。C*確實(shí)命途多舛,最早2008由Facebook開(kāi)發(fā)并開(kāi)源,早期的C*幾乎全是bug,F(xiàn)acebook后來(lái)索性也不再維護(hù)轉(zhuǎn)過(guò)頭搞HBase去了,一個(gè)爛攤子直接丟給社區(qū)。還好DataStax把這個(gè)項(xiàng)目撿起來(lái)商業(yè)化,搞了兩年,終于漸漸開(kāi)始流行起來(lái)。
C*不能簡(jiǎn)單的歸納為讀快寫(xiě)慢,或者讀慢寫(xiě)快,因?yàn)椴捎昧藂ourm的模型,調(diào)整復(fù)制的副本數(shù)以及讀的數(shù)量,可以達(dá)到不同的效果,對(duì)于一致性不是特別高的場(chǎng)景,可以選擇只從一個(gè)節(jié)點(diǎn)讀取數(shù)據(jù),達(dá)到最高的讀性能。另外C*并不依賴(lài)分布式文件系統(tǒng),數(shù)據(jù)直接存儲(chǔ)在磁盤(pán)上,各個(gè)存儲(chǔ)節(jié)點(diǎn)之間自己維護(hù)復(fù)制關(guān)系,減少了一層RPC調(diào)用,延遲上對(duì)比HBase還是有一定優(yōu)勢(shì)的。
不過(guò)即使使用qourm的模型也并不代表C*是一個(gè)強(qiáng)一致的系統(tǒng)。C*并不幫你解決沖突,即使你W(寫(xiě)的副本數(shù))+R(讀請(qǐng)求的副本數(shù))>N(節(jié)點(diǎn)總數(shù)),C*也沒(méi)辦法幫你決定哪些副本擁有更新的版本,因?yàn)槊總(gè)數(shù)據(jù)的版本是一個(gè)NTP的時(shí)間戳或者客戶(hù)端自行提供,每臺(tái)機(jī)器可能都有誤差,所以有可能并不準(zhǔn)確,這也就是為什么C*是一個(gè)AP的系統(tǒng)。不過(guò)C*一個(gè)比較友好的地方是提供了CQL,一個(gè)簡(jiǎn)單的SQL方言,比起HBase在易用性上有明顯優(yōu)勢(shì)。
即使作為一個(gè)AP系統(tǒng),C*已經(jīng)挺快了,但是人們追求更高性能的腳步還是不會(huì)停止。應(yīng)該是今年年初,ScyllaDB的發(fā)布就是典型的證明,ScyllaDB是一個(gè)兼容C*的NoSQL數(shù)據(jù)庫(kù),不一樣的是,ScyllaDB完全用C++開(kāi)發(fā),同時(shí)使用了類(lèi)似DPDK這樣的黑科技,具體我就不展開(kāi)了,有興趣可以到Scylla的官網(wǎng)去看看。BTW,國(guó)內(nèi)的蘑菇街第一時(shí)間使用了ScyllaDB,同時(shí)在Scylla的官網(wǎng)上share了他們的方案,性能還是很不錯(cuò)的。
3、中間件與分庫(kù)分表
NoSQL就先介紹到這里,接下來(lái)我想說(shuō)的是一些在基于單機(jī)關(guān)系型數(shù)據(jù)庫(kù)之上的中間件和分庫(kù)分表方案。
在這方面確實(shí)歷史悠久,而且也是沒(méi)有辦法的選擇,關(guān)系型數(shù)據(jù)庫(kù)不比Redis,并不是簡(jiǎn)單的寫(xiě)一個(gè)類(lèi)似Twemproxy的中間件就搞定了。數(shù)據(jù)庫(kù)的中間件需要考慮很多,比如解析SQL,解析出shardingkey,然后根據(jù)shardingkey分發(fā)請(qǐng)求,再合并:另外數(shù)據(jù)庫(kù)有事務(wù),在中間件這層還需要維護(hù)Session及事務(wù)狀態(tài),而且大多數(shù)方案并沒(méi)有辦法支持跨shard的事務(wù)。
這就不可避免的導(dǎo)致了業(yè)務(wù)使用起來(lái)會(huì)比較麻煩,需要重寫(xiě)代碼,而且會(huì)增加邏輯的復(fù)雜度,更別提動(dòng)態(tài)的擴(kuò)容縮容和自動(dòng)的故障恢復(fù)了。在集群規(guī)模越來(lái)越大的情況下,運(yùn)維和DDL的復(fù)雜度是指數(shù)級(jí)上升的。
中間件項(xiàng)目盤(pán)點(diǎn)
數(shù)據(jù)庫(kù)中間件最早的項(xiàng)目大概是MySQLProxy,用于實(shí)現(xiàn)讀寫(xiě)分離。后來(lái)國(guó)人在這個(gè)領(lǐng)域有過(guò)很多的著名的開(kāi)源項(xiàng)目,比如阿里的Cobar和DDL(并未完全開(kāi)源:后來(lái)社區(qū)基于Cobar改進(jìn)的MyCAT、360開(kāi)源的Atlas等,都屬于這一類(lèi)中間件產(chǎn)品:
在中間件這個(gè)方案上基本走到頭的開(kāi)源項(xiàng)目應(yīng)該是YoutubeVitesse。Vitess基本上是一個(gè)集大成的中間件產(chǎn)品,內(nèi)置了熱數(shù)據(jù)緩存、水平動(dòng)態(tài)分片、讀寫(xiě)分離等等,但是代價(jià)也是整個(gè)項(xiàng)目非常復(fù)雜,另外文檔也不太好。大概1年多以前,我們嘗試搭建起完整的Vitess集群,但是并未成功,可見(jiàn)其復(fù)雜度。
另外一個(gè)值得一提的是Postgres-XC這個(gè)項(xiàng)目,Postgres-XC的野心還是很大的,整體的架構(gòu)有點(diǎn)像早期版本的OceanBase,由一個(gè)中央節(jié)點(diǎn)來(lái)處理協(xié)調(diào)分布式事務(wù)/解決沖突,數(shù)據(jù)分散在各個(gè)存儲(chǔ)節(jié)點(diǎn)上,應(yīng)該是目前PostgreSQL社區(qū)最好的分布式擴(kuò)展方案。其他的就不提了。
4、未來(lái)在哪里?NewSQL?
一句話(huà),NewSQL是未來(lái)。
2012年Google在OSDI上發(fā)表了Spanner的論文,2013年在SIGMOD發(fā)表了F1的論文。這兩篇論文讓業(yè)界第一次看到了關(guān)系模型和NoSQL的擴(kuò)展性在超龐大集群規(guī)模上融合的可能性。在此之前,大家普遍認(rèn)為這個(gè)是不可能的,即使是Google也經(jīng)歷了Megastore這樣系統(tǒng)的失敗。
Spanner綜述
但是Spanner的創(chuàng)新之處在于通過(guò)硬件(GPS時(shí)鐘+原子鐘)來(lái)解決時(shí)鐘同步的問(wèn)題。在分布式系統(tǒng)里,時(shí)鐘是最讓人頭痛的問(wèn)題,剛才提到了C*為什么不是一個(gè)強(qiáng)C的系統(tǒng),正是因?yàn)闀r(shí)鐘的問(wèn)題。而Spanner的厲害之處在于即使兩個(gè)數(shù)據(jù)中心隔得非常遠(yuǎn),不需要有通信(因?yàn)橥ㄐ诺拇鷥r(jià)太大,最快也就是光速)就能保證TrueTimeAPI的時(shí)鐘誤差在一個(gè)很小的范圍內(nèi)(10ms)。另外Spanner沿用了很多Bigtable的設(shè)計(jì),比如Tablet/Directory等,同時(shí)在Replica這層使用Paxos復(fù)制,并未完全依賴(lài)底層的分布式文件系統(tǒng)。但是Spanner的設(shè)計(jì)底層仍然沿用了Colossus,不過(guò)論文里也說(shuō)是可以未來(lái)改進(jìn)的點(diǎn)。
Google的內(nèi)部的數(shù)據(jù)庫(kù)存儲(chǔ)業(yè)務(wù),大多是3~5副本,重要一點(diǎn)的7副本,遍布全球各大洲的數(shù)據(jù)中心,由于普遍使用了Paxos,延遲是可以縮短到一個(gè)可以接受的范圍(Google的風(fēng)格一向是追求吞吐的水平擴(kuò)展而不是低延遲,從悲觀鎖的選擇也能看得出來(lái),因?yàn)榭鐢?shù)據(jù)中心復(fù)制是必選的,延遲不可能低,對(duì)于低延遲的場(chǎng)景,業(yè)務(wù)層自己解決或者依賴(lài)緩存)。
另外由Paxos帶來(lái)的Auto-Failover能力,更是能讓整個(gè)集群即使數(shù)據(jù)中心癱瘓,業(yè)務(wù)層都是透明無(wú)感知的。另外F1構(gòu)建在Spanner之上,對(duì)外提供了更豐富的SQL語(yǔ)法支持,F(xiàn)1更像一個(gè)分布式MPPSQL——F1本身并不存儲(chǔ)數(shù)據(jù),而是將客戶(hù)端的SQL翻譯成類(lèi)似MapReduce的任務(wù),調(diào)用Spanner來(lái)完成請(qǐng)求。
其實(shí)除了TrueTime整個(gè)系統(tǒng)并沒(méi)有用什么全新的算法,而是近些年分布式系統(tǒng)的技術(shù)Spanner和F1的出現(xiàn)標(biāo)志著第一個(gè)NewSQL在生產(chǎn)環(huán)境中提供服務(wù)。
有以下幾個(gè)重點(diǎn):
1.完整的SQL支持,ACID事務(wù):
2.彈性伸縮能力:
3.自動(dòng)的故障轉(zhuǎn)移和故障恢復(fù),多機(jī)房異地災(zāi)備。
NewSQL特性確實(shí)非常誘人,在Google內(nèi)部,大量的業(yè)務(wù)已經(jīng)從原來(lái)的Bigtable切換到Spanner之上。我相信未來(lái)幾年,整個(gè)業(yè)界的趨勢(shì)也是如此,就像當(dāng)年的Hadoop一樣,Google的基礎(chǔ)軟件的技術(shù)趨勢(shì)是走在社區(qū)前面的。
社區(qū)反應(yīng)
Spanner的論文發(fā)表之后,當(dāng)然也有社區(qū)的追隨者開(kāi)始實(shí)現(xiàn)(比如我們:D),第一個(gè)團(tuán)隊(duì)是在紐約的Cockr
OAchDB。CockroachDB的團(tuán)隊(duì)的組成還是非常豪華的,早期團(tuán)隊(duì)由是Google的分布式文件系統(tǒng)Colossus團(tuán)隊(duì)的成員組成:技術(shù)上來(lái)說(shuō),Cockroach的設(shè)計(jì)和Spanner很像,不一樣的地方是沒(méi)有選擇TrueTime而是HLC(Hybridlogicalclock),也就是NTP+邏輯時(shí)鐘來(lái)代替TrueTime時(shí)間戳:另外Cockroach選用了Raft代替Paxos實(shí)現(xiàn)復(fù)制和自動(dòng)容災(zāi),底層存儲(chǔ)依賴(lài)RocksDB實(shí)現(xiàn),整個(gè)項(xiàng)目使用Go語(yǔ)言開(kāi)發(fā),對(duì)外接口選用PostgreSQL的SQL子集。
CockroachDB
CockroachDB的技術(shù)選型比較激進(jìn),比如依賴(lài)了HLC來(lái)做事務(wù)的時(shí)間戳。但是在Spanner的事務(wù)模型的CommitWait階段等待時(shí)間的選擇,CockroachDB并沒(méi)有辦法做到10ms內(nèi)的延遲:CockroachDB的CommitWait需要用戶(hù)自己指定,但是誰(shuí)能拍胸脯說(shuō)NTP的時(shí)鐘誤差在多少毫秒內(nèi)?我個(gè)人認(rèn)為在處理跨洲際機(jī)房時(shí)鐘同步的問(wèn)題上,基本只有硬件時(shí)鐘一種辦法。HLC是沒(méi)辦法解決的。
另外Cockroach采用了gossip來(lái)同步節(jié)點(diǎn)信息,當(dāng)集群變得比較大的時(shí)候,gossip心跳會(huì)是一個(gè)非常大的開(kāi)銷(xiāo)。當(dāng)然CockroachDB的這些技術(shù)選擇帶來(lái)的優(yōu)勢(shì)就是非常好的易用性,所有邏輯都在一個(gè)binary中,開(kāi)箱即用,這個(gè)是非常大的優(yōu)點(diǎn)。
TiDB
目前從全球范圍來(lái)看,另一個(gè)在朝著Spanner/F1的開(kāi)源實(shí)現(xiàn)這個(gè)目標(biāo)上走的產(chǎn)品是TiDB(終于談到我們的產(chǎn)品了)。TiDB本質(zhì)上是一個(gè)更加正統(tǒng)的Spanner和F1實(shí)現(xiàn),并不像CockroachDB那樣選擇將SQL和Key-Value融合,而是像Spanner和F1一樣選擇分離,這樣分層的思想也是貫穿整個(gè)TiDB項(xiàng)目始終的。對(duì)于測(cè)試、滾動(dòng)升級(jí)以及各層的復(fù)雜度控制會(huì)比較有優(yōu)勢(shì):另外TiDB選擇了MySQL協(xié)議和語(yǔ)法的兼容,MySQL社區(qū)的ORM框架,運(yùn)維工具,直接可以應(yīng)用在TiDB上。
和Spanner一樣,TiDB是一個(gè)無(wú)狀態(tài)的MPPSQLLayer,整個(gè)系統(tǒng)的底層是依賴(lài)TiKey-Value來(lái)提供分布式存儲(chǔ)和分布式事務(wù)的支持。TiKey-Value的分布式事務(wù)模型采用的是GooglePercolator的模型,但是在此之上做了很多優(yōu)化。Percolator的優(yōu)點(diǎn)是去中心化程度非常高,整個(gè)集群不需要一個(gè)獨(dú)立的事務(wù)管理模塊,事務(wù)提交狀態(tài)這些信息其實(shí)是均勻分散在系統(tǒng)的各個(gè)Key的meta中,整個(gè)模型唯一依賴(lài)的是一個(gè)授時(shí)服務(wù)器。
在我們的系統(tǒng)上,極限情況這個(gè)授時(shí)服務(wù)器每秒能分配400w以上個(gè)單調(diào)遞增的時(shí)間戳,大多數(shù)情況基本夠用了(畢竟有Google量級(jí)的場(chǎng)景并不多見(jiàn)):同時(shí)在TiKey-Value中,這個(gè)授時(shí)服務(wù)本身是高可用的,也不存在單點(diǎn)故障的問(wèn)題。
TiKey-Value和CockroachDB一樣也是選擇了Raft作為整個(gè)數(shù)據(jù)庫(kù)的基礎(chǔ):不一樣的是,TiKey-Value整體采用Rust語(yǔ)言開(kāi)發(fā),作為一個(gè)沒(méi)有GC和Runtime的語(yǔ)言,在性能上可以挖掘的潛力會(huì)更大。
關(guān)于未來(lái)
我覺(jué)得未來(lái)的數(shù)據(jù)庫(kù)會(huì)有幾個(gè)趨勢(shì),也是TiDB項(xiàng)目追求的目標(biāo):
數(shù)據(jù)庫(kù)會(huì)隨著業(yè)務(wù)云化,未來(lái)一切的業(yè)務(wù)都會(huì)跑在云端,不管是私有云或者公有云,運(yùn)維團(tuán)隊(duì)接觸的可能再也不是真實(shí)的物理機(jī),而是一個(gè)個(gè)隔離的容器或者「計(jì)算資源」。這對(duì)數(shù)據(jù)庫(kù)也是一個(gè)挑戰(zhàn),因?yàn)閿?shù)據(jù)庫(kù)天生就是有狀態(tài)的,數(shù)據(jù)總是要存儲(chǔ)在物理的磁盤(pán)上,而數(shù)據(jù)的移動(dòng)的代價(jià)比移動(dòng)容器的代價(jià)可能大很多。
多租戶(hù)技術(shù)會(huì)成為標(biāo)配,一個(gè)大數(shù)據(jù)庫(kù)承載一切的業(yè)務(wù),數(shù)據(jù)在底層打通,上層通過(guò)權(quán)限,容器等技術(shù)進(jìn)行隔離:但是數(shù)據(jù)的打通和擴(kuò)展會(huì)變得異常簡(jiǎn)單,結(jié)合第一點(diǎn)提到的云化,業(yè)務(wù)層可以再也不用關(guān)心物理機(jī)的容量和拓?fù)洌恍枰J(rèn)為底層是一個(gè)無(wú)窮大的數(shù)據(jù)庫(kù)平臺(tái)即可,不用再擔(dān)心單機(jī)容量和負(fù)載均衡等問(wèn)題。
OLAP和OLTP會(huì)進(jìn)一步細(xì)分,底層存儲(chǔ)也許會(huì)共享一套,但是SQL優(yōu)化器這層的實(shí)現(xiàn)一定是千差萬(wàn)別的。對(duì)于用戶(hù)而言,如果能使用同一套標(biāo)準(zhǔn)的語(yǔ)法和規(guī)則來(lái)進(jìn)行數(shù)據(jù)的讀寫(xiě)和分析,會(huì)有更好的體驗(yàn)。
在未來(lái)分布式數(shù)據(jù)庫(kù)系統(tǒng)上,主從日志同步這樣落后的備份方式會(huì)被Multi-Paxos/Raft這樣更強(qiáng)的分布式一致性算法替代,人工的數(shù)據(jù)庫(kù)運(yùn)維在管理大規(guī)模數(shù)據(jù)庫(kù)集群時(shí)是不可能的,所有的故障恢復(fù)和高可用都會(huì)是高度自動(dòng)化的。
5、答疑環(huán)節(jié)
問(wèn):HANA等內(nèi)存數(shù)據(jù)庫(kù)怎么保證系統(tǒng)掉電而處理結(jié)果不丟?傳統(tǒng)數(shù)據(jù)庫(kù)也用緩存,可是HANA用的內(nèi)存太大。
黃東旭:沒(méi)用過(guò)HANA,但是直觀感覺(jué)這類(lèi)內(nèi)存數(shù)據(jù)庫(kù)的可用性可能通過(guò)集中方式保證:
寫(xiě)入會(huì)先寫(xiě)WAL:
寫(xiě)入可能會(huì)通過(guò)主從或者paxos之類(lèi)的算法做同步和冗余復(fù)制還有HANA本身就是內(nèi)存數(shù)據(jù)庫(kù),會(huì)盡可能把數(shù)據(jù)放到內(nèi)存里,這樣查詢(xún)才能快呀。
問(wèn):對(duì)于傳統(tǒng)創(chuàng)業(yè)公司如何彌補(bǔ)NoSQL的技術(shù)短板?快速的引入NoSQL提高效率?
黃東旭:選用NoSQL主要注意兩點(diǎn):
做好業(yè)務(wù)的調(diào)研,估計(jì)并發(fā)量,數(shù)據(jù)量,數(shù)據(jù)的結(jié)構(gòu)看看適不適合:
對(duì)各種NoSQL擅長(zhǎng)和不擅長(zhǎng)的地方都盡可能了解。
不要盲目相信關(guān)系型數(shù)據(jù)庫(kù),也不要盲目相信NoSQL,沒(méi)有銀彈的。
問(wèn):有多個(gè)條件,比如年齡20到30或年齡35到40,并且加入購(gòu)物車(chē)或下單,這種數(shù)據(jù)怎么存儲(chǔ)?
黃東旭:購(gòu)物車(chē)這種場(chǎng)景是典型的OLTP的場(chǎng)景,可以選用關(guān)系型數(shù)據(jù)庫(kù)MySQLPostgreSQL什么的,如果對(duì)于擴(kuò)展性的數(shù)據(jù)跨機(jī)房有要求的話(huà),可以調(diào)研一下NewSQL,比如我們的TiDB。
問(wèn):多緯度查詢(xún)應(yīng)該選擇哪種數(shù)據(jù)庫(kù)?
黃東旭:多緯度查詢(xún)可以說(shuō)是一個(gè)OLAP的場(chǎng)景,可以選用Greenplum或者Vertica之類(lèi)的分析性數(shù)據(jù)庫(kù)。
問(wèn):想知道為什么需要這些開(kāi)源的數(shù)據(jù)庫(kù),既然已經(jīng)有了MySQL、DB2、Oracle這些成熟的數(shù)據(jù)庫(kù),成本考慮,還是傳統(tǒng)數(shù)據(jù)庫(kù)滿(mǎn)足不了需求?
黃東旭:對(duì),傳統(tǒng)數(shù)據(jù)庫(kù)的擴(kuò)展性是有問(wèn)題的,在海量并發(fā)和數(shù)據(jù)量的場(chǎng)景下很難支持業(yè)務(wù)。所以可以看到比較大的互聯(lián)網(wǎng)公司基本都有自己的分布式數(shù)據(jù)庫(kù)方案。
黃東旭:大家可以想想數(shù)據(jù)倉(cāng)庫(kù)的定義,如果是還需要離線(xiàn)的從線(xiàn)上庫(kù)倒騰數(shù)據(jù)到數(shù)據(jù)倉(cāng)庫(kù)上,這樣很難做到實(shí)時(shí)查詢(xún),而且空間的利用率也低,我認(rèn)為是目前并沒(méi)有太好的方案的情況下的折衷……
核心關(guān)注:拓步ERP系統(tǒng)平臺(tái)是覆蓋了眾多的業(yè)務(wù)領(lǐng)域、行業(yè)應(yīng)用,蘊(yùn)涵了豐富的ERP管理思想,集成了ERP軟件業(yè)務(wù)管理理念,功能涉及供應(yīng)鏈、成本、制造、CRM、HR等眾多業(yè)務(wù)領(lǐng)域的管理,全面涵蓋了企業(yè)關(guān)注ERP管理系統(tǒng)的核心領(lǐng)域,是眾多中小企業(yè)信息化建設(shè)首選的ERP管理軟件信賴(lài)品牌。
轉(zhuǎn)載請(qǐng)注明出處:拓步ERP資訊網(wǎng)http://www.ezxoed.cn/
本文標(biāo)題:一文掌握所有開(kāi)源數(shù)據(jù)庫(kù)的現(xiàn)狀
本文網(wǎng)址:http://www.ezxoed.cn/html/support/11121519536.html