銀行振込の失敗から分散取引まで: 要約と考察

銀行振込の失敗から分散取引まで: 要約と考察

文章

この問題について考え始めた当初の目的は、ある時友人に送金したのですが、私のお金が差し引かれてしまい、友人はお金を受け取れなかったことでした。私は、銀行振込は強い一貫性を確保するためにトランザクションによって保証される必要があると常に考えており、分散トランザクションのさまざまな理論と方法を研究してまとめました。

不倫は非常に広い意味を持つ言葉であり、業界によって解釈が異なります。プログラマーにとって、トランザクションはトランザクションと同等であり、一連の連続した操作が論理的かつ完全な操作に結合されます。つまり、この一連の操作が実行される前と実行後に、システムは予測可能で一貫した状態である必要があります。したがって、この一連の操作はすべて正常に実行されるか、まったく実行できないかのいずれかになります。一部が成功し、一部が失敗した場合は、成功した部分をロールバックする必要があります。

[[207371]]

リレーショナルデータベーストランザクション

私のように、ほとんどの人は、リレーショナル データベース (MySQL、SQL Server、Oracle) について学習しているときに初めてトランザクションについて知りました。リレーショナル データベースでは、一連の操作が ACID 特性を満たす場合、その操作はトランザクションと呼ばれます。リレーショナル データベースの ACID 特性については、教科書やインターネット上に多くの情報が掲載されているため、ここでは簡単に紹介するだけにします。

  • A (アトミック): 原子性。トランザクションを構成するすべての操作は完了するか、まったく実行されません。一部の操作が成功し、他の操作が失敗することはあり得ません。
  • C (一貫性): 一貫性。トランザクションの実行前と実行後にデータベースの一貫性制約に違反しません。ここでの一貫性の意味については後で詳しく説明します
  • I (Isolation): 隔離。データベース内のトランザクションは通常、同時実行されます。分離とは、2 つの同時トランザクションの実行が互いに干渉せず、1 つのトランザクションが他のトランザクションの実行プロセスの中間状態を見ることができないことを意味します。
  • D (耐久性): トランザクションが完了すると、トランザクションによってデータに加えられた変更はデータベースに保持され、ロールバックされません。

送金の簡単な例を見てみましょう。ユーザー A がプレイヤー B に 100 元を送金します。これには 2 つの操作が含まれます。プレイヤー A のアカウントから 100 元が差し引かれ、プレイヤー B のアカウントに 100 元が追加されます。今すぐ

  1. ユーザーA.アカウント -= 100  
  2. ユーザーBアカウント += 100

原子性は理解しやすいです。両方の操作が成功するか、どちらも実行されません (より正確には、効果はどちらも実行されないことと同じです)。ユーザー B のお金が増えていないのに、ユーザー A のお金が減ることはあり得ません。ユーザーはこれを許可しません。ユーザー A のお金が減っていないのに、ユーザー B のお金が増えるということはさらに不可能です。銀行は絶対にそんなことはしません。

一貫性について話すときは誰もがそれを理解しますが、深く調べてみると、まだ完全には理解できていません。インターネット上の ACID における一貫性の説明は非常に曖昧です。全員が、一貫した状態であるべきだと言っています。では、一貫した状態とは何でしょうか?たとえば、送金操作では、A がお金を差し引き、B がお金を追加し、AB のお金の合計は一定になります。これは ACID の一貫性に属するのでしょうか?そうは思わない。 Wiki Transaction_processing と Wiki: ACID は次のように説明されています。

  • 一貫性: トランザクションは状態の正しい変換です。グループとして実行されるアクションは、状態に関連付けられた整合性制約のいずれにも違反しません。
  • 一貫性プロパティにより、どのトランザクションでもデータベースが有効な状態から別の有効な状態に移行されることが保証されます。データベースに書き込まれるデータは、制約、カスケード、トリガー、およびそれらの組み合わせを含む、定義されたすべてのルールに従って有効である必要があります。これは、アプリケーション プログラマが望むすべての点でトランザクションの正確性を保証するものではありません (これはアプリケーション レベルのコードの責任です)。単に、プログラミング エラーによって定義されたルールに違反することがないことを保証するだけです。

