blogサービスの全文検索の話 - #groonga を囲む夕べ

  • View
    7.946

  • Download
    5

  • Category

    Internet

Preview:

Citation preview

blogサービスの全文検索の話

全文検索エンジンGroongaを囲む夕べ5長野雅広 (kazeburo)

Me•長野雅広 (Masahiro Nagano)•@kazeburo / github:kazeburo•Operations Engineer / Site Reliability

•LINE corp.• ISUCON 2013,2014 連覇

今日のお題

livedoor Blog•サービス開始11周年

•国内最大級

•blog開設数 570万件

•総記事数 3億件

•約100億PV/month

livedoor Blogを支える技術

•Reverse Proxy - Apache, Nginx

•Application - Perl, Go

•Cache - Memcached

•RDBMS - MySQL 4.0, 5.5

•Search Engine - Mroonga

どこで Mroonga が使われているか

blog内の記事検索blog横断の検索はありませんが、

3億件の記事が対象

Mroongaを採用した理由

競合• MySQLのLIKE検索

➡ 検索機能不足

➡ カテゴリやタグなどの絞り込みが面倒

• MySQL組み込みの全文検索

➡ 日本語非対応

• Elasticsearch

➡ Java/JVMの経験不足

➡ 大規模環境でのトラブルシューティングに不安

Mroonga

•MySQL! MySQL! MySQL!

➡レプリケーションやバックアップなどMySQLの知見が活かせる

•日本語で作者とコミュニケーション

検索サーバの構成

microservicesマイクロサービスっぽく作ってます

blogApp

blogApp

blogApp

cmsApp

cmsApp

cmsApp

記事表示 Service 記事編集 Service

SearchAPI

SearchAPI

IndexWorker

IndexWorker

Q4M MappingDB

検索 Serviceshard1 shard2 shard3

blogApp

blogApp

blogApp

cmsApp

cmsApp

cmsApp

記事表示 Service 記事編集 Service

SearchAPI

SearchAPI

IndexWorker

IndexWorker

Q4M MappingDB

検索 Service

記事追加

shard1 shard2 shard3

blogApp

blogApp

blogApp

cmsApp

cmsApp

cmsApp

記事表示 Service 記事編集 Service

SearchAPI

SearchAPI

IndexWorker

IndexWorker

Q4M MappingDB

検索 Service

記事追加

shard1 shard2 shard3

Queueing

blogApp

blogApp

blogApp

cmsApp

cmsApp

cmsApp

記事表示 Service 記事編集 Service

SearchAPI

SearchAPI

IndexWorker

IndexWorker

Q4M MappingDB

検索 Service

記事追加

shard1 shard2 shard3

Queueing

blog_idとshardのmapping

blogApp

blogApp

blogApp

cmsApp

cmsApp

cmsApp

記事表示 Service 記事編集 Service

SearchAPI

SearchAPI

IndexWorker

IndexWorker

Q4M MappingDB

検索 Service

記事追加

shard1 shard2 shard3

Queueing

blog_idとshardのmapping

INSERT!

blogApp

blogApp

blogApp

cmsApp

cmsApp

cmsApp

記事表示 Service 記事編集 Service

SearchAPI

SearchAPI

IndexWorker

IndexWorker

Q4M MappingDB

検索 Serviceshard1 shard2 shard3

blogApp

blogApp

blogApp

cmsApp

cmsApp

cmsApp

記事表示 Service 記事編集 Service

SearchAPI

SearchAPI

IndexWorker

IndexWorker

Q4M MappingDB

検索 Service

検索

shard1 shard2 shard3

blogApp

blogApp

blogApp

cmsApp

cmsApp

cmsApp

記事表示 Service 記事編集 Service

SearchAPI

SearchAPI

IndexWorker

IndexWorker

Q4M MappingDB

検索 Service

検索

shard1 shard2 shard3

blog_idとshardのmapping

blogApp

blogApp

blogApp

cmsApp

cmsApp

cmsApp

記事表示 Service 記事編集 Service

SearchAPI

SearchAPI

IndexWorker

IndexWorker

Q4M MappingDB

検索 Service

検索

shard1 shard2 shard3

blog_idとshardのmapping

SELECT

Mroonga サーバの構成

shard1 shard2 shard3

この中身

Shardの構成

master

slave slave

Shard N

Shardの構成

master

slave slave

Shard N

