1. 程式人生 > >基於Sphinx+MySQL的千萬級資料全文檢索(搜尋引擎)架構設計

基於Sphinx+MySQL的千萬級資料全文檢索(搜尋引擎)架構設計

[文章作者:張宴 本文版本:v1.0 最後修改:2008.07.27 轉載請註明原文連結:http://blog.s135.com/post/360/]

  前言:本文闡述的是一款經過生產環境檢驗的千萬級資料全文檢索(搜尋引擎)架構。本文只列出前幾章的內容節選,不提供全文內容。

  在DELL PowerEdge 6850伺服器(四顆64 位Inter Xeon MP 7110N處理器 / 8GB記憶體)、RedHat AS4 Linux作業系統、MySQL 5.1.26、MyISAM儲存引擎、key_buffer=1024M環境下實測,單表1000萬條記錄的資料量(這張MySQL表擁有int、datetime、varchar、text等型別的10多個欄位,只有主鍵,無其它索引),用主鍵(PRIMARY KEY)作為WHERE條件進行SQL查詢,速度非常之快,只耗費0.01秒。

  出自俄羅斯的開源全文搜尋引擎軟體

Sphinx,單一索引最大可包含1億條記錄,在1千萬條記錄情況下的查詢速度為0.x秒(毫秒級)。Sphinx建立索引的速度為:建立100萬條記錄的索引只需3~4分鐘,建立1000萬條記錄的索引可以在50分鐘內完成,而只包含最新10萬條記錄的增量索引,重建一次只需幾十秒。

  基於以上幾點,我設計出了這套搜尋引擎架構。在生產環境運行了一週,效果非常不錯。有時間我會專為配合Sphinx搜尋引擎,開發一個邏輯簡單、速度快、佔用記憶體低、非表鎖的MySQL儲存引擎外掛,用來代替MyISAM引擎,以解決MyISAM儲存引擎在頻繁更新操作時的鎖表延遲問題。另外,分散式搜尋技術上已無任何問題。


  一、搜尋引擎架構設計:
  1、搜尋引擎架構圖:


  點選在新視窗中瀏覽此圖片

  2、搜尋引擎架構設計思路:
  (1)、呼叫方式最簡化:
  儘量方便前端Web工程師,只需要一條簡單的SQL語句“SELECT ... FROM myisam_table JOIN sphinx_table ON (sphinx_table.sphinx_id=myisam_table.id) WHERE query='...';”即可實現高效搜尋。

  (2)、建立索引、查詢速度快:
  ①、Sphinx Search 是由俄羅斯人Andrew Aksyonoff 開發的高效能全文搜尋軟體包,在GPL與商業協議雙許可協議下發行。
  Sphinx的特徵:
  •Sphinx支援高速建立索引(可達10MB/秒,而Lucene建立索引的速度是1.8MB/秒)
  •高效能搜尋(在2-4 GB的文字上搜索,平均0.1秒內獲得結果)
  •高擴充套件性(實測最高可對100GB的文字建立索引,單一索引可包含1億條記錄)
  •支援分散式檢索
  •支援基於短語和基於統計的複合結果排序機制
  •支援任意數量的檔案欄位(數值屬性或全文檢索屬性)
  •支援不同的搜尋模式(“完全匹配”,“短語匹配”和“任一匹配”)
  •支援作為Mysql的儲存引擎

  ②、通過國外《High Performance MySQL》專家組的測試可以看出,根據主鍵進行查詢的類似“SELECT ... FROM ... WHERE id = ...”的SQL語句(其中id為PRIMARY KEY),每秒鐘能夠處理10000次以上的查詢,而普通的SELECT查詢每秒只能處理幾十次到幾百次:
  
點選在新視窗中瀏覽此圖片


  ③、Sphinx不負責文字欄位的儲存。假設將資料庫的id、date、title、body欄位,用sphinx建立搜尋索引。根據關鍵字、時間、類別、範圍等資訊查詢一下sphinx,sphinx只會將查詢結果的ID號等非文字資訊告訴我們。要顯示title、body等資訊,還需要根據此ID號去查詢MySQL資料庫,或者從Memcachedb等其他的儲存中取得。安裝SphinxSE作為MySQL的儲存引擎,將MySQL與Sphinx結合起來,是一種便捷的方法。
  建立一張Sphinx型別表,將MyISAM表的主鍵ID和Sphinx表的ID作一個JOIN聯合查詢。這樣,對於MyISAM表來所,只相當於一個WHERE id=...的主鍵查詢,WHERE後的條件都交給Sphinx去處理,可以充分發揮兩者的優勢,實現高速搜尋查詢。

  (3)、按服務型別進行分離:
  為了保證資料的一致性,我在配置Sphinx讀取索引源的MySQL資料庫時,進行了鎖表。Sphinx讀取索引源的過程會耗費一定時間,由於MyISAM儲存引擎的讀鎖和寫鎖是互斥的,為了避免寫操作被長時間阻塞,導致資料庫同步落後跟不上,我將提供“搜尋查詢服務”的和提供“索引源服務”的MySQL資料庫進行了分開。監聽3306埠的MySQL提供“搜尋查詢服務”,監聽3406埠的MySQL提供“索引源服務”。

  (4)、“主索引+增量索引”更新方式:
  一般網站的特徵:資訊釋出較為頻繁;剛釋出完的資訊被編輯、修改的可能性大;兩天以前的老帖變動性較小。
  基於這個特徵,我設計了Sphinx主索引和增量索引。對於前天17:00之前的記錄建立主索引,每天凌晨自動重建一次主索引;對於前天17:00之後到當前最新的記錄,間隔3分鐘自動重建一次增量索引。

  (5)、“Ext3檔案系統+tmpfs記憶體檔案系統”相結合:
  為了避免每3分鐘重建增量索引導致磁碟IO較重,從而引起系統負載上升,我將主索引檔案建立在磁碟,增量索引檔案建立在tmpfs記憶體檔案系統“/dev/shm/”內。“/dev/shm/”內的檔案全部駐留在記憶體中,讀寫速度非常快。但是,重啟伺服器會導致“/dev/shm/”內的檔案丟失,針對這個問題,我會在伺服器開機時自動建立“/dev/shm/”內目錄結構和Sphinx增量索引。

  (6)、中文分詞詞庫:
  我根據“自整理的中文分詞庫”+“搜狗拼音輸入法細胞詞庫”+“LibMMSeg高頻字型檔”+... 綜合整理成一份中文分詞詞庫,出於某些考慮暫不提供。你可以使用LibMMSeg自帶的中文分詞詞庫。


  二、MySQL+Sphinx+SphinxSE安裝步驟:
  1、安裝python支援(以下針對CentOS系統,其他Linux系統請使用相應的方法安裝)

yum install -y python python-devel



  2、編譯安裝LibMMSeg(LibMMSeg是為Sphinx全文搜尋引擎設計的中文分詞軟體包,其在GPL協議下發行的中文分詞法,採用Chih-Hao Tsai的MMSEG演算法。LibMMSeg在本文中用來生成中文分詞詞庫。)

  以下壓縮包“sphinx-0.9.8-rc2-chinese.zip”中包含mmseg-0.7.3.tar.gz、sphinx-0.9.8-rc2.tar.gz以及中文分詞補丁。

unzip sphinx-0.9.8-rc2-chinese.zip
tar zxvf mmseg-0.7.3.tar.gz
cd mmseg-0.7.3/
./configure
make
make install
cd ../



  3、編譯安裝MySQL 5.1.26-rc、Sphinx、SphinxSE儲存引擎

wget http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.26-rc.tar.gz/from/http://mirror.x10.com/mirror/mysql/
tar zxvf mysql-5.1.26-rc.tar.gz

tar zxvf sphinx-0.9.8-rc2.tar.gz
cd sphinx-0.9.8-rc2/
patch -p1 < ../sphinx-0.98rc2.zhcn-support.patch
patch -p1 < ../fix-crash-in-excerpts.patch
cp -rf mysqlse ../mysql-5.1.26-rc/storage/sphinx
cd ../

cd mysql-5.1.26-rc/
sh BUILD/autorun.sh
./configure --with-plugins=sphinx --prefix=/usr/local/mysql-search/ --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-big-tables --with-readline --with-ssl --with-embedded-server --enable-local-infile
make && make install
cd ../

cd sphinx-0.9.8-rc2/
CPPFLAGS=-I/usr/include/python2.4
LDFLAGS=-lpython2.4
./configure --prefix=/usr/local/sphinx --with-mysql=/usr/local/mysql-search
make
make install
cd ../

mv /usr/local/sphinx/etc/sphinx.conf /usr/local/sphinx/etc/sphinx.conf.old


  第二章第3節之後的正文內容不予公佈,全文的目錄如下(共24頁):

  點選在新視窗中瀏覽此圖片

  點選在新視窗中瀏覽此圖片

  點選在新視窗中瀏覽此圖片