上記の太字の黒い部分は、ACID の一貫性が整合性制約に違反していないことを意味することを示しています。整合性には、エンティティ整合性 (主属性が空ではない)、参照整合性 (外部キーが元のテーブルに存在する必要がある)、およびユーザー定義の整合性が含まれます。ユーザー定義の整合性。列の値が NULL でないか、列の値が一意であるか、列の値がブール式 (性別は 2 つの値のみを持つことができる、年齢は特定の範囲の整数であるなどのチェック ステートメント) を満たしているかどうかなど。たとえば、age smallint CHECK (age >=0 AND age <= 120) などです。データベースは、年齢の値が [0, 120] の範囲内にあることを保証します。この範囲内にない場合、更新操作は失敗し、トランザクションも失敗します。さらに、MySQL のカスケードとトリガーは、ユーザー定義の整合性制約です。 MongoDB 3.2 では、ドキュメント検証は、ドキュメントを挿入または更新するときにチェックされるユーザー定義の整合性制約です。ただし、ユーザーは、データが制約を満たしていない場合の動作を決定するために validationAction を設定できます。デフォルトはエラーであり、データ書き込み操作が拒否されることを意味します。

したがって、このトランザクション操作の前後のユーザー A と B のアカウントの合計は一定です。これは、データベースによって保証される一貫性ではなく、アプリケーション レベルでの一貫性です。アプリケーション レベルでの一貫性は、実際には原子性によって保証されます。

孤立について語るのは簡単ですが、実際にはその背後にあるものは非常に複雑です。データベースの分離は、ロックまたはマルチバージョン制御に依存します。簡単に言うと、UserA.account の初期値が 500 の場合、最初の命令 (つまり、100 を減算する) が実行された後、トランザクションがコミットされていないと、他のトランザクションはこの中間結果 (UserA.account の値は 400) を読み取ることができません。これはダーティ リード (Drity Read) を回避するためのもので、対応する分離レベルは READ_COMMITTED です。 SQL 標準では、次の 4 つの分離レベルが定義されています。

  1. READ_UNCOMMITTED  
  2. READ_COMMITTED  
  3. 繰り返し読み取り 
  4. シリアル化可能 

トランザクションの同時実行によって発生するダーティリード、非反復リード、ファントムリードの問題を解決する

異なるデータベースまたはストレージ エンジンは、デフォルトで異なる分離レベルをサポートします。たとえば、InnoDB ストレージ エンジンはデフォルトで REPEATABLE_READ をサポートしますが、Mongodb は READ_UNCOMMITTED のみをサポートします。

永続性では、トランザクションの実行中に発生する可能性のあるさまざまな例外を考慮する必要があります。取引のプロセスは次のとおりです。

  • 取引を開始する
  • 一連の操作を実行する
  • すべてが正常に実行された場合、トランザクションをコミットして終了します。
  • いずれかの操作が失敗した場合、実行された操作はロールバックされ、トランザクションは終了します。
  • トランザクションの実行中に停電やシステムダウンなどの障害が発生した場合、ログ (REDO ログまたは UNDO ログ) とチェックポイントを使用して、トランザクションが完全に完了したことを確認します。

分散トランザクション

データの規模が大きくなると、単一のリレーショナル データベースの処理能力を超えてしまいます。このとき、リレーショナルデータの垂直分割やシャーディングが登場し、水平拡張(シャーディング)も当然サポートするNoSqlも登場します。さらに、大規模 Web サイトのサービス指向 (SOA) や、過去 2 年間で非常に人気が高まったマイクロサービスでは、サービスを分割して個別に展開することがよくあります。当然、独立したデータベースや異種データベースも使用されます。現時点では、ロックやログ記録など、トランザクションを保証するためにリレーショナル データベースで使用される手段は機能しません。もちろん、この記事ではデータベースだけでなく、分散ストレージ、メッセージ キュー、アトミック性と永続性を確保するために必要なロジックについても説明します。

