本番アプリを開くと、アプリが停止しかけていることに気づきました。フロントエンドが応答しません。バックエンド API がタイムアウトになります。 MongoDB クエリは無期限に実行されているように見えます。あなたの受信箱にはユーザーからの苦情が溢れています。あなたのチームは集まって状況を優先順位付けしようとします。
そこにありましたか?はい、私もです。
私は上級フルスタック開発者ですが、単一ユーザーとしてのみ使用しているときや、問題の領域が単純なときは問題なく動作するアプリにはうんざりしていますが、実際のトラフィックや環境下では機能しなくなってしまいます。もう少し要求の厳しい作業です。
React、Node.js、MongoDB を使用してこれらの懸念事項にどのように対処したかを説明します。
また単純なチュートリアルを紹介するだけではなく、ストーリーを共有します。現実世界の問題に取り組む方法と、時間の試練や何が投げられても乗り越えられる、高速かつスケーラブルなアプリケーションを構築する方法についての物語。
1: React がボトルネックになったとき
私の職場では、React で開発した Web アプリのアップデートを公開したところです。私たちはユーザーが新機能を高く評価してくれると信じて自信に満ちていました。
しかし、苦情が寄せられるようになるまでに時間はかかりませんでした。アプリの読み込みが非常に遅く、遷移が途切れ、ユーザーはますます不満を募らせていました。新しい機能が有益であることはわかっていたにもかかわらず、誤ってパフォーマンスの問題を引き起こしてしまいました。私たちの調査により、問題が明らかになりました。アプリはすべてのコンポーネントを 1 つのパッケージにバンドルしており、ユーザーはアプリにアクセスするたびにすべてをダウンロードする必要がありました。
修正: 遅延読み込みと呼ばれる非常に便利な概念を実装しました。このアイデアは以前にも思いつきましたが、まさに私たちが必要としていたものでした。アプリの構造を完全に刷新し、必要なときに必要なコンポーネントのみをロードするようにしました。
このソリューションをどのように実装したかを簡単に説明します:
const Dashboard = React.lazy(() => import('./Dashboard')); const Profile = React.lazy(() => import('./Profile'));Loading...}>
結果: この変更の影響は驚くべきものでした。バンドルでは 30% もの大幅な縮小が見られ、ユーザーは初期読み込みが大幅に高速化されました。最も良かったのは、アプリの特定の部分がまだ読み込まれていることにユーザーが気づいていなかったことです。私たちはサスペンスを賢明に使用し、シンプルで邪魔にならない読み込みメッセージを表示しました。
2: React でステート管理という野獣を飼いならす
数か月が経った今、私たちの開発チームは本領を発揮し、多くの新機能をリリースしていました。しかし、成長に伴い、私たちは意図せずして、より複雑なアプリと呼ぶものを構築し始めました。 Redux はすぐに、単純な対話を促進するのに役立つというよりも、むしろ厄介な存在になりました。
そこで、より良い代替案を求めて時間をかけて概念図を作成しました。私はその結果を文書化し、そのアプローチがどのようなものであるかについて複数の知識共有会議を促進しました。私たちは最終的に、状態を管理するための提案ソリューションとして React Hooks (特に useReducer) を試すことをグループとして決定しました。最終的には、よりシンプルなコードと、多くの小規模な自己完結型の Redux の新しいバージョンで増加するオーバーヘッドによる膨大なランタイム フットプリントを減らしたかったからです。状態。
その後の変革はまさに革命的でした。私たちは、数十行の定型コードを簡潔で理解しやすいフック ロジックに置き換えていることに気づきました。この新しいアプローチをどのように実装したかを示す例を次に示します:
const initialState = { count: 0 }; function reducer(state, action) { switch (action.type) { case 'increment': return { count: state.count 1 }; case 'decrement': return { count: state.count - 1 }; default: throw new Error(); } } const CounterContext = React.createContext(); function CounterProvider({ children }) { const [state, dispatch] = useReducer(reducer, initialState); return ({children} ); }
結果: この移行の影響は深刻かつ広範囲に及びました。私たちのアプリケーションは大幅に予測可能になり、推論が容易になりました。コードベースはより無駄がなく、より直観的になったので、チームはより速いペースで反復できるようになりました。おそらく最も重要なことは、当社の若手開発者がコードベースをナビゲートして理解する能力が著しく向上したと報告したことです。その結果、双方にとって有利な状況が生まれました。保守するコードが減り、潰すべきバグも減り、開発チームは著しく幸せになり、生産性が向上しました。
3: バックエンドの戦場を征服する — Node.js API を最適化して最高のパフォーマンスを実現する
フロントエンドに多くの改善を導入することができましたが、直後にバックエンドで複数の問題が発生しました。 API のパフォーマンスがひどくなり、特にいくつかのエンドポイントのパフォーマンスが最悪になり始めました。これらのエンドポイントは、さまざまなサードパーティ サービスに対して一連の呼び出しを行いますが、ユーザーベースが拡大するにつれて、システムはこの負荷を処理できなくなりました。
何が間違っていたのかは非常に常識的でした。私たちはパラレルではありませんでした!つまり、各エンドポイントへのリクエストは順次処理されます。つまり、次の呼び出しはすべて、前の呼び出しが完了するまで待機します。この大規模 (数十万リクエスト) システムでは、悲惨な結果になることが判明しました。
解決策: これを修正するために、多くのコードを書き直し、Promise.all() の機能を利用して API リクエストを同時実行することにしました。つまり、複数のリクエストを開始しても、すべての呼び出しが終了するまで次のリクエストを開始するまで待つ必要はありません。
そのために、API 呼び出しを開始したり、完了するまで待機したり、別の呼び出しを作成したりすることはありません…
単純に Promise.all() を使用する代わりに、すべてが一度に起動され、はるかに高速になりました。
このソリューションをどのように実装したかを簡単に説明します:
const getUserData = async () => { const [profile, posts, comments] = await Promise.all([ fetch('/api/profile'), fetch('/api/posts'), fetch('/api/comments') ]); return { profile, posts, comments }; };
結果: この最適化の影響は即時かつ多大なものでした。応答時間の 50% の顕著な短縮が観察され、バックエンドは高負荷時の回復力が大幅に向上していることが実証されました。ユーザーはイライラする遅延を経験することがなくなり、サーバーのタイムアウト数が劇的に減少しました。この機能強化により、ユーザー エクスペリエンスが向上しただけでなく、システムがパフォーマンスを損なうことなく、より大量のリクエストを処理できるようになりました。
4: MongoDB クエスト — データ野獣を飼いならす
私たちのアプリケーションが注目を集め、ユーザーベースが桁違いに増加するにつれ、私たちは新たな障害に直面する必要がありました。それは、そのデータをどのように拡張するかということです。かつては応答性が高かった MongoDB インスタンスが、数百万のドキュメントを処理する必要があるときに動作を停止し始めました。以前はミリ秒単位で実行されていたクエリが完了するまでに数秒かかった、またはタイムアウトになりました。
私たちは数日かけて MongoDB のパフォーマンス分析ツールを調査し、インデックスのないクエリという大きな悪者を特定しました。最も一般的なクエリの一部 (ユーザー プロファイルのリクエストなど) は、強固なインデックスを使用できるコレクション全体をスキャンしていました。
解決策: 入手した情報をもとに、最もリクエストの多かったフィールドに複合インデックスを作成するだけで済み、これによりデータベース本体の検索時間を完全に修正できることがわかりました。ここでは、「ユーザー名」フィールドと「電子メール」フィールドに関してどのように行ったかを示します。
db.users.createIndex({ "username": 1, "email": 1 });
結果: この最適化の効果は驚くべきものでした。以前は実行に最大 2 秒かかっていたクエリが 200 ミリ秒未満で完了するようになり、パフォーマンスが 10 倍向上しました。私たちのデータベースは機敏な応答性を取り戻し、目立った速度低下を引き起こすことなく、大幅に大量のトラフィックを処理できるようになりました。
しかし、そこで終わりではありませんでした。当社の急速な成長軌道は今後も続く可能性が高いと認識し、長期的な拡張性を確保するために積極的な措置を講じました。データを複数のサーバーに分散するためにシャーディングを実装しました。この戦略的決定により、水平方向の拡張が可能になり、ユーザー ベースの拡大と並行してデータ処理能力も確実に向上しました。
5.マイクロサービスの採用 — スケーラビリティのパズルを解決する
ユーザー ベースが増加し続けるにつれて、インフラストラクチャを拡張する必要があるだけでなく、自信を持って拡張できるようにアプリケーションを進化させる必要があることがますます明らかになりました。モノリシック アーキテクチャは、小規模なチームだったときは適していましたが、時間が経つにつれて非常に煩雑になってきました。私たちは、思い切ってマイクロサービス アーキテクチャに向けた構築を開始する必要があることを認識していました。これは、どのエンジニアリング チームにとっても恐ろしい作業ですが、スケーラビリティと信頼性には大きな利点があります。
最大の問題の 1 つは、サービス間の通信でした。私たちのケースでは HTTP リクエストは実際には機能せず、膨大な量の操作が休むことなく応答を待っており、やることが多すぎると必要に応じてプログラムが強制終了されてしまうため、システムにもう 1 つのボトルネックが残りました。この時点で、RabbitMQ を使用するのが明白な答えであることがわかったので、あまり考えずにそれを適用しました。
このソリューションをどのように実装したかを簡単に説明します:
const amqp = require('amqplib/callback_api'); amqp.connect('amqp://localhost', (err, conn) => { conn.createChannel((err, ch) => { const queue = 'task_queue'; const msg = 'Hello World'; ch.assertQueue(queue, { durable: true }); ch.sendToQueue(queue, Buffer.from(msg), { persistent: true }); console.log(`Sent ${msg}`); }); });
結果: RabbitMQ を介して行われた通信と移行自体は、私たちの観点からは魔法のように見えました…そして数字がそれを裏付けました!!!私たちは、各サービスが独自に拡張できる疎結合マイクロサービスの幸運な所有者になりました。突然、具体的な DNS ゾーンで実際のトラフィックが急増しましたが、システムがダウンするという恐怖はありませんでした (サービス操作は常にカスケードされるため、どのサービス操作を要求しても同じであるため) が、残りの部分/操作が静かに手を挙げて「」と言うだけだったので、うまく機能しました。眠れますよ、愛しい人よ。メンテナンスも容易になり、問題が少なくなり、新しい機能やアップデートの追加がより速く、より確実に操作できるようになりました。
結論: 将来のイノベーションへの道筋を描く
このスリリングな旅の各ステップは教訓であり、フルスタック開発はコードを書くだけではないことを思い出させてくれました。フロントエンドの高速化や障害に耐えられるバックエンドの構築から、ユーザー ベースが爆発的に増加する間に拡張するデータベースの処理に至るまで、相互に関連する複雑な問題を理解し、解決することです。
2024 年後半以降に目を向けても、Web アプリケーションに対する需要の増加は止まらないでしょう。スケーラブルでパフォーマンスが最適化され、適切に設計されたアプリケーションの構築に集中し続ければ、今日のあらゆる問題を解決でき、将来的には他の課題を活用できる立場にあります。これらの実体験は、私のフルスタック開発への取り組み方に大きな影響を与えました。そして、これらの影響が今後も私たちの業界をどのように推進していくのかを見るのが待ちきれません!
しかし、あなたはどうですか?あなたも同様の障害に直面したことがありますか? あるいは、これらの問題を克服するための他の創造的な方法で幸運に恵まれたことはありますか?あなたのストーリーや洞察をぜひお聞きしたいです。コメント欄で知らせていただくか、私と連絡を取ってください!
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3