Redis のマスター/スレーブ レプリケーション アーキテクチャの詳細な説明

青灯夜游
リリース: 2021-03-30 10:43:23
転載
2065 人が閲覧しました

この記事では、Redis のマスター/スレーブ レプリケーション アーキテクチャについて説明します。一定の参考値があるので、困っている友達が参考になれば幸いです。

Redis のマスター/スレーブ レプリケーション アーキテクチャの詳細な説明

高可用性には 2 つの意味があります。1 つはデータの損失を可能な限り回避すること、もう 1 つは可能な限りサービスを提供することです。 AOF と RDB はデータの永続性を可能な限り失わないようにするのに対し、マスター/スレーブ レプリケーションは 1 つのデータを複数のインスタンスにコピーを追加して保存します。 1 つのインスタンスがダウンしても、他のインスタンスは引き続きサービスを提供できます。

この記事では、主に、Redis の高可用性テクノロジ ソリューションの 1 つである マスター/スレーブ レプリケーション アーキテクチャ のあらゆる側面について説明します。

この記事はハードコアな記事です。収集してゆっくり味わうことをお勧めします。読者の質が向上すると信じています。間違いがある場合は修正してください、ありがとうございます。

【関連する推奨事項: Redis ビデオ チュートリアル ]

コア知識ポイント

Redis のマスター/スレーブ レプリケーション アーキテクチャの詳細な説明

冒頭メッセージ

質問 = チャンスです。問題に遭遇したとき、人は内心とても幸せになります。問題が大きいほど、チャンスも大きくなります。

何事にも値段がある、得もあれば損もあるはず、得もあれば損もあるはずだから、色々なことを気にしなくてもいい、自分が何をしたいのかをしっかり考えればいいのです対価を払って、あとはやってみよう!

#1. マスター/スレーブ レプリケーションの概要

#65 兄弟: RDB と AOF を使用すると、データ損失を心配する必要がなくなります。ダウンタイムですが、Redis インスタンス マシンがダウンしているときに高可用性を実現するにはどうすればよいですか?

1 台のマシンがダウンしてサービスを提供できない場合、複数のマシンはどうなるでしょうか?解決できるでしょうか? Redis は、マスター/スレーブ レプリケーションを通じてデータの冗長コピーを他の Redis サーバーにコピーするマスター/スレーブ モードを提供します。

前者をマスター ノード (master)、後者をスレーブ ノード (スレーブ) と呼び、データの複製は一方向であり、マスター ノードからスレーブ ノードへのみ可能です。

デフォルトでは、各 Redis サーバーはマスター ノードであり、マスター ノードは複数のスレーブ ノードを持つことができます (またはスレーブ ノードがない) が、スレーブ ノードが持つことができるマスター ノードは 1 つだけです。

65 兄弟: マスターとスレーブの間でデータの一貫性を確保するにはどうすればよいですか?

レプリカ データの一貫性を確保するために、マスター/スレーブ アーキテクチャでは読み取り/書き込み分離方式が採用されています。

  • 読み取り操作: マスター ライブラリとスレーブ ライブラリの両方が実行可能;
  • 書き込み操作: マスター ライブラリが最初に実行し、次に書き込み操作をスレーブ ライブラリに同期します。

Redis のマスター/スレーブ レプリケーション アーキテクチャの詳細な説明

#65 兄弟: なぜ読み書きを分ける必要があるのですか?

マスター ライブラリとスレーブ ライブラリの両方が書き込み命令を実行できると想定できます。同じデータが複数回変更され、それぞれの変更が異なるマスター/スレーブ インスタンスに送信された場合、インスタンスのコピー データは矛盾している。

データの一貫性を確保するために、Redis が複数のインスタンスの変更をロックして調整する必要がある場合、Redis は当然これを実行しません。

65 兄: マスター/スレーブ レプリケーションには他の機能もありますか?
  • 障害回復: マスター ノードがダウンしても、他のノードは引き続きサービスを提供できます。

  • 負荷分散: マスター ノードは書き込みサービスを提供します。 、およびスレーブ ノード 読み取りサービスと共有プレッシャーを提供します;

  • 高可用性の基礎: これはセンチネルとクラスターの実装の基礎であり、高可用性の基礎です。