分散トランザクションの最大の課題は CAP にあります。これは、「CAP 理論と MongoDB の一貫性と可用性に関する考察」という記事で詳しく説明されています。つまり、ネットワーク パーティション (P: Network Partition) が存在するため、ユーザーは一貫性 (C Consistency) と可用性 (A: Avaliable) の間でトレードオフを行う必要があります。強力な一貫性 (主にアプリケーション レベルでの強力な一貫性) を確保したい場合、ネットワークが分割されるとシステムは使用できなくなります。高可用性を確保したい場合は、最終的な一貫性を確保するために弱い一貫性のみを提供できます。以下で説明する分散トランザクションを実装するためのさまざまな方法とプロトコルでは、一貫性と可用性の間でトレードオフが必要になります。

2PC

分散トランザクションに関して、まず最初に思い浮かぶのは間違いなく 2 フェーズ コミット (2pc、2 フェーズ コミット プロトコル) です。 2pc は、非常に古典的な強力な一貫性を持つ集中型アトミック コミット プロトコルです。集中化とは、プロトコル内に、集中型コーディネーター ノード (コーディネーター) と N 個の参加者ノード (参加者、コホート) の 2 種類のノードがあることを意味します。

名前が示すように、2 フェーズ コミット プロトコルの各トランザクション送信は 2 つのフェーズに分かれています。

  • 最初のフェーズでは、コーディネーターはすべての参加者にトランザクションを送信できるかどうかを尋ね(参加者に投票を求め)、すべての参加者がコーディネーターに投票します。
  • 第 2 フェーズでは、コーディネーターはすべての参加者の投票結果に基づいてトランザクションをグローバルにコミットできるかどうかを決定し、すべての参加者に決定を実行するように通知します。 2 フェーズ コミット プロセスでは、参加者は投票を変更できません。 2 フェーズ コミット プロトコルがグローバルにコミットされるための前提は、すべての参加者がトランザクションをコミットすることに同意することです。参加者の 1 人がトランザクションの中止に投票した場合、トランザクションは中止される必要があります。

ウィキでは簡単なプロセスが説明されています:

上の図の下の行は、2 フェーズ コミット プロトコルもログに依存していることを示していることに注意してください。ストレージメディアに問題がない限り、2フェーズプロトコルは最終的に一貫した状態(成功またはロールバック)に到達できます。

次の図 (slideshare から) は、プロセス全体を詳細に説明しています。

Liu Jie の「分散原理入門」には非常に詳細なプロセス紹介があり、上の図と合わせて読むことができます。さらに、さまざまな異常な状況 (コーディネーター、参加者のクラッシュ、ネットワークのセグメント化によるタイムアウトなど) における 2 フェーズ プロトコルの動作状態についても説明します。ここでは 2PC の利点と欠点についてのみ説明します。

  • 利点: 強力な一貫性。ノードまたはネットワークが最終的に正常に戻る限り、プロトコルがスムーズに終了することが保証されます。一部のリレーショナルデータベース(Oracle)とフレームワークは直接サポートしています
  • 欠点: 2 フェーズ コミット プロトコルはフォールト トレランスが低いです。たとえば、ノードがクラッシュしたりタイムアウトしたりすると、プロセスのステータスを判別できず、継続的に再試行することしかできなくなります。 2 フェーズ コミット プロトコルはパフォーマンスが低く、メッセージのやり取りが多く、最も遅いノードの影響を受けます。

この記事では、2 フェーズ コミット プロトコルが分散システムに適さない理由について説明します。

システムの「水平」スケーリングの最大の敵。 2 フェーズ コミットに基づく分散トランザクションでは、トランザクションをコミットするときに複数のノード間で調整する必要があり、これによりトランザクションをコミットする時点が最大限に延期され、トランザクションの実行時間が客観的に長くなります。これにより、トランザクションが共有リソースにアクセスするときに競合やデッドロックが発生する可能性が高まります。データベース ノードが増加するにつれて、この傾向はますます深刻になり、データベース レベルでのシステムの水平スケーリングの「足かせ」になります。これが、多くのシャーディング システムが分散トランザクションを使用しない主な理由です。

