偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

指尖上的大數(shù)據(jù) - IM消息處理優(yōu)化方案

大數(shù)據(jù)
消息從服務(wù)端推到客戶端,然后被分發(fā)到消息隊(duì)列,在消息隊(duì)列中經(jīng)過(guò)一番處理后,最終展示到頁(yè)面上。這張圖只是簡(jiǎn)單地描述了消息的處理流程,下面我們將分步驟說(shuō)明每個(gè)流程的設(shè)計(jì)和優(yōu)化。

在即時(shí)通訊領(lǐng)域,高并發(fā)消息處理是個(gè)很重要的話題。以京東客服系統(tǒng)舉例,每當(dāng)促銷時(shí),促銷店鋪的每個(gè)客服短時(shí)間內(nèi)可能接收到大量的用戶咨詢,如果不能及時(shí)快速地展示出用戶咨詢的信息,那么就無(wú)法對(duì)用戶的咨詢進(jìn)行快速的回復(fù),進(jìn)而可能會(huì)造成一定的用戶流失,這是商家和京東所不能接受的。處理這種高并發(fā)的場(chǎng)景時(shí),我們需要在消息查重、數(shù)據(jù)庫(kù)IO性能、內(nèi)存緩存、UI顯示等多維度進(jìn)行優(yōu)化。

[[424648]]

消息從服務(wù)端推到客戶端,然后被分發(fā)到消息隊(duì)列,在消息隊(duì)列中經(jīng)過(guò)一番處理后,最終展示到頁(yè)面上。這張圖只是簡(jiǎn)單地描述了消息的處理流程,下面我們將分步驟說(shuō)明每個(gè)流程的設(shè)計(jì)和優(yōu)化。

一、消息查重設(shè)計(jì)

客戶端在消息處理完(存入數(shù)據(jù)庫(kù))后會(huì)給服務(wù)端發(fā)送已收回執(zhí),當(dāng)服務(wù)端收到回執(zhí)后便不再重復(fù)給客戶端下發(fā)此消息,然而現(xiàn)實(shí)場(chǎng)景中如果我們處理的過(guò)慢或者網(wǎng)絡(luò)丟包,那服務(wù)端就會(huì)重復(fù)給客戶端發(fā)送該消息。既然我們無(wú)法避免重復(fù)消息,那查重流程就是我們首先要考慮的。

1.1**重復(fù)消息處理過(guò)濾機(jī)制**

通常情況消息處理隊(duì)列為一個(gè)串行隊(duì)列,一條消息進(jìn)入處理隊(duì)列后,會(huì)涉及到Message表、User表,Conversation表等多個(gè)表的讀寫,而我們知道數(shù)據(jù)庫(kù)的IO是非常耗時(shí)的。由于消息處理是個(gè)串行隊(duì)列,消息會(huì)按照時(shí)間接收順序在隊(duì)列中排隊(duì),如果消息處理的不夠快,那么服務(wù)端會(huì)因長(zhǎng)時(shí)間收不到客戶端回執(zhí)而重復(fù)下發(fā)該消息,極端情況下這會(huì)導(dǎo)致消息隊(duì)列中出現(xiàn)大量的重復(fù)消息,隊(duì)列壓力會(huì)越來(lái)越大,內(nèi)存暴增導(dǎo)致OOM。另外因?yàn)橹貜?fù)的消息導(dǎo)致隊(duì)列變長(zhǎng),新消息也不能及時(shí)被處理。解決這個(gè)問(wèn)題很簡(jiǎn)單,我們可以在消息進(jìn)入處理隊(duì)列前先進(jìn)行過(guò)濾,如果已經(jīng)有同樣的消息進(jìn)入處理隊(duì)列,就直接丟掉。具體設(shè)計(jì)如下圖:

1.2**本地緩存過(guò)濾機(jī)制**

為了避免相同消息重復(fù)處理的情況,消息在進(jìn)入處理隊(duì)列后,首先要判斷該消息是否已經(jīng)處理過(guò)(標(biāo)志就是緩存是否已經(jīng)同樣的消息),如果緩存有則不重復(fù)處理。其中緩存分為內(nèi)存緩存和數(shù)據(jù)庫(kù)兩部分,當(dāng)消息在持久化時(shí),同時(shí)在內(nèi)存和數(shù)據(jù)庫(kù)中進(jìn)行緩存。消息查重分為兩步,首先判斷內(nèi)存緩存中是否有,如果有則直接丟棄該消息,而如果沒(méi)有再通過(guò)sql來(lái)查詢數(shù)據(jù)庫(kù),如果第一步內(nèi)存緩存命中,就可以少一次數(shù)據(jù)庫(kù)的查詢。具體設(shè)計(jì)如下圖:

