久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

「數(shù)據(jù)庫選型」拋棄MongoDB,,擁抱PostgreSQL,,工作更輕松

 xxcc140 2020-01-21

Olery成立于5年前。隨著時(shí)間的流逝,,最初由Ruby開發(fā)機(jī)構(gòu)開發(fā)的單一產(chǎn)品(Olery聲望)逐漸發(fā)展成為一套不同的產(chǎn)品和許多不同的應(yīng)用程序,。今天,我們不僅擁有信譽(yù)產(chǎn)品,,還擁有Olery反饋,,酒店點(diǎn)評(píng)數(shù)據(jù)API,可嵌入網(wǎng)站上的小部件以及不久的將來更多產(chǎn)品/服務(wù),。

在應(yīng)用程序數(shù)量方面,,我們也有了長足的發(fā)展。今天,,我們部署了超過25種不同的應(yīng)用程序(全部為Ruby),,其中一些是Web應(yīng)用程序(Rails或Sinatra),但大多數(shù)是后臺(tái)處理應(yīng)用程序,。

盡管我們可以為迄今為止所取得的成就感到非常自豪,,但總會(huì)有一些隱患:我們的主數(shù)據(jù)庫。從Olery開始,,我們就已經(jīng)建立了一個(gè)數(shù)據(jù)庫設(shè)置,,其中涉及MySQL來存儲(chǔ)關(guān)鍵數(shù)據(jù)(用戶,合同等),,而MongoDB則用于存儲(chǔ)評(píng)論和類似數(shù)據(jù)(本質(zhì)上是在數(shù)據(jù)丟失的情況下我們可以輕松檢索的數(shù)據(jù)),。盡管此設(shè)置對(duì)我們非常有用,但隨著我們的發(fā)展,,特別是在MongoDB中,,我們開始遇到各種問題。這些問題中的一些是由于應(yīng)用程序與數(shù)據(jù)庫交互的方式所致,,有些是由于數(shù)據(jù)庫本身所致,。

例如,在某個(gè)時(shí)間點(diǎn),,我們必須從MongoDB中刪除大約一百萬個(gè)文檔,,然后在以后重新插入它們。此過程的結(jié)果是數(shù)據(jù)庫幾乎處于完全鎖定狀態(tài),,持續(xù)了幾個(gè)小時(shí),,導(dǎo)致性能下降,。直到我們執(zhí)行數(shù)據(jù)庫修復(fù)(使用MongoDB的repairDatabase命令)。由于數(shù)據(jù)庫的大小,,此修復(fù)程序本身也花費(fèi)了數(shù)小時(shí)才能完成,。

在另一個(gè)實(shí)例中,我們注意到應(yīng)用程序性能下降,,并設(shè)法將其追溯到我們的MongoDB集群,。但是,經(jīng)過進(jìn)一步檢查,,我們無法找到問題的真正原因,。無論我們安裝了什么度量標(biāo)準(zhǔn),使用的工具或運(yùn)行的命令,,我們都找不到原因,。直到我們替換了集群的主節(jié)點(diǎn),性能才恢復(fù)到正常水平,。

這只是兩個(gè)例子,,隨著時(shí)間的流逝,我們遇到了很多這樣的情況,。這里的核心問題不僅在于我們的數(shù)據(jù)庫正在運(yùn)行,,而且每當(dāng)我們調(diào)查數(shù)據(jù)庫時(shí),都根本沒有跡象表明導(dǎo)致問題的原因,。

無模式問題

我們面臨的另一個(gè)核心問題是MongoDB(或任何其他無模式存儲(chǔ)引擎)的基本功能之一:缺少模式,。缺少模式聽起來可能很有趣,并且在某些情況下,,它當(dāng)然可以帶來好處,。但是,對(duì)于許多人而言,,無模式存儲(chǔ)引擎的使用會(huì)導(dǎo)致隱式模式的問題。這些架構(gòu)不是由您的存儲(chǔ)引擎定義的,,而是根據(jù)應(yīng)用程序的行為和期望定義的,。

例如,您可能有一個(gè)頁面集合,,其中您的應(yīng)用程序需要一個(gè)帶有字符串類型的標(biāo)題字段,。盡管沒有明確定義,但這里的模式非常多,。如果數(shù)據(jù)的結(jié)構(gòu)隨時(shí)間而變化,,這是有問題的,尤其是如果舊數(shù)據(jù)沒有遷移到新的結(jié)構(gòu)中(在無模式存儲(chǔ)引擎中這是很成問題的),。例如,,假設(shè)您具有以下Ruby代碼:

#!ruby post_slug = post.title.downcase.gsub(/\W+/, '-')

這將適用于每個(gè)帶有標(biāo)題字段且返回字符串的文檔,。 對(duì)于使用其他字段名稱(例如post_title)或根本沒有標(biāo)題的字段的文檔,這將不起作用,。 要處理這種情況,,您需要按以下方式調(diào)整代碼:

#!ruby if post.title post_slug = post.title.downcase.gsub(/\W+/, '-') else # ... end

解決此問題的另一種方法是在模型中定義架構(gòu)。例如,,Mongoid是流行的Ruby MongoDB ODM,,可以讓您做到這一點(diǎn)。但是,,在使用此類工具定義架構(gòu)時(shí),,應(yīng)該思考為什么他們沒有在數(shù)據(jù)庫本身中定義架構(gòu)。這樣做將解決另一個(gè)問題:可重用性,。如果只有一個(gè)應(yīng)用程序,,那么在代碼中定義架構(gòu)并不是什么大問題。但是,,當(dāng)您有數(shù)十個(gè)應(yīng)用程序時(shí),,這很快就會(huì)變成一團(tuán)糟。

無模式存儲(chǔ)引擎通過消除對(duì)模式的擔(dān)心,,有望使您的生活更輕松,。實(shí)際上,這些系統(tǒng)只是讓您自己負(fù)責(zé)確保數(shù)據(jù)一致性,。在某些情況下,,這可能會(huì)解決,但我敢打賭,,對(duì)于大多數(shù)情況而言,,這只會(huì)適得其反。

好的數(shù)據(jù)庫的要求

這使我想到了一個(gè)好的數(shù)據(jù)庫的要求,,更具體地說是Olery的要求,。對(duì)于系統(tǒng),尤其是數(shù)據(jù)庫,,我們重視以下方面:

  • 一致性,。
  • 數(shù)據(jù)的可見性和系統(tǒng)的行為。
  • 正確性和明確性,。
  • 可擴(kuò)展性,。

一致性很重要,因?yàn)樗兄谠O(shè)定對(duì)系統(tǒng)的明確期望,。如果數(shù)據(jù)總是以某種方式存儲(chǔ),,那么使用該數(shù)據(jù)的系統(tǒng)將變得更加簡單。如果在數(shù)據(jù)庫級(jí)別需要某個(gè)字段,則應(yīng)用程序無需檢查該字段是否存在。數(shù)據(jù)庫即使在高壓下也應(yīng)該能夠保證某些操作的完成。沒有什么比僅插入數(shù)據(jù)而令人沮喪的了,,只有在幾分鐘之后才顯示數(shù)據(jù)。

可見性適用于兩件事:系統(tǒng)本身以及從其中獲取數(shù)據(jù)的難易程度,。如果系統(tǒng)出現(xiàn)異常,則應(yīng)易于調(diào)試,。反過來,,如果用戶想查詢數(shù)據(jù),這也應(yīng)該很容易,。

正確性意味著系統(tǒng)的行為符合預(yù)期,。如果將某個(gè)字段定義為數(shù)字值,則不應(yīng)將文本插入該字段,。 MySQL的缺點(diǎn)是眾所周知的,,因?yàn)樗梢宰屇鷾?zhǔn)確地做到這一點(diǎn),結(jié)果您可能會(huì)得到虛假數(shù)據(jù),。

可伸縮性不僅適用于性能,,而且還適用于財(cái)務(wù)方面,以及系統(tǒng)如何滿足隨著時(shí)間變化的需求,。一個(gè)系統(tǒng)的性能可能非常好,,但是卻不能以大量金錢為代價(jià),也不會(huì)減慢依賴于它的系統(tǒng)的開發(fā)周期,。

遠(yuǎn)離MongoDB

考慮到以上值,,我們著手尋找MongoDB的替代者。上面提到的值通常是傳統(tǒng)RDBMS的一組核心功能,,因此我們著眼于兩個(gè)候選對(duì)象:MySQL和PostgreSQL,。

MySQL是第一個(gè)候選對(duì)象,因?yàn)槲覀円呀?jīng)在一些關(guān)鍵數(shù)據(jù)中使用它,。但是MySQL并非沒有問題,。例如,在將字段定義為int(11)時(shí),,您可以輕松地插入文本數(shù)據(jù),,MySQL會(huì)嘗試對(duì)其進(jìn)行轉(zhuǎn)換。一些例子:

mysql> create table example ( `number` int(11) not null ); Query OK, 0 rows affected (0.08 sec) mysql> insert into example (number) values (10); Query OK, 1 row affected (0.08 sec) mysql> insert into example (number) values ('wat'); Query OK, 1 row affected, 1 warning (0.10 sec) mysql> insert into example (number) values ('what is this 10 nonsense'); Query OK, 1 row affected, 1 warning (0.14 sec) mysql> insert into example (number) values ('10 a'); Query OK, 1 row affected, 1 warning (0.09 sec) mysql> select * from example; +--------+ | number | +--------+ | 10 | | 0 | | 0 | | 10 | +--------+ 4 rows in set (0.00 sec)

值得注意的是,,在這種情況下,MySQL會(huì)發(fā)出警告,。 但是,,由于警告只是警告,因此常常(即使不是總是)將它們忽略,。

MySQL的另一個(gè)問題是任何表修改(例如添加列)都會(huì)導(dǎo)致表被鎖定以進(jìn)行讀取和寫入,。 這意味著使用此類表的任何操作都必須等待修改完成,。 對(duì)于具有大量數(shù)據(jù)的表,這可能需要數(shù)小時(shí)才能完成,,這可能導(dǎo)致應(yīng)用程序停機(jī),。 這已導(dǎo)致SoundCloud等公司開發(fā)諸如lhm之類的工具來解決這一問題。

基于上述考慮,,我們開始研究PostgreSQL,。 PostgreSQL在很多方面做得很好,而MySQL則做不到,。 例如,,您不能將文本數(shù)據(jù)插入數(shù)字字段:

olery_development=# create table example ( number int not null ); CREATE TABLE olery_development=# insert into example (number) values (10); INSERT 0 1 olery_development=# insert into example (number) values ('wat'); ERROR: invalid input syntax for integer: 'wat' LINE 1: insert into example (number) values ('wat'); ^ olery_development=# insert into example (number) values ('what is this 10 nonsense'); ERROR: invalid input syntax for integer: 'what is this 10 nonsense' LINE 1: insert into example (number) values ('what is this 10 nonsen... ^ olery_development=# insert into example (number) values ('10 a'); ERROR: invalid input syntax for integer: '10 a' LINE 1: insert into example (number) values ('10 a');

PostgreSQL還具有以各種方式更改表的功能,而無需為每個(gè)操作鎖定表,。例如,,添加一個(gè)沒有默認(rèn)值并且可以設(shè)置為NULL的列可以快速完成,而無需鎖定整個(gè)表,。

PostgreSQL中還有許多其他有趣的功能,,例如:基于Trigram的索引和搜索,全文本搜索,,對(duì)JSON查詢的支持,,對(duì)查詢/存儲(chǔ)鍵值對(duì)的支持,對(duì)發(fā)布/訂閱的支持等等,。

所有PostgreSQL中最重要的是在性能,,可靠性,正確性和一致性之間取得平衡,。

遷移到PostgreSQL

最后,,我們決定與PostgreSQL達(dá)成和解,以便在我們關(guān)心的各個(gè)主題之間取得平衡,。從MongoDB遷移整個(gè)平臺(tái)到完全不同的數(shù)據(jù)庫的過程并非易事,。為了簡化過渡過程,我們將這個(gè)過程大致分為3個(gè)步驟:

設(shè)置PostgreSQL數(shù)據(jù)庫并遷移一小部分?jǐn)?shù)據(jù),。更新所有依賴MongoDB來使用PostgreSQL的應(yīng)用程序,,以及支持此功能所需的任何重構(gòu)。將生產(chǎn)數(shù)據(jù)遷移到新數(shù)據(jù)庫并部署新平臺(tái),。

遷移子集

在我們甚至考慮遷移所有數(shù)據(jù)之前,,我們需要使用一小部分最終數(shù)據(jù)來運(yùn)行測(cè)試。如果您知道即使是一小部分?jǐn)?shù)據(jù)也會(huì)給您帶來很多麻煩,,那么遷移毫無意義,。

雖然存在可以解決此問題的工具,但我們還必須轉(zhuǎn)換一些數(shù)據(jù)(例如,重命名字段,,更改類型等),,因此必須為此編寫自己的工具。這些工具大部分是一次性的Ruby腳本,,每個(gè)腳本執(zhí)行特定的任務(wù),,例如移交評(píng)論,清理編碼,,更正主鍵序列等,。

最初的測(cè)試階段并未發(fā)現(xiàn)任何可能阻礙遷移過程的問題,盡管我們的某些數(shù)據(jù)部分存在問題,。例如,,某些用戶提交的內(nèi)容并非總是正確地編碼,因此,,如果不先清除它們就無法導(dǎo)入,。需要進(jìn)行的另一個(gè)有趣的更改是將評(píng)論的語言名稱從其全名(“荷蘭語”,“英語”等)更改為語言代碼,,因?yàn)槲覀兊男虑楦蟹治龆褩J褂谜Z言代碼代替了全名,。