それは本当にそうですね!

3PC

3 フェーズ コミット プロトコル (3pc Three-phase_commit_protocol) は、主に 2 フェーズ コミット プロトコルのブロッキング問題を解決するために使用されます。元の 2 段階から 3 段階に拡張され、タイムアウト メカニズムが追加されます。

3PC は異常な状況下での 2PC のブロッキング問題のみを解決しますが、1 回の送信で 6 つのメッセージが送信されるため、大きな遅延が発生します。プロセスの詳細な説明については、「分散トランザクション、2 フェーズ コミット プロトコル、および 3 フェーズ コミット プロトコルについて」の記事を参照してください。

TCC

TCC は Try、Commit、Cancel の略です。 Alipayのプロモーションにより中国では広く知られています。 TCC は、強力な一貫性を確保しながら、システムのスケーラビリティと可用性を最大化します。

完全なビジネスにはサブビジネスの集合が含まれていると想定します。 Try 操作は、すべてのサブビジネス チェックを完了し、必要なビジネス リソースを予約し、他のトランザクションからの分離を実現します。 Confirm は、Try フェーズで予約されたビジネス リソースを使用して実際にビジネスを実行し、Confirm 操作は再試行をサポートするためにべき等性を満たします。キャンセル操作は、Try フェーズで予約されたビジネス リソースを解放し、これによってもべき等性が満たされます。 「完全なトランザクションは、一連のマイクロトランザクションの Try 操作で構成されます。すべての Try 操作が成功した場合、マイクロトランザクション フレームワークは最終的に Confirmation を統合し、そうでない場合は Cancel を統合して、従来の 2 フェーズ コミット プロトコル (2PC) に似た強力な一貫性を実現します。」

2PC プロトコルと比較して、TCC には次の特徴があります。

  • ビジネス層はリソース層ではなくビジネスサービス層に位置し、アトミック性を保証する。
  • 別途の準備段階がないため、契約書の提出にかかるコストが削減されます。
  • Try操作はリソース操作と準備機能を組み合わせたものです
  • Try操作では、リソース全体をロックするのではなく、ビジネスリソースのロック粒度を柔軟に選択できるため、同時実行性が向上します。

もちろん、TCC には比較的高い開発コストが必要であり、各サブビジネスには応答性の高い確認およびキャンセル操作、つまり対応する補償ロジックを実装する必要があります。

メッセージベースの分散トランザクション

このタイプのトランザクション メカニズムは、分散トランザクションを複数のローカル トランザクションに分割します。ここでは、これらをマスター トランザクションとスレーブ トランザクションと呼びます。まず、マスター トランザクションがローカルでコミットされ、次にスレーブ トランザクションにメッセージを通じて通知されます。スレーブ トランザクションはメッセージから情報を取得し、それをローカルにコミットします。これは、最終的な一貫性のみを保証できる非同期トランザクション メカニズムであることがわかります。ただし、可用性は非常に高く、障害によってブロックされることはありません。さらに、メイントランザクションが最初にコミットされています。スレーブトランザクションをコミットできない場合、メイントランザクションをロールバックするのは依然として面倒です。したがって、このモードは、理論的には成功の確率が高いビジネス状況にのみ適用できます。つまり、スレーブ トランザクションのコミットの失敗は、故障によるものである可能性はありますが、論理エラーである可能性は低いです。

非同期メッセージに基づくトランザクション メカニズムには、ローカル メッセージ テーブルとトランザクション メッセージの 2 つの主なタイプがあります。両者の違いは、メイントランザクションをコミットしてメッセージを送信するという 2 つの操作のアトミック性をどのように確保するかです。

非同期メッセージングを使用して送金の例を実装する場合、操作は 4 つのステップに分かれます。ユーザー A がお金を差し引き、メッセージを送信し、ユーザー B がメッセージを受信し、ユーザー B がお金を差し引きます。最初の 2 つのステップでは、アトミック性を確保する必要があります。 A がお金の引き落としに成功したがメッセージを送信しなかった場合、ユーザー A は損失を被ります。メッセージは正常に送信されたが、お金が引き落とされなかった場合、ユーザー B は追加のお金を受け取りますが、銀行は絶対にこれを行いません。