二、寫入性能優(yōu)化

2.1**消息批處理寫入**

消息處理完需要入庫(kù)持久化,在這里可以分為兩種方式,一種是消息處理完立即入庫(kù),一種是開(kāi)啟事務(wù)批量入庫(kù)。其中第一種比較好理解實(shí)現(xiàn)起來(lái)也比較簡(jiǎn)單,第二種我們?cè)谙⒎e攢到一定量或者一個(gè)時(shí)間段結(jié)束后批量入庫(kù)。SQLite的數(shù)據(jù)操作實(shí)質(zhì)上是對(duì)數(shù)據(jù)文件的IO操作,頻繁地插入數(shù)據(jù)會(huì)導(dǎo)致文件IO經(jīng)常開(kāi)閉,非常損耗性能。通過(guò)開(kāi)啟事務(wù)將數(shù)據(jù)先緩存在內(nèi)存中,當(dāng)提交事務(wù)時(shí)再把所有的更改更新到數(shù)據(jù)文件,此時(shí)數(shù)據(jù)文件的IO只需要開(kāi)閉一次,也避免了長(zhǎng)期占用文件IO所導(dǎo)致性能低下的問(wèn)題。

以下數(shù)據(jù)表記錄了在iPhone 6s設(shè)備上,這兩種方式不同數(shù)據(jù)量寫入數(shù)據(jù)庫(kù)消耗的時(shí)間:

通過(guò)上表,我們可以看到數(shù)據(jù)量越大,開(kāi)啟事務(wù)后性能提升就越明顯。那是不是在實(shí)踐中一定要開(kāi)啟事務(wù)呢?不一定。對(duì)于IM消息來(lái)說(shuō),大部分服務(wù)端都是一條一條下發(fā)給客戶端,并不存在多條消息同時(shí)到達(dá)客戶端的情況,如果我們想用到事務(wù)的特性,需要先將處理完的消息緩存到內(nèi)存中,定時(shí)或者定量進(jìn)行批處理入庫(kù),而這都需要額外的邏輯實(shí)現(xiàn),會(huì)增加代碼的復(fù)雜度,進(jìn)而增加維護(hù)成本。另外由于消息到達(dá)先后特性,最終的效果會(huì)因?yàn)榫W(wǎng)絡(luò)等狀況并沒(méi)有上面的數(shù)據(jù)那么好。大家可以根據(jù)自身的情況抉擇。

除了利用事務(wù)來(lái)提高寫入性能外,SQLite在3.7.0版本引入了WAL(Write-Ahead Log)模式,在特定情況下可以大幅提升寫入性能。

2.2**開(kāi)啟WAL模式**

“原子提交(atomic commit)”是SQLite一個(gè)重要特性,原子提交意味著單個(gè)事務(wù)的所有更改要么全部完成,要么全部不完成,不會(huì)出現(xiàn)單個(gè)事務(wù)內(nèi)的操作執(zhí)行到一半的情況。為了實(shí)現(xiàn)這個(gè)特性,SQLite需要臨時(shí)文件的輔助,比如rollback模式的journal文件;WAL模式的wal文件和shm文件。

SQLite默認(rèn)為rollback模式,我們可以通過(guò)修改配置更改為WAL模式。下面通過(guò)對(duì)兩種模式的事務(wù)提交流程分析,來(lái)看看WAL模式怎么提高寫性能的。

2.2.1ROLLBACK 模式

SQLite數(shù)據(jù)庫(kù)連接默認(rèn)為rollback模式(journal_mode = DELETE;)。 rollback模式工作原理大致為:寫操作進(jìn)行前進(jìn)行數(shù)據(jù)庫(kù)文件拷貝,然后對(duì)數(shù)據(jù)庫(kù)進(jìn)行寫操作。如果發(fā)生Crash或者Rollback則將日志中的原始內(nèi)容回滾到數(shù)據(jù)庫(kù)文件進(jìn)行恢復(fù)操作,否則在Commit完成時(shí)刪除日志文件。以下為rollback模式下寫入的重要的節(jié)點(diǎn):

  • 首先,在系統(tǒng)緩存中創(chuàng)建rollback journal文件,把需要修改的原始內(nèi)容保存到這個(gè)文件中,然后修改用戶空間的數(shù)據(jù)庫(kù);
  • 然后,將rollback journal文件頭和文件內(nèi)容通過(guò)兩次fsync()從系統(tǒng)緩存同步到磁盤中(這個(gè)步驟非常耗時(shí));
  • 下一步,先將修改后的數(shù)據(jù)同步到系統(tǒng)緩存,再同步到磁盤中;
  • 最后,刪除rollback journal文件;

