こんにちは、財前です。
この記事では、React、ASP.NET Core、Node.jsなどを用いたWebサイトを作ってみて、思うところを書いていきます。
背景
自分は平日はIT企業で働いていますが、土日は個人でWebサイトを開発していることが多いです。
以前は、外国人向けの日本語学習用サイトをメインで作っていました。
こういうやつです。
日本語の単語クイズや、日本昔話から日本語を学ぶことができるサイトです。
こちらのサイトの開発の様子は、以下の過去記事にも詳細があるので、よろしければ見てみてください:
Reactを使った、海外向けのWebアプリケーションの個人開発の近況 >>
上記のサイトを作っていて、強く感じたことがありました。
それは、
コンテンツ作るのしんどい…
ということです。
単語クイズに関しては、単語を自分でDBに登録しなければいけません。
日本昔話から日本語を学ぶ教材も、一話一話、英語と日本語の文章を手動で投稿していく必要がありました。
(外部の翻訳APIを叩いて、できる限りの労力削減はできるようにしていますが… それでもめんどくさい…)
土日の限られた時間で個人開発をしている自分にとって、開発とは別の「コンテンツ作り」のところに時間を取られるのは、とても痛いものでした…
何より、自分の技術力向上に寄与しない作業に永遠と時間を取られることが、なんだかストレスでした…
そんな時、以下のブログ記事と出会いました。
【月700万PV/10年運用】僕が作った総PV6億の個人開発サービス【収益公開】
こちらは、ゆーじさんという、「2ちゃんねる勢いランキング」というサービスを個人で開発された方のブログです。
(勝手にリスペクトさせて頂いてます)
自分はエンジニアなのでプログラムや技術に興味はあるのですが、もともと、SEOにも興味を持っていました。
そんな中で、上記のブログを書いたゆーじさんが、技術を用いて、手動では不可能なSEOの手法を取っているのを見て、とても興味を持ちました。
上記の「2ちゃんねる勢いランキング」について自分なりに考えてみたところ、たぶん早い話が、超ロングテールSEOなのかと解釈しました…
記事を自動で生成して(たとえ1記事1記事の力は手動で書いたブログよりも弱くても)、膨大な数の記事から、マイナーなキーワードも含めて大量の流入を得ることで、PVを稼いでいるのだと、勝手に解釈しました…
(「site://URL」を使って記事数を調べさせて頂くと、超大量の記事がインデクスされているようだったので…)
ロングテールSEOというと、たぶんAmazonが一番有名な例だと思います。
(物理的なスペースの制限のある実店舗では実現できないような膨大な品ぞろえを実現して、大量のマイナー商品の売り上げから大きな利益を得るという…)
そこから、ブログを書く時などでも、「ロングテールを意識しましょう!」みたいなことが言われるようになったのかと思っていますが、
本来、本当のロングテールSEOは、ブログなどではなく、AmazonみたいなWebサービスでやるべきものですよね…
(Webサービスの方が機械的に大量のページを生成できるので…)
ゆーじさんのブログから刺激を受けた僕は、さっそく自分のサイトの開発を行うことにしました。。。
作ったサイト
そんなわけで、作ったサイトがこちらです。
うぃき忍者:
https://wiki-jp.lingual-ninja.com/
上述の「2ちゃんねる勢いランキング」には足元にも及びませんが、
一応動いてます…笑
一言で言うと、「Wikipediaの記事を紹介するWebサイト」です。
すごくシンプルなサイトなので、特筆して説明することもないぐらいです…
初期の開発期間は2日間です。
バッチ処理の開発に1日、サイトの開発に1日かけました。
(その後、大きく手を加える必要が出たことに関しては後述します…)
初期開発が2日で済んだのは、使用した技術が、普段から自分が仕事でも趣味でも使っているReactとASP.NET Core、Azure、そしてNode.js(バッチ処理)だったため、スムーズに開発ができたことと、
何より、前述の外国人向けの日本語学習サイトを開発した時にコツコツ作ったモジュールを、そのまま大量に流用しているので、相当な時間を短縮することができました。
Node.jsで作ったバッチ処理が、今もせっせとWikipediaから情報を取得して、コンテンツを作り続けてくれています。
記事数としては、2020年の8月5日現在で、1万記事ぐらいです。
(カテゴリページとかも入れると、3万ページぐらい)
カテゴリページの方が記事数よりも多いのは問題な気がするので、カテゴリページはnoindexに指定して、Googleの検索結果としてヒットしないようにしています。
2020年の6月半ばに作ってリリースしたので、もうすぐ2か月が経とうとしている状況です。
検索エンジンからのアクセスは、1日に100人ちょっとの状況が続いていますが、記事数が増加するのに伴って日々増加しているので、今後に期待したいです…!笑
大変だった点:急激なパフォーマンス低下
2日間で集中してサイトを完成させた当初は、達成感を感じていました。
アクセスが自動で伸びていく未来に、胸を躍らせておりました。
その後が大変だということも知らずに…
1か月近く経ってから訪れた課題、
それは、
急激なパフォーマンス低下
です…
原因は、DBのデータが大量になってきたことでした。
現在、このサイトのテーブルには、数百万~1千万ちょっとのレコードが入っています。
そういうテーブルに対しては、
select * from テーブル名;
を発行しただけで、
いつまでたってもレスポンスが返って来ない…
という状況になります。
そして、その時のDBの負荷を見ると、DBのコンピューターリソースの使用率が100%に張り付き、そのせいで、その他のテーブルへのSQLの実行速度にまで影響を与える…
という最悪の事態になります…
普通にselectしただけなのに…
そういうわけで、
SQLも色々工夫をして、応急処置をたくさん試みたのですが、
限界がある…
ということに気づき始めました…
さらに、一つ良くなかったこととしては、
テーブル設計時に、
「とりあえず正規化はしておいた方がいいでしょ」
と、安易に考え、
複数のテーブルに分割して設計したことです…
外部キーなどで結合できるように…
しかし、
頑張ってパフォーマンスチューニングをしているうちに、
テーブルの正規化って、しない方が良いんじゃないの…?
と、強く思うようになってきました…
正規化を行うと、どうしても複数のテーブルを結合するようなSQLを発行する必要が出てきますが、
そこがパフォーマンスの妨げになります。
もう既にデータを収集するバッチが日々稼働しており、既にDBに大量のデータが入ってしまっている手前、今更テーブルの構造を変えるのもなぁ…
というジレンマに苛まれました。
さらに、正規化や結合の件を抜きにしても、そもそも普通に1つのテーブルからselectするだけで、レスポンスが永遠に返って来ないのですから、対策にも限界があります。
where句で早めに絞り込むことでかなりパフォーマンスは上がるのですが、トップページ等、どうしてもテーブルのレコードをwhere句抜きで取って来たい場面もありました。
打開策:キャッシュ!
上記の問題に対して取った対策の中で最も有効だったのが、
アプリケーション側に、データをキャッシュする!
ということでした…
一応、上記のリンクからサイトを開いてもらうと、それなりのパフォーマンスでトップページなども表示されると思います。
なぜそれなりに動くようになったかというと、
実は、
サーバーにリクエストが来るたびに、毎回SQLを発行する
というのは、やめました。
パフォーマンスもそうですし、何よりも、大量のデータを持ったテーブルに対するSQL実行による、DBへの負荷が無視できない状況だったからです…
今は何とか動いても、今後どんどんテーブル内のレコードは増えていきます。
(まだリリースして2か月たってないですし…)
また、アクセスも伸びていっているので、リクエストの度にSQLを発行していたら、DBへの負荷がうなぎ登りに上昇していきます。
そのため、Webサービスのアプリケーションサーバー側で、少しずつ、Sleep処理などを挟みながら、負荷の少ないSQLを発行していき、
ジワジワと結果をキャッシュしていく方針に切り替えました。
僕はサーバーサイドでは、ASP.NET CoreというC#のフレームワークを使っているので、
SQLの実行結果は、C#のオブジェクトとしてサーバー側にキャッシュされていき、
HTTPリクエストを受け付けた際には、毎回DBに問い合わせることなく、プログラムで保持しているオブジェクトの情報をそのままレスポンスとして返します。
幸い、アプリケーションサーバー側のリソースには余裕があったので、
この方針が一番効果的でした…
爆速とは言いませんが、
使えるレベルのパフォーマンスにはなったのではないかと思います…
SEOするなら、SSR(サーバーサイドレンダリング)した方が良いんじゃない?
もうこれ以上サーバー側のリソースを酷使したくないので、勘弁してください…
以上、
「最近はこんなものを作ってたよ」
という報告でした。。。
うぃき忍者の今後の活躍に期待したいと思います…
最後まで読んで下さり、ありがとうございました!
コメント