更新應(yīng)用

到目前為止,大部分時(shí)間都花在了更新應(yīng)用程序上,,尤其是那些嚴(yán)重依賴MongoDB聚合框架的應(yīng)用程序,。投入一些測(cè)試覆蓋率較低的舊版Rails應(yīng)用程序,您將有數(shù)周的工作時(shí)間,。這些應(yīng)用程序的更新過程基本上如下:

  • 將MongoDB驅(qū)動(dòng)程序/模型設(shè)置代碼替換為PostgreSQL相關(guān)代碼
  • 運(yùn)行測(cè)試
  • 修復(fù)一些測(cè)試
  • 再次運(yùn)行測(cè)試,,沖洗并重復(fù)直到所有測(cè)試通過

對(duì)于非Rails應(yīng)用程序,我們決定使用Sequel,,而我們?cè)赗ails應(yīng)用程序中堅(jiān)持使用ActiveRecord(至少現(xiàn)在是這樣),。 Sequel是一個(gè)很棒的數(shù)據(jù)庫工具包,它支持我們可能想使用的大多數(shù)(如果不是全部)PostgreSQL特定功能,。與ActiveRecord相比,,其查詢構(gòu)建DSL的功能也要強(qiáng)大得多,盡管有時(shí)可能會(huì)有些冗長,。

例如,,假設(shè)您要計(jì)算使用某個(gè)語言環(huán)境的用戶數(shù)量以及每個(gè)語言環(huán)境的百分比(相對(duì)于整個(gè)集合)。在普通的SQL中,,這樣的查詢?nèi)缦滤荆?/p>

#!sql SELECT locale, count(*) AS amount, (count(*) / sum(count(*)) OVER ()) * 100.0 AS percentage FROM users GROUP BY locale ORDER BY percentage DESC;

在我們的例子中,,這將產(chǎn)生以下輸出(使用PostgreSQL命令行界面時(shí)):

locale | amount | percentage --------+--------+-------------------------- en | 2779 | 85.193133047210300429000 nl | 386 | 11.833231146535867566000 it | 40 | 1.226241569589209074000 de | 25 | 0.766400980993255671000 ru | 17 | 0.521152667075413857000 | 7 | 0.214592274678111588000 fr | 4 | 0.122624156958920907000 ja | 1 | 0.030656039239730227000 ar-AE | 1 | 0.030656039239730227000 eng | 1 | 0.030656039239730227000 zh-CN | 1 | 0.030656039239730227000 (11 rows)

Sequel允許您使用純Ruby編寫上述查詢,而無需字符串片段(這是ActiveRecord經(jīng)常需要的):

#!ruby star = Sequel.lit('*') User.select(:locale) .select_append { count(star).as(:amount) } .select_append { ((count(star) / sum(count(star)).over) * 100.0).as(:percentage) } .group(:locale) .order(Sequel.desc(:percentage))

如果您不喜歡使用Sequel.lit('*'),,也可以使用以下語法:

#!ruby User.select(:locale) .select_append { count(users.*).as(:amount) } .select_append { ((count(users.*) / sum(count(users.*)).over) * 100.0).as(:percentage) } .group(:locale) .order(Sequel.desc(:percentage))

雖然這兩個(gè)查詢可能都比較冗長,,但它們更易于重用部分查詢,,而不必訴諸字符串連接。

將來,,我們可能還會(huì)將Rails應(yīng)用程序移至Sequel,但是考慮到Rails與ActiveRecord緊密相連,,我們尚不確定是否值得花時(shí)間和精力,。

遷移生產(chǎn)數(shù)據(jù)

最終,這使我們進(jìn)入了遷移生產(chǎn)數(shù)據(jù)的過程,?;旧嫌袃煞N方法可以執(zhí)行此操作:

  • 關(guān)閉所有平臺(tái),并在所有數(shù)據(jù)遷移后使其重新聯(lián)機(jī),。
  • 在保持運(yùn)行的同時(shí)遷移數(shù)據(jù),。

選項(xiàng)1有一個(gè)明顯的缺點(diǎn):停機(jī)時(shí)間。另一方面,,方法2不需要停機(jī),,但是很難處理。例如,,在此設(shè)置中,,您在遷移數(shù)據(jù)時(shí)必須考慮添加的所有數(shù)據(jù),否則會(huì)丟失數(shù)據(jù),。