以上只列舉了單個(gè)事務(wù)提交成功的流程,由于篇幅的原因,如提交失敗(設(shè)備斷電、系統(tǒng)崩潰等)rollback流程等細(xì)節(jié)內(nèi)容可以參考SQLite官方文檔,文檔很完善,強(qiáng)烈建議抽時(shí)間學(xué)習(xí)下。

2.2.2WAL**模式**

首先,我們看下官方文檔中對(duì)WAL模式的優(yōu)缺點(diǎn)描述:

優(yōu)點(diǎn)有:

  • 在大多數(shù)情況下,使用WAL模式速度更快;
  • WAL模式進(jìn)一步提升了數(shù)據(jù)庫(kù)的并發(fā)性,因?yàn)樽x不會(huì)阻塞寫,而寫也不會(huì)阻塞讀,讀和寫可以并發(fā)執(zhí)行;
  • 使用WAL模式,磁盤I/O操作更有秩序;
  • 使用WAL模式減少了fsync()操作次數(shù),因此不易受到系統(tǒng)上的fsync()系統(tǒng)調(diào)用(system call)中斷的影響;

缺點(diǎn)有:

  • WAL模式通常要求VFS支持共享內(nèi)存原語(yǔ)(shared-memoryprimitives);
  • 使用數(shù)據(jù)庫(kù)的所有進(jìn)程必須位于同一臺(tái)主機(jī)上, WAL無(wú)法在網(wǎng)絡(luò)文件系統(tǒng)上運(yùn)行;
  • 在讀取操作遠(yuǎn)多于寫入操作的應(yīng)用程序中,WAL可能比傳統(tǒng)的日志模式稍慢(可能慢1%或2%);
  • 每個(gè)數(shù)據(jù)庫(kù)文件都關(guān)聯(lián)了額外的.wal文件和.shm共享內(nèi)存文件;

**寫流程:**

WAL模式相較于rollback則采用了相反的做法。在進(jìn)行數(shù)據(jù)庫(kù)寫操作時(shí),將數(shù)據(jù)append到-wal日志文件中而原有數(shù)據(jù)庫(kù)內(nèi)容保存不變。如果事務(wù)失敗,-wal文件中的記錄會(huì)被忽略;如果事務(wù)成功,它將在隨后的某個(gè)時(shí)間被寫回到數(shù)據(jù)庫(kù)文件中,該步驟被稱為Checkpoint。WAL模式下寫數(shù)據(jù)庫(kù)操作比rollback模式下更為集中,而且該模式下顯著降低了磁盤同步fsync()的頻率,所以相對(duì)來(lái)說(shuō)寫性能更優(yōu)秀。我們可以使用以下代碼開(kāi)啟WAL模式:

  1. \1. PRAGMA journal_mode = WAL; 

**讀流程:**

在WAL模式下讀的時(shí)候,SQLite會(huì)先在WAL文件中搜索,找到最后一個(gè)寫入點(diǎn),記住它,并忽略在此之后的寫入點(diǎn)(這保證了讀寫和讀讀可以并發(fā)執(zhí)行)。隨后,它確定所要讀的數(shù)據(jù)的所在頁(yè)是否在-wal文件中,如果在,則讀-wal文件中的數(shù)據(jù),如果不在,則直接讀數(shù)據(jù)庫(kù)文件中的數(shù)據(jù)。為了避免每個(gè)讀取操作掃描整個(gè)-wal文件來(lái)尋找頁(yè)面(-wal文件可以增長(zhǎng)到幾兆字節(jié),具體取決于Checkpoint運(yùn)行的頻率,默認(rèn)情況下,當(dāng)-wal文件達(dá)到1000頁(yè)的閾值大小時(shí),SQLite會(huì)自動(dòng)執(zhí)行Checkpoint,我們也可以修改SQLITE_DEFAULT_WAL_AUTOCHECKPOINT來(lái)指定不同的閾值),SQLite提供了WAL-index文件來(lái)輔助頁(yè)面的查找。WAL-index文件使用了進(jìn)程間共享內(nèi)存的技術(shù),共享內(nèi)存是一個(gè)以.shm結(jié)尾并且和數(shù)據(jù)庫(kù)文件在同一個(gè)目錄下的文件,這個(gè)文件比較特別,內(nèi)存和文件存在映射關(guān)系,取到這個(gè)文件的地址后可以像內(nèi)存一樣對(duì)其讀寫,而一般文件需要調(diào)用read、write函數(shù)才能讀寫。WAL-index可以幫助讀取操作快速定位WAL文件中的頁(yè)面,極大地提高了讀取的性能。