2. マスター/スレーブ レプリケーションのセットアップ

マスター/スレーブ レプリケーションのアクティブ化はスレーブ ノードから完全に開始され、すべてをマスターノード上で行う必要はありません。

65 兄弟: マスター/スレーブ レプリケーション アーキテクチャを構築するにはどうすればよいですか?

マスター データベースとスレーブ データベース間の関係は、replicaof (slaveof は Redis 5.0 より前に使用されていました) コマンドを通じて形成できます。

スレーブ ノードでマスター/スレーブ レプリケーションを有効にするには 3 つの方法があります。

  • 設定ファイル

    の設定ファイルに を追加します。スレーブサーバーのレプリカ <masterip> <masterport></masterport></masterip>

  • コマンドの開始

    redis-server Add --replicaof <masterip> &lt ;masterport></masterip>

  • クライアント コマンド

    複数の Redis インスタンスを起動した後、クライアント経由でコマンドを直接実行します: replicaof <masterip> &lt ; masterport></masterip> の場合、Redis インスタンスはスレーブ ノードになります。

たとえば、インスタンス 1 (172.16.88.1)、インスタンス 2 (172.16.88.2)、インスタンス 3 (172.16.88.3) があると仮定し、インスタンス 2 とインスタンスに対して次のコマンドを実行します。コマンド、インスタンス 2 およびインスタンス 3 はインスタンス 1 のスレーブ ライブラリになり、インスタンス 1 がマスターになります。

replicaof 172.16.88.1 6379
ログイン後にコピー

3. マスター/スレーブ レプリケーションの原理

マスター/スレーブ ライブラリ モードで読み取り/書き込み分離が採用されると、すべてのデータ書き込み操作はマスター ライブラリ上でのみ実行され、 3 つの例を調整する必要があります。

マスター データベースに最新のデータが追加されると、マスター データベースとスレーブ データベースのデータの一貫性が保たれるように、マスター データベースはスレーブ データベースに同期されます。

65 兄: マスターとスレーブのデータベースの同期はどのように完了しましたか?マスター データベースのデータはスレーブ データベースに一度に送信されますか? それともバッチで同期されますか?通常の操作中に同期するにはどうすればよいですか?マスター ライブラリとスレーブ ライブラリ間のネットワークが切断された場合、再接続後もデータの一貫性は維持されますか?

65 兄弟、なぜそんなにたくさんの質問があるのですか? 同期は 3 つの状況に分かれています:

  • マスター/スレーブ ライブラリの最初の完全なコピー;

  • マスターとスレーブの通常動作中の同期;

  • マスター ライブラリとスレーブ ライブラリ間のネットワークが切断され、同期のために再接続されます。

マスター/スレーブ データベースの最初の完全なコピー

65 兄: めまいがするので、マスター/スレーブ データベースを同期しましょう初めてそれについて話しましょう。

マスター/スレーブ ライブラリの最初のレプリケーション プロセスは、接続確立段階 (準備段階)、マスター ライブラリからライブラリへのデータの同期段階の 3 つの段階に大別できます。スレーブ ライブラリ、および同期中に新しい書き込みコマンドを送信します。ライブラリの段階から;

画像に直接移動すると、全体としてグローバルな視点が得られます。これについては後で詳しく説明します。 。

Redis のマスター/スレーブ レプリケーション アーキテクチャの詳細な説明

#接続の確立

この段階の主な機能は、マスター間の接続を確立することです。完全なデータ同期の準備をしてください。

スレーブ ライブラリはマスター ライブラリとの接続を確立します。スレーブ ライブラリは、replicaof を実行し、pync コマンドを送信し、同期が行われることをマスター ライブラリに伝えます。マスター ライブラリが応答を確認すると、マスター ライブラリ間の同期が行われます。マスター ライブラリとスレーブ ライブラリが開始されます

65 兄弟: スレーブ ライブラリはどのようにしてメイン ライブラリの情報を知り、接続を確立するのですか?
スレーブ ノードの構成ファイル内の replicaof 構成項目でマスター ノードの IP とポートを構成すると、スレーブ ノードはどのマスター ノードに接続するかを認識します。

