著者 |テンセントスターコンピューティングチーム 1. 背景1.1 問題の起源近年、テンセント社内の自社開発クラウド プロジェクトの継続的な発展に伴い、クラウド ネイティブ方式を使用して独自のワークロードをホストする企業がますます増えており、コンテナ プラットフォームの規模も拡大し続けています。 Kubernetes をベースとしたクラウドネイティブ技術は、クラウドネイティブ分野の発展を大きく促進し、主要なコンテナプラットフォームの事実上の技術標準となっています。クラウド ネイティブのシナリオでは、リソースの共有を最大化するために、単一のホスト マシンで複数の異なるユーザーのコンピューティング タスクが実行されることがよくあります。ホスト マシンでリソースが適切に分離されていない場合、ビジネス負荷のピーク時に複数のコンテナーがリソースをめぐって激しく競合することが多く、プログラムのパフォーマンスが急激に低下する可能性があります。これは主に次の点で現れます。
したがって、クラウド ネイティブのシナリオでは、CPU 使用率が高い場合にコンテナ間で激しい競争が発生してパフォーマンスが低下することがないように、コンテナ リソースの割り当てに細かい制限を課す必要があります。 1.2 スケジューリングシナリオテンセントのスターコンピューティングプラットフォームは、同社のCPUとGPUのコンピューティングサービス全体を担い、膨大な量のマルチタイプのコンピューティングリソースを備えています。現在、プラットフォームが実行する主要なサービスのほとんどはオフライン シナリオです。ビジネスのコンピューティング能力の需要の高まりに応じて、低コストのリソースを安定的に提供し、可用性、サービス品質、およびスケジュール機能を継続的に改善し、より多くのビジネス シナリオをカバーします。しかし、Kubernetes のネイティブ スケジューリング機能とリソース バインディング機能は、複雑なコンピューティング シナリオのニーズを満たすことができなくなり、主に次の側面に反映される、より洗練されたリソース スケジューリングが緊急に必要とされています。 (1)Kubernetesネイティブスケジューラはノードリソースのトポロジ情報を認識できず、Podの生成に失敗するスケジューリング プロセス中、kube-scheduler はノードのリソース トポロジを認識しません。 kube-scheduler が Pod をノードにスケジュールした後、kubelet はノードのリソース トポロジ アフィニティ要件を満たすことができないと判断した場合、Pod の生成を拒否します。 Pod が外部制御ループ (デプロイメントなど) を通じてデプロイされると、Pod の作成 --> スケジューリング --> 実稼働の失敗が繰り返される無限ループが発生します。 (2)オフライン仮想マシンコロケーションソリューションによるノード上で実際に利用可能なCPUコア数の変化オンラインビジネスを運営するクラウドホストの平均利用率が低いという現実に直面し、アイドルリソースを最大限に活用するために、オフライン仮想マシンとオンライン仮想マシンを混在させて展開し、企業のオフラインコンピューティングのニーズを満たし、自社開発のクラウドリソースの平均利用率を向上させることができます。 Tencent Star Computing Power は、オフライン操作がオンライン業務に支障をきたさないことを保証しながら、自社開発のカーネル スケジューラ VMF のサポートに基づいて、マシン上のアイドル リソースを最大限に活用し、優先度の低いオフライン仮想マシンを生成することができます。 VMF の不公平なスケジューリング戦略により、オフライン VM の使用可能なコアの実際の数はオンライン VM の影響を受け、オンライン サービスの混雑状況によって変化します。そのため、cadvisor を介してオフライン ホストで kubelet によって収集される CPU コアの数は正確ではなく、スケジュール情報に偏差が生じます。 CVM アーキテクチャ (3)資源の効率的な利用には、より細かいスケジュールの粒度が必要であるkube-scheduler の役割は、Pod がスケジュールを完了するために適切なノードを選択することです。しかし、リソースをより効率的に使用したい場合、ネイティブ スケジューラの機能だけでは不十分です。スケジューリング時には、CPU コア、GPU トポロジ、ネットワーク トポロジなどを認識できるなど、スケジューラがよりきめ細かいスケジューリングを実行し、リソースの使用率をより合理的にできることを期待しています。 2. 予備知識2.1 cgroups の cpuset サブシステムcgroups は Linux カーネルによって提供されるメカニズムであり、単一のプロセスまたは複数のプロセスによって使用されるリソースを制限し、CPU やメモリなどのリソースを細かく制御できます。 Linux のコンテナ技術は、主に cgroup を通じてリソース制御を実装します。 cgroup では、cpuset サブシステムは cgroup 内のプロセスに独立した CPU およびメモリ ノードを割り当てることができます。 cpuset サブシステムの cpuset.cpus ファイルに CPU コア番号を書き込むか、cpuset.mems ファイルにメモリ NUMA 番号を書き込むことで、プロセスまたはプロセス グループが特定の CPU またはメモリのみを使用するように制限できます。 幸いなことに、コンテナのリソース制限内の cpuset サブシステムを手動で操作する必要はありません。コンテナランタイム (CRI) が提供するインターフェースに接続することで、コンテナのリソース制限を直接更新できます。 // ContainerManagerには、ContainerManager によって管理されるコンテナを操作するためのメソッドが含まれています。 2.2 NUMAアーキテクチャ非均一メモリ アクセス (NUMA) は、メモリ アクセス時間がプロセッサに対するメモリの位置によって決まる、マルチプロセッサ コンピュータ向けに設計されたメモリ アーキテクチャです。 NUMA では、プロセッサは非ローカル メモリ (別のプロセッサ上にあるメモリ、またはプロセッサ間で共有されるメモリ) よりも高速に独自のローカル メモリにアクセスできます。最新のマルチコア サーバーのほとんどは、ハードウェアのスケーラビリティを向上させるために NUMA アーキテクチャを使用しています。 numaアーキテクチャ 図からわかるように、各 NUMA ノードには独立した CPU コア、L3 キャッシュ、メモリがあり、NUMA ノードは相互接続されています。同じ NUMA ノード上の CPU は L3 キャッシュを共有でき、同じ NUMA ノード上のメモリへのアクセスは高速になりますが、NUMA ノード間のメモリへのアクセスは低速になります。したがって、プログラムのローカル パフォーマンスが完全に満たされるようにするには、同じ NUMA ノードの CPU コアを CPU を集中的に使用するアプリケーションに割り当てる必要があります。 2.3 Kubernetes スケジューリング フレームワークKubernetes は、v1.19 以降、スケジューリング フレームワークを公式かつ安定的にサポートしています。スケジューリング フレームワークは、Kubernetes スケジューラのプラグイン アーキテクチャです。既存のスケジューラに新しい「プラグイン」 API のセットが追加され、プラグインがスケジューラにコンパイルされます。これは、カスタム スケジューラにとって朗報です。 kube-scheduler のソース コードを変更せずにさまざまなスケジューリング プラグインを実装し、プラグイン コードと kube-scheduler を同じ実行可能ファイルにコンパイルすることで、カスタム拡張スケジューラを開発できます。この柔軟性により、さまざまなスケジューラ プラグインの開発と構成が容易になります。同時に、拡張スケジューラは、kube-scheduler のソースコードを変更することなく、依存関係をすばやく変更し、最新のコミュニティ バージョンに更新できます。 スケジューリング フレームワーク拡張 スケジューラの主な拡張ポイントを上の図に示します。拡張スケジューラは主に次の手順に重点を置いています。 (1)プレフィルターとフィルターこれら 2 つのプラグインは、Pod を実行できないノードを除外するために使用されます。いずれかのフィルター プラグインがノードを実行不可能としてマークした場合、そのノードは候補セットに入らず、後続のスケジューリング プロセスを続行します。 (2)PreScore、Score、NormalizeScoreこれら 3 つのプラグインは、フィルタリング段階を通過するノードをソートするために使用されます。スケジューラは各ノードに対して各スコアリング プラグインを呼び出し、最も高いスコアを持つノードが最終的なスケジューリング結果として選択されます。 (3)準備金と準備金解除このプラグインは、ポッドが実際にノードにバインドされる前にリソースを予約して、スケジュールの一貫性を確保するために使用されます。バインドが失敗した場合、予約されたリソースは Unreserve を通じて解放されます。 (4)バインドこのプラグインは、ポッドをノードにバインドするために使用されます。デフォルトの Bind プラグインは、スケジューリングを完了するためにノードの spec.nodeName のみを指定します。スケジューラを拡張し、その他のスケジューリング結果情報を追加する必要がある場合は、デフォルトの Bind プラグインを無効にして、カスタム Bind プラグインに置き換える必要があります。 3. 国内外の技術研究の現状現在、Kubernetes コミュニティと Volcano オープンソース コミュニティの両方に、トポロジ認識に関連するソリューションがあります。これらのソリューションにはいくつかの類似点がありますが、それぞれに制限があり、Star Computing の複雑なシナリオに対応できません。 3.1 Kubernetes コミュニティKubernetes コミュニティ スケジューリング インタレスト グループには、トポロジを考慮したスケジューリングのソリューションもあります。このソリューションは主に RedHat が主導しており、スケジューラ プラグインとノード機能検出の連携により、ノード トポロジを考慮したスケジューリング メソッドを実装します。コミュニティのアプローチでは、ノードが kubelet 構成要件を満たしながらスケジューリング ノードのスクリーニングとスコアリングを完了できるかどうかのみを考慮し、コア バインディングは実行しません。コアバインディング操作は、kubelet が完了するまでまだ残っています。関連する提案はここにあります。具体的な実施計画は以下のとおりです。
このソリューションには多くの問題があり、生産現場のニーズを満たすことができません。
3.2 火山コミュニティVolcano は、Kubernetes 上で高性能ワークロードを実行するためのコンテナ バッチ コンピューティング エンジンであり、CNCF インキュベーション プロジェクトです。 v1.4.0-Beta バージョンでは、NUMA 認識機能がリリースされました。 Kubernetes コミュニティ スケジューリング インタレスト グループの実装と同様に、実際のコア バインディングは個別に実装されておらず、kubelet の組み込み関数が直接使用されます。具体的な実施計画は以下のとおりです。
このソリューションの問題は、Kubernetes コミュニティのスケジューリング関心グループのものと似ています。具体的なコアの割り当ては kubelet によって異なります。 仕上げる。スケジューラは kubelet との一貫性を保つために最善を尽くしますが、リソースを予約できないため、不整合が依然として発生します。これは、同時実行性の高いシナリオでは特に顕著です。 3.3 まとめ国内外の現在の研究結果の分析に基づいて、オープンソースコミュニティは依然としてノードリソースのバインディングを kubelet に任せたいと考えており、スケジューラは kubelet との一貫性を確保しようとしています。これがコミュニティの方向性に沿ったものであることは理解できます。そのため、さまざまなソリューションの一般的な実装は完璧ではなく、Tencent Star Computing Power の要件を満たすことができません。複雑な生産環境では、より堅牢でスケーラブルなソリューションが必要です。そのため、各ソリューションのアーキテクチャ上の利点に基づいて、Tencent Star Computing Power の実際のシナリオに適合する、より強力なリソース調整型スケジューリング拡張ソリューションを検討することにしました。 4. 問題分析4.1 オフラインVMノードで実際に利用可能なCPUコア数の変化セクション 1.2 から、Tencent Star Computing がオフライン仮想マシンに基づくコロケーション ソリューションを使用していることがわかります。ノード上で使用可能な CPU コアの実際の数は、オンライン サービスのピーク値によって変化します。そのため、cadvisor を介してオフライン ホストで kubelet によって収集される CPU コアの数は正確ではなく、この値は固定値になります。したがって、オフライン リソースの場合、スケジューラは他の手段を通じてノードの実際の計算能力を取得する必要があります。 シーエム 現在、スケジューリングとコア バインディングはオフライン仮想マシンの実際の計算能力に到達できないため、タスクは深刻なオンライン干渉のある NUMA ノードにバインドされます。リソースの競争が非常に深刻で、タスクのパフォーマンスが低下します。 CVM-2 について 幸いなことに、物理マシン上のオフライン仮想マシンの各 NUMA ノードの実際の使用可能な CPU リソース比率を収集し、損失式を通じてオフライン仮想マシンの実際の計算能力を計算することができます。次のステップは、スケジューラがスケジューリング中に CPU トポロジと実際の計算能力を認識して割り当てを行えるようにすることです。 4.2 きめ細かなスケジュールにはより高い柔軟性が必要kubelet 独自の cpumanager を介してコアをバインドすると、ノード上のすべての Pod に常に影響します。 Pod が保証された QoS 条件を満たし、CPU 要求値が整数である限り、コア バインディングが実行されます。ただし、一部の Pod は高負荷タイプではないものの、CPU を独占するものもあります。このアプローチでは、トポロジ機能が有効になっているノードで優先度の高いリソースが簡単に浪費される可能性があります。 同時に、異なるリソース タイプのノードに対するトポロジ認識要件も異なります。たとえば、Xingchen Computing Power のリソース プールにも、断片化された仮想マシンが多数含まれています。これらのノードは、混合デプロイメント方式で生成されません。相対的に言えば、リソースは安定していますが、仕様は非常に小さいです(8 コア CVM、各 NUMA ノードには 4 つのコアがあるなど)。ほとんどのタスクには 4 つ以上のコアがあるため、このようなリソースは使用中に NUMA ノード全体に割り当てることができます。そうでない場合、一致させることは困難です。 したがって、トポロジを考慮したスケジューリングでは、さまざまなコア割り当てとトポロジを考慮したシナリオに適応するために、より高い柔軟性が求められます。 4.3 スケジューリングソリューションはよりスケーラブルである必要があるスケジューラは、トポロジ リソースを抽象化するときにスケーラビリティを考慮する必要があります。このソリューションでは、cgroups サブシステムに含まれるリソースだけでなく、さまざまな異種リソースのスケジュールなど、将来スケジュールする必要がある可能性のある拡張リソースも簡単に使用できます。 4.4 ハイパースレッディングによるCPU競合の回避CPU コアの競合が激しい場合、ハイパースレッディングによってパフォーマンスが低下する可能性があります。より理想的な割り当て方法は、1 つの論理コアを高負荷のアプリケーションに割り当て、別の論理コアをそれほど負荷の高くないアプリケーションに割り当てるか、ピーク時間と谷時間が反対の 2 つのアプリケーションを同じ物理コアに割り当てることです。同時に、CPU 競合の問題が発生する可能性の高い、同じ物理コアの 2 つの論理コアに同じアプリケーションを割り当てることを回避します。 5. 解決策上記の問題を完全に解決し、将来のスケーラビリティを考慮するために、Cassini という洗練されたスケジューリング ソリューションを設計しました。ソリューション全体は 3 つのコンポーネントと 1 つの CRD で構成されており、これらが連携してきめ細かいリソース スケジューリングのタスクを完了します。 注: カッシーニという名前は、土星の正確で精密な探査を行った有名な土星探査機カッシーニ・ホイヘンスに由来しています。この名前は、より正確なトポロジの検出とスケジュールを象徴するために使用されます。 5.1 全体的なアーキテクチャ解決 各モジュールの責任は次のとおりです。
全体的なスケジュール設定プロセスは次のとおりです。 (1)Cassini-workerが起動し、ノード上のトポロジリソース情報を収集する。 (2)ノードトポロジ情報を記録するために、NodeResourceTopology(NRT)タイプのCRリソースを作成または更新する。 (3)kubeletのcpu_manager_stateファイルを読み取り、既存のコンテナのkubeletコアバインディング結果をPodアノテーションにパッチします。 (4)cassini-masterは外部システムから取得した情報に基づいて対応するノードのNRTオブジェクトを更新する。 (5)拡張スケジューラscheduler-pluginsはPodのスケジューリングを実行します。 NRT オブジェクトに基づいてノードのトポロジ情報を認識し、Pod をスケジュールするときにトポロジ スケジューリング構造を Pod アノテーションに書き込みます。 (6)ノードkubeletはリッスンし、Podを起動する準備をします。 (7)ノードkubeletはコンテナランタイムインターフェースを呼び出してコンテナを起動します。 (8)cassini-workerは定期的にkubeletのポート10250にアクセスしてノード上のPodを一覧表示し、Podアノテーションからスケジューラのトポロジスケジューリング結果を取得します。 (9)cassini-workerはコンテナのランタイムインターフェースを呼び出してコンテナのコアバインディング結果を変更します。 全体として、cassini-worker はノード上のより詳細なリソース トポロジ情報を収集し、cassini-master は外部システムからノード リソースに関する追加情報を集中的に取得していることがわかります。スケジューラ プラグインはネイティブ スケジューラを拡張し、この追加情報を意思決定の基礎として使用してより洗練されたスケジューリングを実行し、結果を Pod アノテーションに書き込みます。最後に、cassini-worker は、スケジューラのリソース トポロジ スケジューリング結果を実装する責任を負うエグゼキュータの役割を引き受けます。 5.2 API設計NodeResourceTopology (NRT) は、ノード リソース トポロジ情報を抽象的に記述するために使用される Kubernetes CRD です。 コミュニティ スケジューリング インタレスト グループの設計。各ゾーンは抽象的なトポロジ領域を記述するために使用され、ZoneType はそのタイプを記述するために使用され、ResourceInfo はゾーン内のリソースの合計量を記述するために使用されます。 // Zone はリソース トポロジ ゾーンを表します( 例:ソケット、ノード、ダイ、 またはコア。 スケーラビリティを高めるために、各ゾーンに属性が追加され、ゾーンのカスタム属性が記述されることに注意してください。セクション 4.1 に示すように、オフライン仮想マシンの収集された実際のコンピューティング能力を Attributes フィールドに書き込み、各 NUMA ノードの実際の利用可能なコンピューティング能力を記述します。 5.3 スケジューラの設計プラグイン拡張スケジューラは、ネイティブ スケジューラを新しいプラグインで拡張します。これは、おおよそ次のようになります。
TopologyMatch プラグインにより、スケジューラはノード トポロジ情報を考慮し、スケジューリング中にトポロジ割り当てを実行できるようになり、Bind プラグインは結果を注釈に添付します。 ノード電源スケジューリングやその他の多次元スケジューリング用のスケジューラ プラグインもここに実装されていることは注目に値します。この記事ではそれについては説明しません。興味のある学生は私に個人的にメッセージを送って詳細を知ることができます。 5.4 マスターデザインcassini-master は、一部のノードでは収集できないリソース情報を外部から収集する中央制御コンポーネントです。オフライン仮想マシンの実際の利用可能なコンピューティング能力を物理的に収集し、cassini-master はその結果を対応するノードの NRT リソースに追加する役割を担います。このコンポーネントは、更新と拡張を容易にするために、統合リソース コレクションの機能を削除します。 5.5 ワーカーの設計cassini-worker は、各ノードで DaemonSet として実行される、より複雑なコンポーネントです。その責任は 2 つの部分に分かれています。 (1)ノード上のトポロジリソースを収集する。 (2)スケジューラのトポロジスケジューリング結果を実行する。 5.5.1 リソースの収集リソース トポロジの収集は、主に /sys/devices からシステム関連のハードウェア情報を収集し、NRT リソースで作成または更新することによって実現されます。このコンポーネントは、ノード kubelet の構成情報を監視して報告し、スケジューラがノードの kubelet のコア バインディング戦略、予約済みリソース、およびその他の情報を認識できるようにします。 ハードウェア情報はほとんど変更されないため、デフォルトでは長期間に一度収集され、更新されます。ただし、watch によって構成されるイベントはリアルタイムです。 kubelet が設定されると、すぐにそれが認識され、スケジューラがノード設定に基づいてさまざまな決定を下すことが容易になります。 5.5.2 トポロジスケジューリング結果の実行トポロジ スケジューリングの結果は、指定されたコンテナーのトポロジ割り当てを定期的に調整することによって実行されます。 (1)ポッド情報を取得する 各ノードの cassini-worker が kube-apiserver を監視して kube-apiserver に負荷をかけるのを防ぐために、cassini-worker は kubelet の 10250 ポートに定期的にアクセスしてノード上の Pod を一覧表示し、Pod アノテーションからスケジューラのトポロジ スケジューリング結果を取得する方法を使用します。同時に、ステータスから各コンテナの ID とステータスも取得できるため、トポロジ リソースの割り当て条件を作成できます。 (2)kubeletのCPUバインディング情報を記録する kubelet が CPU コア バインディングを有効にすると、拡張スケジューラはすべての TopologyMatch プラグインをスキップします。現時点では、Pod アノテーションにはトポロジ スケジューリングの結果は含まれません。 kubelet は Pod の CPU コア バインディングを完了すると、その結果を cpu_manager_state ファイルに記録します。 cassini-worker はファイルを読み取り、後続のスケジュールのために kubelet バインディング結果を Pod アノテーションにパッチします。 (3)CPUバインディング情報を記録する cpu_manager_state ファイルと、アノテーションから取得した Pod のトポロジ スケジューリング結果に従って、ノード上のすべての Pod のコア バインディング結果を記録する独自の cassini_cpu_manager_state ファイルを生成します。 (4)トポロジ割り当てを実行する cassini_cpu_manager_state ファイルに従って、コンテナ ランタイム インターフェイスを呼び出して、最終的なコンテナ コア バインディング作業を完了します。 6. 結果を最適化する上記の洗練されたスケジュール ソリューションに基づいて、いくつかのオンライン タスクをテストしました。以前、ユーザーから、一部のノードにスケジュールされた後にタスクの計算パフォーマンスが低下し、steal_time の増加によりタスクが頻繁に削除されることが報告されていました。これをトポロジー対応スケジューリング ソリューションに置き換えると、トポロジー対応スケジューリングは各 NUMA ノードの実際のオフライン コンピューティング能力 (offline_capacity) をきめ細かく認識できるため、タスクは適切な NUMA ノードにスケジュールされます。テストタスクのトレーニング速度は、元の速度の 3 倍まで上げることができ、これは優先度の高い CVM での業務に費やされる時間に匹敵します。トレーニング速度は比較的安定しており、リソースがより合理的に使用されます。 同時に、ネイティブ スケジューラを使用する場合、スケジューラはオフライン仮想マシンの実際の計算能力を認識できません。タスクがノードにスケジュールされると、ノードは その結果、steal_time が増加し、タスクがそのようなビジーなノードを許容できない場合、エビクターはポッドのエビクションを開始します。この場合、ネイティブ スケジューラを使用すると、繰り返しのエビクションと繰り返しのスケジューリングが発生し、SLA に大きな影響を与えることになります。この記事で説明したソリューションを使用すると、CPU プリエンプションの排除率を物理マシンのレベルまで大幅に削減できます。 7. まとめと展望本稿では、実際のビジネス上の問題点から始めて、まずテンセントスターコンピューティングパワーのビジネスシナリオと洗練されたスケジュール管理に関するさまざまな背景知識を簡単に紹介し、次に国内外の現在の研究状況を徹底的に調査し、さまざまな既存のソリューションには限界があることを明らかにします。最後に、問題点を分析した後、対応する解決策が提示されました。最適化後、リソースはより合理的に使用され、元のテストタスクのトレーニング速度は元の速度の 3 倍に増加し、CPU プリエンプション率は物理マシンのレベルまで大幅に削減されます。 将来的には、洗練されたスケジューリングにより、GPU 仮想化テクノロジによる GPU カード全体および断片化された GPU カードのスケジューリング、高性能ネットワーク アーキテクチャのスケジューリングのサポート、電源リソースのスケジューリング、過剰販売シナリオのサポート、カーネル スケジューリングとの連携など、より多くのシナリオがカバーされるようになります。 |
<<: プラットフォーム・アズ・コードの未来はKubernetes拡張機能
事業継続の重要性事業継続性とは、大規模な混乱や災害に対応するための戦略を策定することです。災害復旧 ...
TIOBE は 2014 年 4 月のプログラミング言語ランキングを発表しました。上位 3 位は C...
3月は養成校の入学者ピーク時期です。この時期にいかにうまく宣伝するかが、各養成ユニットに優秀な学生を...
Tencent Weibo には数億人の登録ユーザーがいます。ブログ プラットフォームと同様に、Te...
現在、中国には主流の検索エンジンは、Baidu、Google、Sogou、Soso、Youdao、i...
エッジ コンピューティングはクラウド コンピューティングの一種で、コンピューティング、ストレージ、ネ...
BandwagonHost をよく知らない人や、BandwagonHost サーバーについて知らない...
「ブラッシャー」は簡単に金儲けでき、オンラインストアの評判は薄れる南方日報の記者がオンライン「ブラッ...
調査によると、一部のウェブサイトでは、改訂状況の違いにより新旧ウェブサイトの混在問題が発生し、ウェブ...
スパイダーは最適化担当者にとっての「マスコット」のようなものであり、スパイダーを引き付けて Web ...
メガレイヤーはどうですか? Megalayer の香港データセンターはどうですか?メガレイヤー香港サ...
SecureCRT は、Windows で Linux サーバーに接続するためのソフトウェアです。こ...
Appleのおかげで、今日の製品やアプリケーションはますますユーザーエクスペリエンスに重点を置くよう...
1. プロジェクトの目的が明確でないSEO プロジェクトの初期段階では、SEO はマーケティング戦略...
「あなたのパンツはとても素敵ですね。どこで買ったのですか?Xiaomiの携帯を使っていますね!」この...