**讀、寫測(cè)試:**

以下數(shù)據(jù)表記錄了在iPhone 6s設(shè)備上,這兩種模式不同數(shù)據(jù)量的寫和讀耗時(shí):

  • 寫入測(cè)試
  • 讀測(cè)試

從上面兩個(gè)表的測(cè)試數(shù)據(jù)可以看到WAL模式對(duì)讀性能影響有限,而寫入性能相對(duì)于rollback模式提升了3**~4倍左右**。iOS系統(tǒng)從5.1.1版本開(kāi)始SQLite版本便升級(jí)到3.7.7,而我們現(xiàn)在大部分應(yīng)用支持的最低版本為iOS8,所以我們可以直接開(kāi)啟WAL模式來(lái)提高寫入性能。

三、查詢性能優(yōu)化

3.1**對(duì)常用列查詢添加索引**

為了防止查詢數(shù)據(jù)時(shí)每次都遍歷整張表,常見(jiàn)的關(guān)系型數(shù)據(jù)庫(kù)均提供了索引,適當(dāng)?shù)靥砑铀饕梢源蟠筇岣邤?shù)據(jù)庫(kù)的讀性能。SQLite索引結(jié)構(gòu)為B+樹(shù),也被存在數(shù)據(jù)庫(kù)文件里,結(jié)構(gòu)如下圖(該圖來(lái)自維基百科) :

提升查找速度的關(guān)鍵在于盡可能減少磁盤I/O,那么可以知道,每個(gè)節(jié)點(diǎn)中的key個(gè)數(shù)越多,樹(shù)的高度就越小,需要I/O的次數(shù)也就越少。因?yàn)锽+樹(shù)的非葉節(jié)點(diǎn)中不存儲(chǔ)data,所以可以存儲(chǔ)更多的key。很多存儲(chǔ)引擎在B+樹(shù)的基礎(chǔ)上進(jìn)行了優(yōu)化,添加了指向相鄰葉節(jié)點(diǎn)的指針,形成了帶有順序訪問(wèn)指針的B+樹(shù),這樣做可以提高區(qū)間查找的效率,只要找到第一個(gè)值那么就可以順序的查找后面的值。

3.1.1**幾種索引方式**

SQLite主要有以下四種索引方式:

  • 普通索引(只基于表的一個(gè)列創(chuàng)建的索引)
  • 唯一索引(除了普通索引的特性,索引列重復(fù)的數(shù)據(jù)不允許插入到表中)
  • 隱式索引(數(shù)據(jù)庫(kù)隱式為主鍵創(chuàng)建的唯一索引)
  • 組合索引(基于一個(gè)表的兩個(gè)或多個(gè)列創(chuàng)建的索引)

這里重點(diǎn)說(shuō)下組合索引,例如為table_name表創(chuàng)建了col1,col2,col3組合索引:

  1. \1. ALTER TABLE 'table_name' ADD INDEXindex_name('col1','col2','col3'); 

組合索引遵循”最左前綴”原則,把最常用作為檢索或排序的列放在最左,依次遞減,上面的組合索引相當(dāng)于建立了col1,col1col2,col1col2col3三個(gè)索引,而col2或者col3是不能使用索引的,這里一定要注意查詢語(yǔ)句和索引的順序要一致,否則索引無(wú)法正常命中。

3.1.2**添加索引性能提升**

以下數(shù)據(jù)表記錄了在iPhone 6s設(shè)備上,不同數(shù)據(jù)量有無(wú)索引情況下的性能表現(xiàn):

從上面表來(lái)看,添加索引對(duì)數(shù)據(jù)庫(kù)的讀性能提升很大,尤其是當(dāng)本地?cái)?shù)據(jù)表越來(lái)越大,有索引與沒(méi)有索引讀性能對(duì)比是天壤地別。但是在使用索引時(shí)一定要要了解每種索引的適用、命中原則情況,不要一股腦的添加索引。首先,索引是需要額外的磁盤空間存儲(chǔ);其次,在insert/update數(shù)據(jù)時(shí)索引結(jié)構(gòu)可能會(huì)發(fā)生變化消耗一部分寫入性能;再次,不合理的查詢語(yǔ)句會(huì)命中不了索引。查詢優(yōu)化還是建議大家翻閱官方文檔。

3.2**增加內(nèi)存Cache層提升查詢性能**