スレーブ ノードは、マスター ノードの IP およびポート情報を保存するために使用される 2 つのフィールド、masterhost および masterport を維持します。

スレーブ ライブラリは

replicaof を実行し、データ同期を実行することを示す psync コマンドを送信します。コマンドを受信した後、マスター ライブラリは次の指示に従ってレプリケーションを開始します。パラメータ。このコマンドには、メイン ライブラリの runIDcopy progress offset という 2 つのパラメータが含まれています。

    runID
  • : 各 Redis インスタンスは、開始時に一意の識別 ID を自動的に生成します。最初のマスター/スレーブ レプリケーションでは、メイン データベースの runID がまだ不明であるため、パラメータは "?" に設定されます。
  • offset
  • : 最初のコピーは -1 に設定され、最初のコピーを示し、コピーの進行状況のオフセットを記録します。
  • メイン ライブラリは、psync コマンドを受信した後、
FULLRESYNC を使用して、2 つのパラメーター (メイン ライブラリの runID とメイン ライブラリの現在のコピー進行​​状況オフセット) でコマンドに応答します。それをスレーブライブラリ

に返します。ライブラリからの応答を受信した後、これら 2 つのパラメータが記録されます。

FULLRESYNC 応答は、最初のレプリケーションに使用された完全なレプリケーション

を示します。つまり、マスター データベースは現在のデータをすべてスレーブ データベースにコピーします。

マスター データベースはデータをスレーブ データベースに同期します

第 2 フェーズ

マスターは

bgsave

コマンドを実行して RDB を生成しますファイルがスレーブ ライブラリに送信され、メイン ライブラリは各スレーブのレプリケーション バッファを開き、RDB ファイルの生成以降に受信したすべての書き込みコマンドを記録します。 ライブラリから RDB ファイルを受信したら、それをディスクに保存し、現在のデータベースのデータをクリアしてから、RDB ファイルのデータをメモリにロードします。

新しい書き込みコマンドをスレーブ ライブラリに送信します

第 3 フェーズ

スレーブ ノードが RDB をロードした後、マスター ノードは RDB を複製します。バッファ内のデータがスレーブ ノードに送信され、スレーブが受信して実行し、スレーブ ノードはマスター ノードと同じ状態に同期します。

65 兄: マスター データベースがスレーブ データベースにデータを同期しているとき、リクエストは正常に受け付けられますか?

メイン データベースはブロックされません。高速になりたいだけなので、Redis はあらゆる場面でブロックされます。

RDB ファイル生成後の書き込み操作は、先ほどの RDB ファイルには記録されていません。マスター/スレーブ データベースのデータの整合性を確保するために、マスター データベースはメモリ内のレプリケーション バッファを使用して、 RDB ファイルの生成とその後のすべての書き込み操作を記録します。

65 兄弟: データベースから RDB ファイルを受け取った後、なぜ現在のデータベースをクリアする必要があるのですか?

スレーブ ライブラリは、
replcaof

コマンドを通じてマスター ライブラリとの同期を開始する前に、マスター データとスレーブ データ間の影響を防ぐために、他のデータを保存する場合があるためです。 レプリケーション バッファとは正確には何ですか?

マスター側に作成されたバッファ。以下の 3 周期のマスターデータ書き込み動作すべてが格納されます。

1) RDB を生成するマスター実行 bgsave 中の書き込み操作;

2) マスターが rdb をスレーブ ネットワークに送信する際の書き込み操作;

3) スレーブ ロード rdbデータをメモリに復元する際のファイル書き込み操作。

Redis 和客户端通信也好,和从库通信也好,Redis 都分配一个内存 buffer 进行数据交互,客户端就是一个 client,从库也是一个 client,我们每个 client 连上 Redis 后,Redis 都会分配一个专有 client buffer,所有数据交互都是通过这个 buffer 进行的。

Master 先把数据写到这个 buffer 中,然后再通过网络发送出去,这样就完成了数据交互。

不管是主从在增量同步还是全量同步时,master 会为其分配一个 buffer ,只不过这个 buffer 专门用来传播写命令到从库,保证主从数据一致,我们通常把它叫做 replication buffer。

replication buffer 太小会引发的问题

replication buffer 由 client-output-buffer-limit slave 设置,当这个值太小会导致主从复制连接断开