ローカルメッセージテーブル

ローカル メッセージ テーブルに基づくソリューションは、メッセージをローカル データベースに書き込み、メイン トランザクションの原子性とローカル トランザクションを介したメッセージ書き込みを保証することを意味します。たとえば、銀行振込の場合、疑似コードは次のようになります。

  1. 始める トランザクション:更新 ユーザー アカウントをアカウント - 100設定しユーザー ID を'A'にします。    
  2. 入れる メッセージ(userId, amount, status) 'A' 、100、1)  
  3. 専念 取引 

次に、プル モードまたはプッシュ モードを通じて、ビジネスからのメッセージを取得して実行します。プッシュ モードの場合、トランザクションからのメッセージをサブスクライブするには、通常、永続機能を備えたメッセージ キューが使用されます。プル モードの場合は、トランザクションからメッセージを定期的にプルして実行します。

MongoDB の記述はローカル メッセージ テーブルと非常に似ています。 WriteConcern が w:1 の場合、更新操作は、oplog とプライマリに書き込まれている限り、クライアントに返すことができます。セカンダリは oplog を非同期的にプルし、実行をローカルに記録します。

取引メッセージ:

トランザクション メッセージングは​​、「トランザクション メッセージング」をサポートするメッセージ キューに依存します。基本的な考え方は、メッセージ ミドルウェアを使用して 2 フェーズ コミットを実装し、ローカル トランザクションとメッセージングを分散トランザクションに配置して、ローカル操作が成功し、外部メッセージングが成功するか、または両方が失敗するようにすることです。プロセスは次のとおりです。

  • メイン トランザクションは、予備メッセージをメッセージ キューに送信します。 ACK を受信すると、メイン トランザクションがローカルで実行されます。
  • 実行結果(成功または失敗)に基づいて、コミットまたはロールバックメッセージをメッセージキューに送信します。

詳細なプロセスを下の図に示します (画像ソースについては透かしを参照してください)。

ローカル メッセージ テーブル方式と比較すると、トランザクション メッセージはメッセージ ミドルウェアによってローカル トランザクションとメッセージの原子性が保証され、メッセージの保存にローカル データベースに依存しないことがわかります。ただし、「トランザクション メッセージ」を実装するメッセージ キューは比較的少なく、まだ十分に汎用的ではありません。

ローカル メッセージ テーブルであっても、トランザクション メッセージであっても、トランザクションが実行され、正確に 1 回だけ実行されるようにする必要があります。失敗した場合は再試行する必要がありますが、初回は再試行が不可能です。スレーブ トランザクションが最終的に失敗した場合、メイン ビジネスにロールバックするように通知する必要がありますか?ただし、この時点ではメイン トランザクションがコミットされているため、論理ロールバックを実現する唯一の方法は補償です。ただし、現在の時点はメイントランザクションの送信から一定の時間が経過しており、ロールバックが失敗する可能性もあります。したがって、最善の方法は、トランザクション ロジックが失敗しないようにすることです。障害が発生した場合は、ログに記録し、警告を発し、手動で介入します。

1個

「楽しさと利益のための分散システム」という記事で、1PC (1 フェーズ コミット) の概念を知りました。 2PC および 3PC と同等になります。 Wiki には公式エントリがなく、Google にも記事があまりありません。私の理解では、1PC は分散ストレージ システムのレプリケーション セット、つまりレプリケーション セット内の複数のノードのデータ送信に適用できます。一般的に言えば、これらのノードは同じデータを保存します。単一のノードが送信できる限り、理論的には他のノードも送信できるはずです。 「楽しさと利益のための分散システム」では、次のように説明されています。

  • コミットが永続的であるとみなされる前に 2 番目のフェーズを実施しておくと、ノードに障害が発生した場合にシステムが更新をロールバックできるため便利です。対照的に、プライマリ/バックアップ (「1PC」) では、一部のノードで失敗し、他のノードで成功した操作をロールバックする手順がないため、レプリカが分岐する可能性があります。