幸運(yùn)的是,,Olery具有相當(dāng)獨(dú)特的設(shè)置,因?yàn)閷?duì)數(shù)據(jù)庫的大多數(shù)寫入操作僅在相當(dāng)固定的時(shí)間間隔內(nèi)進(jìn)行,。確實(shí)更改頻率更高的數(shù)據(jù)(例如用戶和合同信息)是相當(dāng)少量的數(shù)據(jù),,這意味著與我們的評(píng)論數(shù)據(jù)相比,遷移所需的時(shí)間要少得多,。

這部分的基本流程是:

  • 遷移關(guān)鍵數(shù)據(jù),,例如用戶,合同,,基本上是我們以任何方式無法承受的所有數(shù)據(jù),。
  • 遷移不太重要的數(shù)據(jù)(我們可以重新刮擦,重新計(jì)算的數(shù)據(jù)等),。
  • 測(cè)試是否一切正常并在一組單獨(dú)的服務(wù)器上運(yùn)行,。
  • 將生產(chǎn)環(huán)境切換到這些新服務(wù)器。
  • 重新遷移步驟1的數(shù)據(jù),,確保在此期間創(chuàng)建的數(shù)據(jù)不會(huì)丟失,。

第2步花費(fèi)了迄今為止最長的時(shí)間,大約是24小時(shí),。另一方面,,遷移步驟1和5中提到的數(shù)據(jù)僅花費(fèi)了大約45分鐘,。

結(jié)論

自我們完成遷移以來已經(jīng)快一個(gè)月了,到目前為止,,我們感到非常滿意,。到目前為止,所產(chǎn)生的影響不過是積極的,,在各種情況下甚至導(dǎo)致我們應(yīng)用程序的性能大大提高,。例如,由于遷移,,我們的酒店評(píng)論數(shù)據(jù)API(在Sinatra上運(yùn)行)最終獲得了比以前更低的響應(yīng)時(shí)間:

「數(shù)據(jù)庫選型」拋棄MongoDB,,擁抱PostgreSQL,工作更輕松

遷移是在1月21日進(jìn)行的,,最大的高峰只是應(yīng)用程序執(zhí)行了硬重啟(導(dǎo)致該過程中的響應(yīng)時(shí)間稍慢),。 21日之后,平均響應(yīng)時(shí)間幾乎縮短了一半,。

我們看到性能大幅提高的另一種情況就是所謂的“審查持久性”,。 這個(gè)應(yīng)用程序(作為守護(hù)程序運(yùn)行)的目的很簡單:保存評(píng)論數(shù)據(jù)(評(píng)論,評(píng)論等級(jí)等),。 盡管我們最終對(duì)該應(yīng)用程序進(jìn)行了一些非常大的更改以進(jìn)行遷移,,但結(jié)果卻非常有益:

「數(shù)據(jù)庫選型」拋棄MongoDB,擁抱PostgreSQL,,工作更輕松

我們的刮板(scrapers )也最終更快了:

「數(shù)據(jù)庫選型」拋棄MongoDB,,擁抱PostgreSQL,工作更輕松

區(qū)別并不像復(fù)審持久性那么大,,但是由于抓取工具僅使用數(shù)據(jù)庫來檢查是否存在復(fù)審(相對(duì)較快的操作),,因此這并不奇怪。

最后是計(jì)劃抓取過程的應(yīng)用程序(簡稱為“調(diào)度程序”):

「數(shù)據(jù)庫選型」拋棄MongoDB,,擁抱PostgreSQL,,工作更輕松

由于調(diào)度程序僅按特定的間隔運(yùn)行,因此該圖有些難以理解,,但是遷移后的平均處理時(shí)間明顯減少了,。

最后,我們對(duì)到目前為止的結(jié)果非常滿意,,我們當(dāng)然不會(huì)錯(cuò)過MongoDB,。 性能非常好,與之相比,,圍繞它的工具使其他數(shù)據(jù)庫顯得蒼白,,與MongoDB相比(尤其是對(duì)于非開發(fā)人員而言),查詢數(shù)據(jù)要輕松得多,。 盡管確實(shí)有一個(gè)服務(wù)(Olery Feedback)仍在使用MongoDB(盡管是一個(gè)單獨(dú)的相當(dāng)小的集群),,但我們打算將來也將其遷移到PostgreSQL,。

原文:https://developer./blog/goodbye-mongodb-hello-postgresql/

本文:http:///goodbye-mongodb-hello-postgresql

討論:請(qǐng)加入知識(shí)星球或者微信圈子【首席架構(gòu)師圈】

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多