1)当 master-slave 复制连接断开,master 会释放连接相关的数据。replication buffer 中的数据也就丢失了,此时主从之间重新开始复制过程。

2)还有个更严重的问题,主从复制连接断开,导致主从上出现重新执行 bgsave 和 rdb 重传操作无限循环。

当主节点数据量较大,或者主从节点之间网络延迟较大时,可能导致该缓冲区的大小超过了限制,此时主节点会断开与从节点之间的连接;

这种情况可能引起全量复制 -> replication buffer 溢出导致连接中断 -> 重连 -> 全量复制 -> replication buffer 缓冲区溢出导致连接中断……的循环。

具体详情:[top redis headaches for devops – replication buffer]
因而推荐把 replication buffer 的 hard/soft limit 设置成 512M。

config set client-output-buffer-limit "slave 536870912 536870912 0"
ログイン後にコピー
65 哥:主从库复制为何不使用 AOF 呢?相比 RDB 来说,丢失的数据更少。

这个问题问的好,原因如下:

  • RDB 文件是二进制文件,网络传输 RDB 和写入磁盘的 IO 效率都要比 AOF 高。

  • 从库进行数据恢复的时候,RDB 的恢复效率也要高于 AOF。

增量复制

65 哥:主从库间的网络断了咋办?断开后要重新全量复制么?

在 Redis 2.8 之前,如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大。

从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。

增量复制:用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效

repl_backlog_buffer

断开重连增量复制的实现奥秘就是 repl_backlog_buffer 缓冲区,不管在什么时候 master 都会将写指令操作记录在 repl_backlog_buffer 中,因为内存有限, repl_backlog_buffer 是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容

master 使用 master_repl_offset记录自己写到的位置偏移量,slave 则使用 slave_repl_offset记录已经读取到的偏移量。

master 收到写操作,偏移量则会增加。从库持续执行同步的写指令后,在 repl_backlog_buffer 的已复制的偏移量 slave_repl_offset 也在不断增加。

正常情况下,这两个偏移量基本相等。在网络断连阶段,主库可能会收到新的写操作命令,所以 master_repl_offset会大于 slave_repl_offset

Redis のマスター/スレーブ レプリケーション アーキテクチャの詳細な説明

当主从断开重连后,slave 会先发送 psync 命令给 master,同时将自己的 runIDslave_repl_offset发送给 master。

master 只需要把 master_repl_offsetslave_repl_offset之间的命令同步给从库即可。

增量复制执行流程如下图:

Redis のマスター/スレーブ レプリケーション アーキテクチャの詳細な説明

65 哥:repl_backlog_buffer 太小的话从库还没读取到就被 Master 的新写操作覆盖了咋办?

我们要想办法避免这个情况,一旦被覆盖就会执行全量复制。我们可以调整 repl_backlog_size 这个参数用于控制缓冲区大小。计算公式:

repl_backlog_buffer = second * write_size_per_second
ログイン後にコピー
  • second:从服务器断开重连主服务器所需的平均时间;

  • write_size_per_second:master 平均每秒产生的命令数据量大小(写命令和数据大小总和);

例如,如果主服务器平均每秒产生 1 MB 的写数据,而从服务器断线之后平均要 5 秒才能重新连接上主服务器,那么复制积压缓冲区的大小就不能低于 5 MB。

为了安全起见,可以将复制积压缓冲区的大小设为2 * second * write_size_per_second,这样可以保证绝大部分断线情况都能用部分重同步来处理。

基于长连接的命令传播

65 哥:完成全量同步后,正常运行过程如何同步呢?

当主从库完成了全量复制,它们之间就会一直维护一个网络连接,主库会通过这个连接将后续陆续收到的命令操作再同步给从库,这个过程也称为基于长连接的命令传播,使用长连接的目的就是避免频繁建立连接导致的开销。

在命令传播阶段,除了发送写命令,主从节点还维持着心跳机制:PING 和 REPLCONF ACK。

主->从:PING

每隔指定的时间,主节点会向从节点发送 PING 命令,这个 PING 命令的作用,主要是为了让从节点进行超时判断。

从->主:REPLCONF ACK

在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:

REPLCONF ACK <replication_offset></replication_offset>
ログイン後にコピー