つまり、分散ストレージで広く使用されている集中型レプリケーション セット プロトコル Primary Secondary の場合、一部のノードに障害が発生し、一部のノードが成功したときにロールバック操作が行われないと、不整合が発生する可能性があります。ただし、これらの分散ストレージ システムは、これらの不整合が一時的なものであることを保証するために最善を尽くし、再試行やその他の手段を通じて最終的な一貫性を確保します。

1PC の利点は、パフォーマンスが非常に優れており、物理的な障害が発生した場合にのみ不整合が発生することです。

たとえば、MongoDB では、更新操作はプライマリ ノードと oplog コレクションに書き込まれます。セカンダリ ノードは、プライマリ ノードの oplog コレクションから操作ログを取得して実行します。これは非同期プロセスです。セカンダリノードが障害により oplog の実行に失敗しても、プライマリノードのデータはロールバックされません。また、「Learning Distributed Systems with Questions: Centralized Replication Sets」では、データの信頼性を向上させるために (極端なケースでのデータ ロールバックを回避するために)、WriteConcern を w:Majority に設定する (シャードはプライマリ、セカンダリ、およびアービターから構成される) ことも説明されています。この時点でセカンダリの 1 つに障害が発生すると、書き込み操作は成功しません。したがって、タイムアウト期間に達すると、クライアントにエラー メッセージが返されます。ただし、この時点ではデータはプライマリ ノードに保持されており、ロールバックされません。この時点でセカンダリ ノードが再起動されると、ログはプライマリ ノードから取得され、実行されます。したがって、クライアントから返されたエラー メッセージに WriteResult.writeConcernError が含まれている場合は、慎重に処理する必要があります。

分散ファイルシステム GFS および haystack では、セカンダリ ノードに障害が発生した場合、単純で大まかな再試行が採用され、最終的に正しいデータを読み取ることができるようにいくつかのメカニズム (チェックサム、オフセット) が使用されます。

考察と結論

多くの場合、分散トランザクションではアトミック性のみを確保する必要があります。これにより、アプリケーション レベルでの一貫性も確保されますが、ローカル トランザクションは分離性と永続性を確保する責任を負います。

アトミック性は、分散されておらず、単一のプロセスと単一のスレッドのみである場合でも考慮する必要があるものです。これは C++ の RAII であり、Python のステートメントと、さまざまな言語の try...finally... です。プロセス間の非同期通信の場合、言語レベルのメカニズムを通じてアトミック性を保証することは困難です。

分散分野では、ネットワークやマシンの障害により再試行が必要になることが多いため、べき等性が非常に重要です。

電子商取引やオンラインチケット購入などの多くのシナリオでは、まず高可用性を保証する必要があり、強力な一貫性が採用される可能性は低いです。したがって、「処理中...」という中間ステータスも表示されます。バックグラウンドは非同期で処理される可能性があります。 12306 でチケットを購入された方は、注文が成功してから直前にチケットが発行できるかどうかまでに長い時間がかかることをご存知でしょう。

著者のビジネス分野では、結果的一貫性で十分である限り、強い一貫性を伴うシナリオは存在しません。 2PC、TCC、ローカル メッセージ テーブル、トランザクション メッセージのいずれの場合でも、上記のすべての方法では、追加のフレームワークまたはコンポーネントの導入が必要です。そのため、ビジネス補償がよく使用されます。たとえば、2 つのプロセスが関与する操作では、アトミック性とプロセス間 RPC 通信を確保する必要があります。この場合、通常はプロセス A が最初に実行され、次に RPC がプロセス B のインターフェースを呼び出します。プロセス B の戻り結果に基づいて、ロールバック (補償) するかどうかが決定されます。ただし、非同期 RPC、マルチスレッド、または 2 つ以上のプロセスの直列接続が関係する場合は、補正が不可能になるか、または困難になる場合があります。この場合、エラーログのみが記録され、手動調査が通知されます。そのため、取引補償は一般的で単純なビジネスにのみ適しており、普遍的なフレームワークを形成することは困難であり、あまり実用的ではありません。