参照・更新は全てMaster

Slaveはバックアップ

ハードウェア

•Intel Xeon 6core/12thread * 2

•Memory 96GB

•PCI-E SSD

テーブルとスキーマ

スキーマCREATE TABLE article_index_0001 ( id bigint unsigned NOT NULL AUTO_INCREMENT, blog_id int unsigned NOT NULL, article_id int unsigned NOT NULL, status tinyint NOT NULL, public_terms mediumtext, private_terms mediumtext, article_datetime datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY unique_entry (blog_id,article_id), FULLTEXT KEY for_public (public_terms), FULLTEXT KEY for_cms (public_terms,private_terms)) ENGINE=mroonga;

storage mode

スキーマCREATE TABLE article_index_0001 ( id bigint unsigned NOT NULL AUTO_INCREMENT, blog_id int unsigned NOT NULL, article_id int unsigned NOT NULL, status tinyint NOT NULL, public_terms mediumtext, private_terms mediumtext, article_datetime datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY unique_entry (blog_id,article_id), FULLTEXT KEY for_public (public_terms), FULLTEXT KEY for_cms (public_terms,private_terms)) ENGINE=mroonga; x150storage mode

mysql>show tables;+--------------------+| Tables_in_hermes |+--------------------+| article_index_0001 || article_index_0002 || article_index_0003 || article_index_0004 || article_index_0005 || article_index_0006 || article_index_0007 |......| article_index_0142 || article_index_0143 || article_index_0144 || article_index_0145 || article_index_0146 || article_index_0147 || article_index_0148 || article_index_0149 || article_index_0150 |+--------------------+150 rows in set (0.00 sec)

Table 分散

0001 0002 0003 0004 0005 0006

0007 ... ... ... ... 0144

0145 0146 0147 0148 0149 0150

SearchAPI

IndexWorker

blog_idで分散

Table 分散

0001 0002 0003 0004 0005 0006

0007 ... ... ... ... 0144

0145 0146 0147 0148 0149 0150

SearchAPI

IndexWorker

blog_idで分散

(murmur_hash(blog_id) % 150) + 1

Table分散を行う理由

•Mroonga/Groongaの制限を超えるため

•「最大インデックスサイズ: 256GByte」

•並列性能の向上

•障害時の影響範囲を最小化

運用ノウハウ

Kernel Tuning$ cat /etc/sysctl.conf# NUMAを無効にvm.zone_reclaim_mode = 0

# 物理メモリ以上のメモリ確保を許可vm.overcommit_memory = 1

# mmapで確保できる最大マッピング数vm.max_map_count = 5000000

Linux Tuning (2)

# 透過的hugepageを切る$ echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled

my.cnf

[mysqld]table_open_cache = 多め!

MySQL 5.6ではデフォルト2000

その他の工夫

Splog/巨大記事対策•Mroongaにいれる1記事あたりの最大文字数の設定

➡Splog(spam + blog) の記事は大量のリンクを貼っていたり、自動生成した記事が多いため、1記事あたりの容量が増えがち

• ` ` やHTMLの終了タグの削除

参照クエリの並列数制限

並列度を上げると性能劣化

https://gist.github.com/kazeburo/9014939

0

37.5

75

112.5

150

1 2 3 4 5 6 7 8 16

参照クエリの並列度と処理時間

処理時間

並列度

http://redmine.groonga.org/issues/2335

GET_LOCKで並列度制限# table名でlock

mysql> SELECT GET_LOCK(“article_index_0099”,30);

# 検索

mysql> SELECT article_id FROM article_index_0099 \ WHERE blog_id=30 AND status=1 \ AND MATCH(public_terms) AGAINST(? IN BOOLEAN MODE) \ ORDER BY article_datetime DESC LIMIT 10 OFFSET 0;

# 終わったらlockを解放

mysql> SELECT RELEASE_LOCK(“article_index_0099”)

困っている事

更新集中時の負荷

•記事の更新が集中した場合にロードアベレージが上がりやすい

•記事更新にもGET_LOCKが必要?

たまに落ちる•masterだけじゃなくて参照が行われていないslaveもMySQLが落ちる

•落ちた時に一部のテーブルのindexが壊れるのか更新ができない状態になり、mysqldump && restoreが必要となる

まだ落ちるパターンが分かればバグレポートあげたい

以上です。

Recommended