Redis 分散ロックは SET コマンドを使用して実装できますか? CAP 理論は分散分野では常に存在してきました。 分散ロックのトリックはそれほど単純ではなく、インターネットで見られる分散ロック ソリューションには問題がある可能性があります。 「Code Brother」では、分散ロックが段階的に改善される仕組みと、高同時実行の運用環境で分散ロックを正しく使用する方法を段階的に説明します。 テキストを入力する前に、この質問について考えてみましょう。
分散ロックはいつ使用すればよいですか?マー兄さん、分散ロックがいつ必要になるかを説明する簡単な例を挙げてもらえますか? クリニックには医師が一人しかおらず、多くの患者が治療に来ます。 医師は一度に一人の患者にしか医療サービスを提供できません。 そうでなければ、医者は腎虚を患っている「小彩季」に薬を処方する準備をしているが、患者は足の臭いを発している「謝八歌」に交代し、薬は謝八歌に奪われてしまうだろう。 足の臭いのする人が腎不全の治療薬を持ち去った。 共有リソースを同時に読み書きする場合、データの正確性を確保するために、同時に 1 つのスレッドだけがアクセスするように制御する必要があります。 分散ロックは、JVM プロセス内の 1 つのスレッドだけが保護されたリソースに同時にアクセスできるように制御するために使用されます。 分散ロックの概要65 ブラザー:分散ロックはどのような特性を満たす必要がありますか? 相互排他: 一度にロックを保持できるのは 1 つのクライアントだけです。 デッドロックなし: ロックを取得したクライアントがクラッシュした場合でも、いつでもロックを取得できます。 フォールト トレランス: Redis ノードの過半数が稼働している限り、クライアントはロックを取得および解放できます。 コード兄弟、SETNX キー値コマンドを使用して「相互排他」機能を実装できます。 このコマンドは、SET if Not eXists の略語に由来しており、キーが存在しない場合はこのキーに値を設定し、それ以外の場合は何もしないことを意味します。 Redis の公式アドレスには次のように書かれています: コマンドは次を返します:
次のシナリオ: 一日中コードを入力して疲れているので、リラックスして肩と首をマッサージしたいです。 技術者 168 号は最も人気があり、誰もが彼に注文を付けたがるので、同時実行性が高く、分散ロック制御が必要です。 168 人の技術者と同時に予約を取ることができるのは 1 人の「顧客」だけです。 肖彩吉は168人の技術者の募集に合格しました:
謝覇は後から到着したが、彼の申請は却下された。
現在、お申し込みに成功したお客様は、168名の技術者による「リソース共有」による肩・首のリラクゼーションサービスをご利用いただけます。 楽しみが終わったら、後から来た人が 168 人の技術者のサービスを受けられるように、ロックを時間通りに解除する必要があります。 Xiao Caijiさん、ロックを解除する方法を教えていただけますか? とても簡単です。DEL を使用してキーを削除するだけです。
マー兄さん、「ドラゴン」を見たことがありますか?はい、ドラゴンに仕えられたからです。 シャオ・ツァイジ、物事はそんなに単純じゃないよ。 このソリューションには、ロックを解除できないという問題があります。この問題を引き起こすシナリオは次のとおりです。 クライアントが配置されているノードがクラッシュし、ロックを正しく解放できません。 ビジネスロジックが異常であるため、DEL 命令を実行できません。 このようにして、ロックは常に使用され、私の手の中にあります。私が死んだら、他のクライアントはロックを取得できなくなります。 タイムアウト設定コード兄弟、ロックが正常に取得されたときに「タイムアウト」を設定できます たとえば、マッサージ サービスを 60 分間設定したい場合は、キーをロックするときに 60 分の有効期限を設定できます。
これにより、時間経過後にロックが自動的に解除され、他のお客様は引き続き 168 人の技術者によるマッサージ サービスを受けることができます。 誰かがこのように書いたらひどいことになるでしょう。 「ロック」と「タイムアウトの設定」は 2 つのコマンドであり、アトミック操作ではありません。 最初の項目のみが実行され、2 番目の項目が実行される機会がない場合、「タイムアウト」設定は失敗し、ロックは解除されません。 ママ兄さん、どうしたらいいですか?この問題を解決するワンストップサービスが欲しいです。 Redis 2.6.X 以降、公式は SET コマンドのパラメータを拡張し、キーが存在しない場合に値を設定する、タイムアウト期間を設定する、アトミック性を満たすというセマンティクスを満たすようになりました。
これだけじゃ十分ではありません。自分たちが追加していないロックの解除も防止する必要があります。価値を活かすことができる。 続きを読む… 自分が追加していないロックを解除しましたワンストップサービスを安心してご利用いただけますか? いいえ、他の人のロックを解除する別のシナリオがあります。 クライアント 1 はロックを正常に取得し、30 秒のタイムアウトを設定します。 クライアント 1 の実行は、何らかの理由 (ネットワークの問題、FullGC の発生など) により非常に遅くなり、30 秒経っても実行が完了しませんでしたが、ロックが期限切れになり、「自動的に解放」されました。 クライアント 2 はロックを正常に申請します。 クライアント 1 は実行を完了すると、DEL ロック解除命令を実行し、その時点でクライアント 2 のロックが解除されます。 解決する必要がある重要な問題があります。それは、自分のロックしか解除できないことです。 追加したロックを削除するにはどうすればよいですか? DEL 命令を実行するときは、削除命令を実行する前に追加したロックであるかどうかを確認する方法を見つける必要があります。 ベルを結んだ人はそれを解かなければならない コード兄弟、ロックするときに、ロックするクライアントを表す値として「一意の識別子」を設定します。リソース名ランダム値 NX PX 30000 を設定する ロックを解除するとき、クライアントは自身の「一意の識別子」とロックの「識別子」を比較して、それらが等しいかどうかを確認します。一致した場合は削除されます。それ以外の場合は、ロックを解除する権利はありません。 疑似コードは次のとおりです。
これは GET + DEL 命令の組み合わせであり、アトミック性の問題が関係していると考えたことがありますか。 これを Lua スクリプトを通じて実装すると、判断と削除のプロセスがアトミック操作になります。
一意の値を value に設定して、ロックをロックしたクライアントを識別することが重要です。あるクライアントが別のクライアントのロックを削除する可能性があるため、DEL のみを使用することは安全ではありません。 上記のスクリプトを使用すると、各ロックはランダムな文字列で「署名」され、ロックを削除するクライアントの「署名」がロックの値と一致する場合にのみ削除されます。 公式ドキュメントにも次のように書かれています: https://redis.io/topics/distlock この解決策は比較的完璧であり、おそらく最も頻繁に使用される解決策です。 ロックタイムアウトを正しく設定するロックタイムアウトを計算するにはどうすればいいですか? 今回はランダムに書くことはできません。これは通常、テスト環境での複数のテストと複数ラウンドのストレス テストに基づいており、たとえば、平均実行時間は 200 ミリ秒と計算されます。 すると、ロック タイムアウト期間は平均実行時間の 3 ~ 5 倍に拡大されます。 なぜ拡大するのですか? ロック操作ロジックにネットワーク IO 操作、JVM FullGC などが含まれている場合、オンライン ネットワークが常にスムーズに動作するとは限らず、ネットワーク ジッタのためにバッファ時間を残す必要があるためです。 1時間など、もっと大きな値に設定したほうが安全ではないでしょうか? これにこだわらないでください。どれくらい大きいのが「大きい」のでしょうか? 設定時間が長すぎると、ダウンタイムの再起動が発生すると、分散ロック サービスのすべてのノードが 1 時間以内に使用できなくなります。 オペレーターが手動でロックを削除しますか? 運用とメンテナンスに本当に負担がかからない限りは。 完璧な解決策はあるのでしょうか?どのように時間を設定しても、適切ではないようです。 ロックを取得したスレッドにデーモン スレッドを開始させて、期限切れになりそうなロックを「延長」させることができます。 ロック時に有効期限が設定され、クライアントは「デーモン スレッド」を開始して、ロックの有効期限を定期的に検出します。 ロックの有効期限が近づいているがビジネス ロジックが実行されていない場合は、ロックが自動的に更新され、有効期限がリセットされます。 意味は通じますが、書けません。 慌てる必要はありません。これらすべてのタスクをカプセル化するライブラリがすでに存在します。それはレディソンと呼ばれています。 分散ロックを使用する場合、ロックの有効期限切れを回避するために「自動更新」ソリューションを採用します。このデーモン スレッドは一般に「ウォッチドッグ」スレッドと呼ばれます。 最後まで最適化すると、ソリューションはより「厳密」になり、対応するモデルは次のように抽象化されます。
この解決策は実のところ非常に完璧です。このステップまで記述できることは、すでに 90% のプログラマーの能力を超えています。 しかし、完璧さを追求するプログラマーにとって、これでは十分ではありません。
ロック解除コードの場所は重要です前回の分析に基づくと、すでに「比較的厳密な」分散ロックが存在します。 そこで、「Xie Ba Ge」はプロジェクトに分散ロックを適用するために次のコードを作成しました。疑似コードのロジックは次のとおりです。
これについて考えたことはありますか: ビジネス ロジックの実行中に例外がスローされると、プログラムはロックを解除するプロセスを実行できなくなります。 したがって、ロックを解除するコードは finally{} ブロックに配置する必要があります。 ロック位置も問題あり。 try メソッドの外側に配置すると、redisLock.lock() ロック例外が発生しても、実際の命令はサーバーに送信され実行されていても、クライアントが応答の読み取りでタイムアウトした場合、ロック解除コードを実行する機会がなくなります。 したがって、ロック解除ロジックが確実に実行されるように、 redisLock.lock() を try コード ブロックに記述する必要があります。 まとめると、正しいコードの場所は次のとおりです。
再入可能ロックの実装65 ブラザー: 再入可能ロックを実装するにはどうすればいいですか? スレッドがコードの一部を実行し、ロックを正常に取得して実行を続行すると、ロックされたコードに再び遭遇します。再入可能性により、スレッドは実行を継続できますが、再入可能性がない場合は、実行を継続する前にロックが解放されるのを待機し、再度ロックを正常に取得する必要があります。 再入可能性をコードで説明してください:
スレッド X がメソッド a でロックを取得した後、メソッド b の実行を継続すると仮定します。この時点で再入が不可能な場合、スレッドはロックが解放されるまで待機し、再度ロックを競合する必要があります。 ロックは明らかにスレッド X によって所有されていますが、ロックを取得する前に、スレッド X 自身がロックを解放するのを待つ必要があります。これはとても奇妙に見えます。自分を解放するよ〜 Redis ハッシュ再入可能ロックRedissonライブラリはRedisハッシュを通じて再入可能ロックを実装します スレッドがロックを取得した後、将来ロック メソッドに遭遇すると、ロックの数を直接 1 増やしてからメソッド ロジックを実行します。 ロックメソッドを終了した後、ロック回数が 1 減少します。ロック回数が 0 になると、ロックは完全に解除されます。 再入可能ロックの最大の特徴は、ロックが追加された回数を計算するカウント機能であることがわかります。 したがって、分散環境で再入可能ロックを実装する必要がある場合は、ロックの数もカウントする必要があります。 ロックロジックこれを実装するには、Redis ハッシュ構造を使用できます。キーはロックされた共有リソースを表し、ハッシュ構造のフィールドキーの値にはロックの数が格納されます。 KEYS1 = "lock"、ARGV "1000, uuid" と仮定して、Lua スクリプトを通じてアトミック性を実装します。
ロック コードは、まず Redis の exists コマンドを使用して、現在のロックが存在するかどうかを判断します。 ロックが存在しない場合は、hincrby を直接使用してキー uuid を持つロック ハッシュ テーブルを作成し、ハッシュ テーブル内のキー uuid を 0 に初期化してから、再度 1 を追加し、最後に有効期限を設定します。 現在のロックが存在する場合は、hexists を使用して、キー uuid が現在のロックに対応するハッシュ テーブルに存在するかどうかを判断します。存在する場合は、hincrby を使用して再度 1 を追加し、最後に有効期限を再度設定します。 最後に、上記の 2 つのロジックが一致しない場合は、直接戻ります。 ロジックをアンロック-- ハッシュセットの再入可能キーの値が0に等しいかどうかを判定します -- 0の場合は、再入可能キーが存在しないことを意味します
まず、hexists を使用して、Redis ハッシュ テーブルに特定のフィールドが含まれているかどうかを判断します。 ロックに対応するハッシュ テーブルが存在しない場合、またはキー uuid がハッシュ テーブルに存在しない場合は、直接 nil が返されます。 存在する場合、現在のロックはそれによって保持されていることを意味します。まず、hincrby を使用して再入回数を 1 減らし、計算後に再入回数を決定します。 0 以下の場合は、del を使用してロックを削除します。 ロック解除コードの実行方法はロックの場合と似ていますが、ロック解除の実行結果の戻り値の型が Long である点が異なります。ここでロックと同様にブール値が使用されていない理由は、ロック解除の Lua スクリプトでは、3 つの戻り値が次の意味を持つためです。
マスタースレーブアーキテクチャによって引き起こされる問題コード兄弟、分散ロックはここでは「完璧」ですよね?分散ロックにこれほど多くのトリックがあるとは思いませんでした。 まだ長い道のりが残っています。これまで分析したシナリオはすべて、「単一の」Redis インスタンスをロックすることによって発生する可能性のある問題であり、Redis マスター/スレーブ モードによって発生する問題は含まれていませんでした。 高可用性を確保するために、通常は「Cluster Cluster」または「Sentinel Cluster」モードを使用します。 どちらのモードも「マスタースレーブアーキテクチャデータ同期レプリケーション」に基づいてデータ同期を実装しており、Redis のマスタースレーブレプリケーションはデフォルトで非同期です。 以下の内容は公式ドキュメント https://redis.io/topics/distlock から引用したものです。 次のシナリオで何が起こるか想像してみましょう。 クライアント A はマスター ノードのロックを正常に取得します。 ロック取得情報がスレーブに同期される前にマスターがクラッシュしました。 スレーブが新しいマスターとして選出され、この時点ではロックされたデータを取得するクライアント A は存在しません。 クライアント B は、分散ロックによって定義された相互排他ルールに違反して、クライアント A が保持しているロックを正常に取得できます。 確率は極めて低いですが、このリスクの存在を認識しなければなりません。 Redisの作者はRedlockと呼ばれるソリューションを提案した。 分散ロックの標準を統一するために、Redis の作者は Redlock を作成しました。これは、分散ロックを実装するための公式の Redis ガイドと見なされています (https://redis.io/topics/distlock)。しかし、このレッドロックは海外の分散専門家からも批判されている。 なぜなら、完璧ではなく、「穴」があるからです。 レッドロックとはこれは赤い鍵ですか?
インスタントラーメンを食べ過ぎると、Redlock は、マスタースレーブ アーキテクチャでマスターとスレーブの切り替えが発生したときに、複数のクライアントが同じロックを保持する問題を解決するために提案されたアルゴリズムです。 公式ドキュメント (https://redis.io/topics/distlock) を読むことができます。以下は公式ドキュメントからの翻訳です。 Redlock を使用する場合、公式の推奨事項は、異なるマシンに 5 つの Redis マスター ノードをデプロイすることです。ノードは完全に独立しており、マスタースレーブレプリケーションは使用しません。フォールトトレランスのために複数のノードが使用されます。 クライアントがロックを取得するには、次の 5 つの手順があります。 クライアントは現在の時刻 T1 (ミリ秒レベル) を取得します。 同じキーと値の順序を使用して、N 個の Redis インスタンスからロックを取得しようとします。 各リクエストにはタイムアウト (ミリ秒単位) が設定されています。このタイムアウトはロックの有効期間よりもはるかに短くする必要があります。これにより、次のインスタンスにリクエストをすばやく送信できるようになります。 たとえば、ロックの自動解除時間が 10 秒の場合、リクエストのタイムアウトを 5 ~ 50 ミリ秒以内に設定することができ、クライアントが長時間ブロックされることを防ぐことができます。 クライアントは現在の時刻 T2 を取得し、ステップ 1 から T1 を減算して、ロックの取得にかかる時間を計算します (T3 = T2 - T1)。ロックは、クライアントがほとんどのインスタンス (N/2 + 1) でロックの取得に成功し、ロックの取得に使用された合計時間 T3 がロックの有効時間よりも短い場合にのみ成功したと見なされます。そうでない場合、ロックは失敗します。 ステップ 3 でロックが正常に取得されると、リソースを共有するためのビジネス ロジック操作が実行されます。キーの実際の有効時間は、有効時間からロックを取得するために使用された時間を引いた値 (手順 3 で計算された結果) に等しくなります。 何らかの理由でロックの取得に失敗した場合 (少なくとも N/2+1 個の Redis インスタンスでロックが取得されていないか、ロックの取得時間が有効時間を超えている場合)、クライアントはすべての Redis インスタンスのロックを解除する必要があります (一部の Redis インスタンスが正常にロックされていない場合でも)。 また、デプロイされるインスタンスの数は奇数である必要があります。多数決ルールを満たすには、インスタンスが 6 個ある場合、4 つのインスタンスが正常にロックを取得して初めて成功と見なされるため、奇数の方が合理的です。 物事はそんなに単純ではありません。 Redis の作者がこのソリューションを提案した後、業界の著名な分散システムの専門家から疑問が投げかけられました。 二人はまるで神々が戦うかのように、一つの問題に対して多くの結論を出すのに十分な証拠をもって、何度も議論を交わしました... この問題を提起した Martin Kleppmann のブログ投稿: https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html Redlock デザイナーの回答: http://antirez.com/news/101 レッドロックはい、いいえMartin Kleppmann 氏は、ロックの目的は共有リソースの読み取りと書き込みを保護することであり、分散ロックは「効率的」かつ「正確」であるべきだと考えています。 効率: 分散ロックは高パフォーマンスの要件を満たす必要があります。 Redlock アルゴリズムは、5 つのノードでロックを取得するロジックを実行する際のパフォーマンスが低く、コストと複雑さが増加します。 正確性: 分散ロックは、同時実行プロセスで共有データを同時に読み書きできるスレッドが 1 つだけになることを防ぐ必要があります。 これら 2 つの理由により、5 つの Redis インスタンスを実行し、ロックが成功するために大多数の要件を満たすかどうかを判断するという、Redlock のコストと複雑さを負担する必要がありません。 マスタースレーブアーキテクチャのクラッシュ回復が発生する可能性は極めて低いため、大きな問題にはなりません。スタンドアロン版を使用すれば十分です。Redlock は重すぎて不要です。 Martin は、Redlock がセキュリティ要件をまったく満たしておらず、ロック障害の問題が依然として残っていると考えています。 マーティンの結論Redlock は、良い面も悪い面もあります。つまり、設定効率の点では、Redlock は重すぎて不要であり、設定の正確さの点では、Redlock は十分に安全ではありません。 不合理なクロックの仮定: アルゴリズムは、システム クロックについて危険な仮定を行います (複数のノード マシンのクロックが一貫していると仮定します)。これらの仮定が満たされない場合、ロックは失敗します。 正確性を保証できない: Redlock はフェンシング トークンと同様のソリューションを提供できないため、正確性の問題を解決できません。正確性を保つには、Zookeeper などの「コンセンサス システム」を備えたソフトウェアを使用してください。 Redis作者Antirezの反論Redis の作者による反論記事には、3 つの重要なポイントがあります。 クロックの問題: Redlock では完全に一貫性のあるクロックは必要なく、ほぼ一貫性のあるクロックで十分です。 「エラー」は、ロックのリース期間を超えない限り許可されます。このクロック精度の要件はそれほど高くなく、実際の環境にも合致しています。 ネットワーク遅延とプロセス停止の問題: ロックを取得する前にクライアントがどのような時間のかかる問題に遭遇したとしても、Redlock はステップ 3 でそれを検出できます。 クライアントがロックを取得した後、NPCが発生し、RedlockとZookeeperは無力になります。 フェンシング トークンのメカニズムについて質問します。 次回はRedlockに関する討論でお会いしましょう。それでは、Redisson を使用して分散ロックを実装する実践的な部分に移りましょう。 Redisson 分散ロックSpringBoot スターター メソッドに基づいてスターターを追加します。
ただし、公式の推奨では springboot バージョンと一緒に redisson バージョンを使用することになっているため、ここでは springboot と redisson のバージョンに注意する必要があります。 Redisson と Spring Boot ライブラリの統合も Spring Data Redis モジュールに依存します。 「Code Brother」は SpringBoot 2.5.x バージョンを使用するため、redisson-spring-data-25 を追加する必要があります。
プロフィールを追加する
したがって、Spring コンテナでは次の Bean が使用可能になります。
失敗時の無限再試行
ロックが失敗すると、継続的に再試行されます。 Watch Dog 自動延長メカニズムがあり、デフォルトで 30 秒に設定され、30/3 = 10 秒ごとに 30 秒に延長されます。 タイムアウト再試行に失敗し、自動的に寿命が延長される
タイムアウト時に自動的にロックを解除する
タイムアウト再試行、自動ロック解除
ウォッチドッグ自動遅延分散ロックを取得したノードがクラッシュし、ロックがまだロックされている場合、デッドロックが発生します。 この状況を回避するために、ロックのタイムアウト自動解除時間を設定します。 しかし、まだ問題が残っています。 スレッドがロックを正常に取得し、30 秒のタイムアウトを設定したとします。ただし、タスクが 30 秒以内に完了せず、タイムアウトによりロックが解放された場合、他のスレッドが取得すべきでないロックを取得する可能性があります。 そのため、Redisson はウォッチドッグ自動遅延メカニズムとロックを監視するためのウォッチドッグを提供します。その機能は、Redisson インスタンスが閉じられる前にロックの有効期間を継続的に延長することです。 つまり、ロックを取得したスレッドがロジックを完了していない場合、ウォッチドッグはスレッドがロック タイムアウトを継続的に延長するのを支援し、タイムアウトによってロックが解放されることはありません。 デフォルトでは、ウォッチドッグの更新時間は 30 秒ですが、Config.lockWatchdogTimeout を変更することで指定することもできます。 さらに、Redisson は、leaseTime パラメータを指定してロック時間を指定できるロック メソッドも提供します。 この時間が経過すると、ロックは自動的に解除され、ロックの有効期間は延長されません。 原則は次のとおりです。 注意すべき点が 2 つあります。
ソースコードガイドlock メソッドが呼び出されると、最終的に tryAcquireAsync が呼び出されます。 呼び出しチェーンは lock()->tryAcquire->tryAcquireAsync です。詳細な説明は次のとおりです。
scheduleExpirationRenewal は renewExpiration を呼び出し、タイムアウトを有効にして拡張アクションを実行します。
scheduleExpirationRenewal は renewExpirationAsync を呼び出し、次の Lua スクリプトを実行します。 主に、Redis にロックが存在するかどうかを判断します。そうなった場合、有効期限が延長されます。
要約する終わったら、画面を閉じて、自分が何をしているのか、なぜそれをしているのか、どんな問題を解決しようとしているのかを考えながら、もう一度各ステップを頭の中で確認することをお勧めします。 一緒に、Redis 分散ロックのさまざまなトリックを最初から最後まで確認しました。実際、これらの点の多くは、分散ロックに何を使用しても存在する問題です。大切なのは思考のプロセスです。 システム設計に関しては、誰もが異なる出発点を持っています。完璧な建築、普遍的な建築というものは存在しませんが、完璧さと普遍性の間で良いバランスをとった建築は良い建築です。 この記事はWeChatの公開アカウント「MaGeByte」から転載したもので、以下のQRコードからフォローできます。この記事を転載する場合は、Code Byte の公開アカウントにご連絡ください。 |
<<: マルチクラウド戦略の 4 つの潜在的な問題: どうすれば解決できるでしょうか?
>>: ガートナー:クラウドは新たなデジタル体験の中心となる
間違いなく、ウェブサイトの内部最適化にとって、スパムコンテンツはSEOに深刻な影響を与える要素です。...
文/Jincuodao(WeChat公式アカウント:ijincuodao)以前も似たような商品を手掛...
Dangdang.com の収益構造 (Tianxia.com からの画像)テンセントテクノロジーの...
Baidu 検索エンジンはユーザー エクスペリエンスをターゲットにしており、多数の Web サイトが...
Cloudcone は今年の独身の日 (11.11) に 2 つの安価な VPS を導入しました。こ...
[51CTO.com からのオリジナル記事] 本日の re:Invent カンファレンスで、AWS ...
2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っていますはじめに:...
ビリビリは3月3日、第4四半期および通期の業績発表を行った。第4四半期のMAUは2億7,170万人に...
今年、Banwagong はブラックフライデーのプロモーションも実施し、全商品が 10% オフになり...
検索エンジンのランキングによってもたらされる無限のビジネスチャンスにより、SEO 専門職が誕生しまし...
最近、分散ストレージプロトコル Filecoin は、新しい無料サービス NFT.Storage の...
[[232050]]天候に頼って生計を立ててきた伝統的な農業は、静かに変化しつつある。四川省の特別養...
ご存知のとおり、ウェブサイトの運用とメンテナンスの最適化は体系的なプロセスです。業界やウェブサイトの...
最近、忙しいウェブマスターや SEO 担当者の中には、Baidu の最新の青大根アルゴリズムを学び始...
月給5,000~50,000のこれらのプロジェクトはあなたの将来ですキーワードの優位性は、企業のウェ...