雖然我們可以通過(guò)添加索引的方式,提升數(shù)據(jù)庫(kù)的查詢性能。但畢竟在系統(tǒng)磁盤緩存未命中時(shí)還是需要進(jìn)行磁盤IO,而我們知道磁盤IO是非常耗時(shí),所以減少對(duì)庫(kù)的操作對(duì)讀性能提升也很有幫助。為了實(shí)現(xiàn)這點(diǎn),我們可以在DB層上面增加內(nèi)存Cache層,在讀數(shù)據(jù)時(shí)優(yōu)先從內(nèi)存Cache層讀,如果命中便可以少一次讀庫(kù)操作。內(nèi)存緩存可以使用簡(jiǎn)單的key-value結(jié)構(gòu),key為主鍵(或者其他唯一鍵,這個(gè)鍵應(yīng)當(dāng)經(jīng)常被當(dāng)作查詢條件),下圖為增加內(nèi)存Cache層后的查詢和緩存邏輯:

四、消息**UI刷新設(shè)計(jì)**

當(dāng)消息處理完后,下一步需要把消息展示在UI上。如果每條消息處理完就立即刷新頁(yè)面,在普通低并發(fā)場(chǎng)景下沒(méi)有太大問(wèn)題,但是在高并發(fā)場(chǎng)景下就會(huì)造成短時(shí)間內(nèi)UI刷新次數(shù)過(guò)多,從而導(dǎo)致頁(yè)面卡頓,在這里我們可以通過(guò)兩種方式進(jìn)行優(yōu)化。

4.1**延遲刷新**

消息到達(dá)UI隊(duì)列時(shí),可以延遲特定時(shí)間(比如100ms)再刷新UI,每條消息都將UI刷新的時(shí)間延遲100ms刷新。為了防止UI刷新操作因新消息的到來(lái)而一直被延遲,可以設(shè)置延遲閾值(比如2s),當(dāng)達(dá)到延時(shí)閾值時(shí),直接提交刷新UI操作。

4.2**滑動(dòng)列表時(shí)不刷新UI**

當(dāng)用戶滑動(dòng)會(huì)話列表/會(huì)話頁(yè)消息列表時(shí),列表不刷新,等到列表停止滑動(dòng)時(shí)再刷新,這樣可以保證列表的滑動(dòng)流暢度。iOS實(shí)現(xiàn)起來(lái)很方便,只要把Timer加到NSDefaultRunLoopMode就可以了。下圖為具體的實(shí)現(xiàn)邏輯:

五、最終完整的設(shè)計(jì)

我們通過(guò)上面幾點(diǎn),將消息處理的每個(gè)步驟的優(yōu)化點(diǎn)一一做了說(shuō)明,下圖詳細(xì)地展示了消息從接收到展示的完整處理流程:

六、最后

我們通過(guò)消息查重設(shè)計(jì)、寫入性能優(yōu)化、查詢性能優(yōu)化、消息UI刷新設(shè)計(jì)四個(gè)維度,分別介紹了高并發(fā)消息處理的優(yōu)化邏輯。希望通過(guò)此文章,可以給你在設(shè)計(jì)客戶端高并發(fā)消息處理方案時(shí)提供一種新的思路。

 

責(zé)任編輯:未麗燕 來(lái)源: 京東零售云
相關(guān)推薦

2022-12-30 15:29:35

數(shù)據(jù)分析工具Pandas

2024-07-01 08:18:14

2014-04-09 13:18:12

移動(dòng)互聯(lián)技術(shù)商業(yè)銀行

2012-06-25 15:16:06

搜索

2019-10-12 05:17:11

物聯(lián)網(wǎng)大數(shù)據(jù)IOT

2012-08-01 16:43:40

歐朋瀏覽器

2019-02-21 15:34:08

數(shù)據(jù)分析師大數(shù)據(jù)可視化

2011-12-24 14:16:42

惠普IT績(jī)效管理信息優(yōu)化

2024-10-10 10:07:07

2016-12-07 15:25:55

2023-08-22 08:01:42

SpringBatch事務(wù)管理

2017-07-21 14:22:17

大數(shù)據(jù)大數(shù)據(jù)平臺(tái)數(shù)據(jù)處理

2016-01-15 18:45:24

IM即時(shí)通訊云服務(wù)

2022-03-08 13:14:32

數(shù)據(jù)湖大數(shù)據(jù)

2017-06-23 21:32:16

MySQL大數(shù)據(jù)優(yōu)化

2013-04-18 10:04:02

大數(shù)據(jù)方案Hadoop

2024-06-27 08:00:17

2012-06-06 10:38:23

惠普信息優(yōu)化大數(shù)據(jù)

2023-11-29 13:56:00

數(shù)據(jù)技巧

2013-10-18 15:27:30

微軟大數(shù)據(jù)微軟
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)