其中 replication_offset 是从服务器当前的复制偏移量。发送 REPLCONF ACK 命令对于主从服务器有三个作用:

  • 检测主从服务器的网络连接状态。

  • 辅助实现 min-slaves 选项。

  • 检测命令丢失, 从节点发送了自身的 slave_replication_offset,主节点会用自己的 master_replication_offset 对比,如果从节点数据缺失,主节点会从 repl_backlog_buffer缓冲区中找到并推送缺失的数据。注意,offset 和 repl_backlog_buffer 缓冲区,不仅可以用于部分复制,也可以用于处理命令丢失等情形;区别在于前者是在断线重连后进行的,而后者是在主从节点没有断线的情况下进行的。

如何确定执行全量同步还是部分同步?

在 Redis 2.8 及以后,从节点可以发送 psync 命令请求同步数据,此时根据主从节点当前状态的不同,同步方式可能是全量复制部分复制。本文以 Redis 2.8 及之后的版本为例。

关键就是 psync的执行:

Redis のマスター/スレーブ レプリケーション アーキテクチャの詳細な説明

  • 从节点根据当前状态,发送 psync命令给 master:

    • 如果从节点从未执行过 replicaof ,则从节点发送 psync ? -1,向主节点发送全量复制请求;
    • 如果从节点之前执行过 replicaof 则发送 psync <runid> <offset></offset></runid>, runID 是上次复制保存的主节点 runID,offset 是上次复制截至时从节点保存的复制偏移量。
  • 主节点根据接受到的psync命令和当前服务器状态,决定执行全量复制还是部分复制:

    • runID 与从节点发送的 runID 相同,且从节点发送的 slave_repl_offset 之后的数据在 repl_backlog_buffer 缓冲区中都存在,则回复 CONTINUE,表示将进行部分复制,从节点等待主节点发送其缺少的数据即可;
    • runID 与从节点发送的 runID 不同,或者从节点发送的 slave_repl_offset 之后的数据已不在主节点的 repl_backlog_buffer 缓冲区中 (在队列中被挤出了),则回复从节点 FULLRESYNC <runid> <offset></offset></runid>,表示要进行全量复制,其中 runID 表示主节点当前的 runID,offset 表示主节点当前的 offset,从节点保存这两个值,以备使用。

一个从库如果和主库断连时间过长,造成它在主库 repl_backlog_buffer 的 slave_repl_offset 位置上的数据已经被覆盖掉了,此时从库和主库间将进行全量复制。

总结下

每个从库会记录自己的 slave_repl_offset,每个从库的复制进度也不一定相同。

在和主库重连进行恢复时,从库会通过 psync 命令把自己记录的 slave_repl_offset 发给主库,主库会根据从库各自的复制进度,来决定这个从库可以进行增量复制,还是全量复制。

レプリケーション バッファーと repl_backlog

  • レプリケーション バッファーは、config set client-output-buffer-limit スレーブ set を通じて各スレーブに対応します。上。

  • repl_backlog_buffer はリング バッファです。マスター プロセス全体に 1 つだけ存在し、すべてのスレーブに共通です。 repl_backlog のサイズは、repl-backlog-size パラメータによって設定されます。デフォルトのサイズは 1M です。サイズは、1 秒あたりに生成されたコマンドの合計に基づいて計算できます (マスターが rdb bgsave を実行します) (マスターが rdb をスレーブに送信します) (スレーブ ロード RDB ファイル) 時間 バックログ バッファのサイズを推定します。repl-backlog-size 値は、これら 2 つの積以上です。

一般に、レプリケーション バッファは、マスター/スレーブ ライブラリが完全なレプリケーションを実行するときに、マスター ライブラリ上のクライアントがスレーブ ライブラリに接続するために使用するバッファです。 repl_backlog_buffer は、スレーブ ライブラリからの増分レプリケーションをサポートするために、書き込み操作を継続的に保存するために使用されるメイン ライブラリの専用バッファです。