私は、銀行振込のようなシナリオは強い一貫性を持たなければならないと常に信じてきました。その後、私はそのようなことに遭遇しました。友達に送金しました。私の側では送金が成功したと表示されましたが、友人はお金を受け取っていませんでした。時間がかかると思っていましたが、24時間経ってもまだ届きませんでした。自分で振込票を再度確認したところ、相手の銀行口座を間違って記入していたことが判明しました。したがって、転送操作は確実に強一貫性があるわけではなく、その実行方法に関する具体的な詳細はインターネット上で見つけることができないことがわかります。さらに困ったことに、送金が失敗し、私のお金が差し引かれ、友人もお金を受け取れなかったのです。しかし、何の連絡も無く、お金も返ってきませんでした。銀行に問い合わせた後にようやく返金されました。これは本当にひどい経験ですが、銀行がボスなので、私たちにできることは何もありません。

<<:  Zookeeper に基づく分散ロック

>>:  ビッグデータを活用したいですか?パブリッククラウドまたはオンプレミス

推薦する

クラウドネイティブデータミドルプラットフォームの技術とトレンドの解説

データミドルプラットフォームの開発は、一般的に、データベース、データウェアハウス、ビッグデータプラッ...

国内外の主要検索エンジンと検索パラメータの収集

最近、BI を使ったデータ分析システムに取り組んでいたため、検索エンジンとその検索パラメータのリスト...

SAPはエクスペリエンス管理でインテリジェントエンタープライズの構築への道を切り開きます

SAP は、オーランドで開催された第 30 回 SAPPHIRE NOW® イベントで、消費者と企業...

ウェブサイトのコンテンツの更新方法とコンテンツライティングスキルについてお話しします

ウェブサイトの記事はウェブサイト存続の基盤です。ウェブサイトの記事を通じてのみ、ユーザーのニーズを満...

SEO に執着しないでください。あなたたちは SEO をあまりにも神話的に見せています。

私は、朱衛坤が素晴らしい人だと言うためにこの記事を書いているわけではありません。繰り返しますが、私は...

小紅書、お金を稼ぐためにどれだけ一生懸命働いているの?

最近、大手企業が小紅樹の「芝生化ビジネス」に目を付けている。分析によると、大手インターネット企業は昨...

Dynatrace がクラウド市場を制覇し、ソフトウェア インテリジェンスの新時代を創造

2018年7月18日、第5回Dynatrace Perform Greater Chinaユーザーカ...

SEOにおけるウェブサイト構造の大きな役割を分析する

ウェブサイトの構造は、その性質に応じて論理構造と物理構造に分けられ、ウェブサイト内のページ間の階層関...

3日間更新なし

何らかの理由で、元のサーバースポンサーがネットワークケーブルを抜いてしまい、ウェブサイトにアクセスで...

Pinduoduo はなぜ成功しているのでしょうか?

数日前、 Pinduoduo は2019 年通期業績報告書を発表しました。報告書によると、Pindu...

fastcomet: ハロウィン 20% オフ プロモーション、日本 KDDI 回線、仮想ホスト、VPS、サーバー

10 月 27 日から 11 月 2 日まで、Fastcomet はハロウィーン プロモーションを開...

有名なクラウドホスティング(VPS)業者VULTR:WeChat決済を正式にサポート

9 月 21 日のニュース: Vultr は、WeChat 決済方法に正式に接続したことを発表しまし...

再入荷のお知らせ: BandwagonHost 香港 VPS、香港トップ CN2 GIA ライン、1Gbps 超大容量帯域幅

BandwagonHost 香港 VPS は在庫切れです。中国本土のように高速 (登録済みのマシンと...

SEO外部要因の研究:SEOリソースの統合と最適化

みなさんこんにちは。私はMuzi Chengzhouです。 SEO に関しては、ウェブマスターが毎日...