repl_backlog_buffer は専用バッファです。Redis サーバーの起動後、書き込み操作コマンドの受信が開始されます。これはすべてのスレーブ ライブラリで共有されます。マスター ライブラリとスレーブ ライブラリは、それぞれ独自のレプリケーションの進行状況を記録します。そのため、異なるスレーブ ライブラリが回復しているとき、それらは独自のレプリケーションの進行状況 (slave_repl_offset) をマスター ライブラリに送信し、マスター ライブラリは独立した同期。

図に示すように:

Redis のマスター/スレーブ レプリケーション アーキテクチャの詳細な説明

4. マスター/スレーブ アプリケーションの問題

4.1 読み取りと書き込みの分離の問題

データの有効期限の問題

65 兄弟: マスター/スレーブ レプリケーションのシナリオでは、スレーブノードは期限切れのデータを削除しますか?

これは良い質問です。マスター ノードとスレーブ ノード間のデータの一貫性を保つため、スレーブ ノードはデータを積極的に削除しません。 Redis には 2 つの削除戦略があることがわかっています。

  • 遅延削除: クライアントが対応するデータをクエリすると、Redis はデータの有効期限が切れているかどうかを判断し、期限が切れた場合はデータを削除します。

  • 定期的な削除: Redis は、スケジュールされたタスクを通じて期限切れのデータを削除します。

65 兄弟: クライアントはスレーブ ノードからデータを読み取ることで、期限切れのデータを読み取ることになりますか?

Redis 3.2 以降では、ノードからデータを読み取るときに、まずデータの有効期限が切れているかどうかを判断します。有効期限が切れた場合、クライアントに返却されず、データは削除されます。

4.2 単一マシンのメモリ サイズ制限

Redis の単一マシンのメモリが 10 GB に達すると、スレーブ ノードの同期時間は数分のレベルになります。 ; スレーブノードが増えると復旧速度が遅くなります。システムの読み取り負荷が非常に高く、この期間にスレーブ ノードがサービスを提供できない場合、システムに多大な負荷がかかります。

データ量が大きすぎると、完全レプリケーションフェーズ中にマスターノードがフォークしてRDBファイルを保存するのに時間がかかりすぎ、スレーブノードは長時間データを受信できず、タイムアウトがトリガーされます。マスター ノードとスレーブ ノードのデータ同期も、フル ボリュームに陥る可能性があります。コピー ->タイムアウトによりレプリケーションが中断されます->再接続->フル コピー->タイムアウトによりレプリケーションが中断されます...サイクル。

さらに、マスター ノードの単一マシン メモリの絶対量に加えて、マスター ノードが占めるホスト メモリの割合が大きすぎてはなりません。50% ~ 65% のみを使用するのが最善です。メモリ、30% ~ 45% を残す メモリは、bgsave コマンドの実行やコピー バッファの作成などに使用されます。

概要

  • マスター/スレーブ レプリケーションの役割: AOF および RDB バイナリ ファイルにより、ダウンタイムからのデータの迅速な回復が保証され、データ損失が防止されます。可能な限りご対応させていただきます。ただし、ダウンタイムが発生すると依然としてサービスを提供できないため、マスター/スレーブ アーキテクチャと読み取り/書き込みの分離が進化しました。

  • マスター/スレーブ レプリケーションの原則: 接続確立フェーズ、データ同期フェーズ、コマンド伝播フェーズ。データ同期フェーズは完全レプリケーションと部分レプリケーションに分割されます。コマンド伝播フェーズでは、 PING コマンドと REPLCONF ACK コマンドは、相互にハートビート検出を実行します。

  • マスター/スレーブ レプリケーションは、データの冗長性、障害回復、読み取り負荷分散などの問題を解決または軽減しますが、その欠陥は依然として明らかです。 障害回復は自動化できません。操作 負荷分散ができない; ストレージ容量は 1 台のマシンによって制限されている; これらの問題を解決するには、Sentinel とクラスター の助けが必要ですが、これについては後の記事で紹介します。

65 兄: マー兄、あなたの写真は本当に美しく、内容も良いです。あなたの記事からたくさんのことを学びました。集めて、「いいね!」して、読んで、共有したいです。より多くの優秀な開発者に共通の進歩を見てもらいましょう!

プログラミング関連の知識について詳しくは、プログラミング ビデオをご覧ください。 !

以上がRedis のマスター/スレーブ レプリケーション アーキテクチャの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:segmentfault.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!