{"id":361,"date":"2017-08-15T00:00:00","date_gmt":"2017-08-15T00:00:00","guid":{"rendered":"https:\/\/en.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/"},"modified":"2024-05-22T07:38:00","modified_gmt":"2024-05-22T14:38:00","slug":"design-and-implementation-of-multi-raft","status":"publish","type":"post","link":"https:\/\/www.pingcap.com\/ko\/blog\/design-and-implementation-of-multi-raft\/","title":{"rendered":"The Design and Implementation of Multi-raft"},"content":{"rendered":"<h2><span class=\"ez-toc-section\" id=\"Placement_Driver\"><\/span>Placement Driver<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Placement Driver (PD), the global central controller of TiKV, stores the metadata information of the entire TiKV cluster, generates Global IDs, and is responsible for the scheduling of TiKV and the global TSO time service.<\/p>\n<p>PD is a critical central node. With the integration of etcd, it automatically supports the distributed scaling and failover as well as solves the problem of single point of failure. We will write another article to thoroughly introduce PD.<\/p>\n<p>In TiKV, the interaction with PD is placed in the <a href=\"https:\/\/github.com\/tikv\/tikv\/tree\/master\/components\/pd_client\">pd<\/a> directory. You can interact with PD with your self-defined RPC and the protocol is quite simple. In <a href=\"https:\/\/github.com\/tikv\/tikv\/blob\/master\/components\/pd_client\/src\/lib.rs\">pd\/mod.rs<\/a>, we provide the Client trait to interact with PD and have implemented the RPC Client.<\/p>\n<p>The Client trait of PD is easy to understand, most of which are the set\/get operations towards the metadata information of the cluster. But you need to pay extra attention to the operations below:<\/p>\n<p><strong><code>bootstrap_cluster<\/code><\/strong>: When we start a TiKV service, we should firstly find out whether the TiKV cluster has been bootstrapped through <code>is_cluster_bootstrapped<\/code>. If not, then create the first region on this TiKV service.<\/p>\n<p><strong><code>region_heartbeat<\/code><\/strong>: Region reports its related information to PD regularly for the subsequent scheduling. For example, if the number of peers reported to PD is smaller than the predefined number of replica, then PD adds a new Peer replica to this Region.<\/p>\n<p><strong><code>store_heartbeat<\/code><\/strong>: Store reports its related information to PD regularly for the subsequent scheduling. For example, Store informs PD of the current disk size and the free space. If PD considers it inadequate, it will not migrate other Peers to this Store.<\/p>\n<p><strong><code>ask_split\/report_split<\/code><\/strong>: When a Region needs to split, it will inform PD through <code>ask_split<\/code> and PD then generates the ID of the newly-split Region. After split successfully, Region informs PD through <code>report_split<\/code>.<\/p>\n<p>By the way, we will make PD support gRPC protocol in the future, so the <code>ClientAPI<\/code> will have some changes.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Raftstore\"><\/span>Raftstore<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The goal of TiKV is to support 100 TB+ data and it is impossible for one Raft group to make it, we need to use multiple Raft groups, which is <strong>Multi-raft<\/strong>. In TiKV, the implementation of Multi-raft is completed in Raftstore and you can find the code in the <a href=\"https:\/\/github.com\/pingcap\/tikv\/tree\/master\/components\/raftstore\/src\/store\">raftstore\/store<\/a> directory.<\/p>\n<h3>Region<\/h3>\n<p>To support Multi-raft, we perform data sharding and make each Raft store a portion of data.<\/p>\n<p>Hash and Range are commonly used for data sharding. TiKV uses Range and the main reason is that Range can better aggregate keys with the same prefix, which is convenient for operations like scan. Besides, Range outperforms in split\/merge than Hash. Usually, it only involves metadata modification and there is no need to move data around.<\/p>\n<p>The problem of Range is that a Region may probably become a performance hotspot due to frequent operations. But we can use PD to schedule these Regions onto better machines.<\/p>\n<p>To sum up, we use Range for data sharding in TiKV and split them into multiple Raft Groups, each of which is called a Region.<\/p>\n<p>Below is the protocol definition of Region&#8217;s protbuf:<\/p>\n<pre><code>\nmessage RegionEpoch {\n\n     optional uint64 conf_ver  = 1 [(gogoproto.nullable) = false];\n\n     optional uint64 version     = 2 [(gogoproto.nullable) = false];\n\n}\n\nmessage Region {\n\n    optional uint64 id                  = 1 [(gogoproto.nullable) = false];\n\n    optional bytes  start_key           = 2;\n\n    optional bytes  end_key             = 3;\n\n    optional RegionEpoch region_epoch   = 4;\n\n    repeated Peer   peers               = 5;\n\n}\n\nmessage Peer {\n\n    optional uint64 id          = 1 [(gogoproto.nullable) = false];\n\n    optional uint64 store_id    = 2 [(gogoproto.nullable) = false];\n\n}\n\n<\/code><\/pre>\n<p><strong><code>region_epoch<\/code><\/strong>: When a Region adds or deletes Peer or splits, we think that this Region&#8217;s epoch has changed. RegionEpoch&#8217;s <code>conf_ver<\/code> increases during ConfChange while <code>version<\/code> increases during split\/merge.<\/p>\n<p><strong><code>id<\/code><\/strong>: Region&#8217;s only indication and PD allocates it in a globally unique way.<\/p>\n<p><strong><code>start_key<\/code><\/strong>, <strong><code>end_key<\/code><\/strong>: Stand for the range of this Region [start_key, end_key). To the very first region, start and end key are both empty, and TiKV handles it in a special way internally.<\/p>\n<p><strong><code>peers<\/code><\/strong>: The node information included in the current Region. To a Raft Group, we usually have three replicas, each of which is a Peer. Peer&#8217;s <code>id<\/code> is also globally allocated by PD and <code>store_id<\/code> indicates the Store of this Peer.<\/p>\n<h3>RocksDB \/ Keys Prefix<\/h3>\n<p>In terms of actual data storage, whether it&#8217;s Raft Metadata, Log or the data in State Machine, we store them inside a RocksDB instance. More information about RocksDB, please refer to <a href=\"https:\/\/github.com\/facebook\/rocksdb\">the RocksDB project on GitHub<\/a>.<\/p>\n<p>We use different prefixes to differentiate data of Raft and State Machine. For detailed information, please refer to <a href=\"https:\/\/github.com\/tikv\/tikv\/blob\/master\/components\/keys\/src\/lib.rs\">keys\/src\/lib.rs<\/a>. As for the actual data of State Machine, we add &#8220;z&#8221; as the prefix and for other metadata stored locally, including Raft, we use the 0x01 prefix.<\/p>\n<p>I want to highlight the Key format of some important metadata and I&#8217;ll skip the first 0x01 prefix.<\/p>\n<ul>\n<li>0x01: To store <code>StoreIdent<\/code>. Before initializing this Store, we store information like its Cluster ID and Store ID into this key.<\/li>\n<li>0x02: To store some information of Raft. 0x02 is followed by the ID of this Raft Region (8-byte big endian) and a Suffix to identify different subtypes.<\/li>\n<li>0x01: Used to store Raft Log, followed by Log Index (8-byte big endian)<\/li>\n<li>0x02: Used to store <code>RaftLocalState<\/code><\/li>\n<li>0x03: Used to store <code>RaftApplyState<\/code><\/li>\n<li>0x03: Used to store some local metadata of Region. 0x03 is followed by the Raft Region ID and a Suffix to represent different subtypes.<\/li>\n<li>0x01: Used to store <code>RegionLocalState<\/code><\/li>\n<\/ul>\n<p>Types mentioned above are defined in protobuf:<\/p>\n<pre><code>\nmessage RaftLocalState {\n\n    eraftpb.HardState hard_state = 1;\n\n    uint64 last_index = 2;\n\n}\n\nmessage RaftApplyState {\n\n    uint64 applied_index = 1;\n\n    RaftTruncatedState truncated_state = 2;\n\n}\n\nenum PeerState {\n\n    Normal = 0;\n\n    Applying = 1;\n\n    Tombstone = 2;\n\n}\n\nmessage RegionLocalState {\n\n    PeerState state = 1;\n\n    metapb.Region region = 2;\n\n}\n\n<\/code><\/pre>\n<p><strong><code>RaftLocalState<\/code>:<\/strong> Used to store <code>HardState<\/code> of the current Raft and the last Log Index.<\/p>\n<p><strong><code>RaftApplyState<\/code>:<\/strong> Used to store the last Log index that Raft applies and some truncated Log information.<\/p>\n<p><strong><code>RegionLocalStaste<\/code>:<\/strong> Used to store Region information and the corresponding Peer state on this Store. <code>Normal<\/code> indicates that this Peer is normal, <code>Applying<\/code> means this Peer hasn&#8217;t finished the <code>apply snapshot<\/code> operation and <code>Tombstone<\/code> shows that this Peer has been removed from Region and cannot join in Raft Group.<\/p>\n<div class=\"trackable-btns\"><a href=\"\/download\"><button>Download TiDB<\/button><\/a><br \/>\n<a href=\"https:\/\/share.hsforms.com\/1e2W03wLJQQKPd1d9rCbj_Q2npzm\"><button>Subscribe to Blog<\/button><\/a><\/div>\n<h3>Peer Storage<\/h3>\n<p>We use Raft through <code>RawNode<\/code> because one Region corresponds to one Raft Group. Peer in Region corresponds to one Raft replica. Therefore, we encapsulate operations towards <code>RawNode<\/code> in Peer.<\/p>\n<p>To use Raft, we need to define our storage and this can be implemented in the <code>PeerStorage<\/code> class of <a href=\"https:\/\/github.com\/pingcap\/tikv\/blob\/master\/components\/raftstore\/src\/store\/peer_storage.rs\">raftstore\/store\/peer_storage.rs<\/a>.<\/p>\n<p>When creating <code>PeerStorage<\/code>, we need to get the previous <code>RaftLocalStat<\/code>, <code>RaftApplyState<\/code> and <code>last_term<\/code> of this Peer from RocksDB. These will be cached to memory for the subsequent quick access.<\/p>\n<p>Below requires extra attention:<\/p>\n<p>The value of both <code>RAFT_INIT_LOG_TERM<\/code> and <code>RAFT_INIT_LOG_INDEX<\/code> is 5 (as long as it&#8217;s larger than 1). In TiKV, there are several ways to create a Peer:<\/p>\n<ol>\n<li>Create actively: In general, for the first Peer replica of the first Region, we use this way and set its Log Term and Index as 5 during initialization.<\/li>\n<li>Create passively: When a Region adds a Peer replica and this <code>ConfChange<\/code> command has been applied, the Leader will send a Message to the Store of this newly-added Peer. When the Store receives this Message and confirms its legality, and finds that there is no corresponding Peer, it will create a corresponding Peer. However, at that time, this Peer is an uninitialized and any information of its Region is unknown to us, so we use 0 to initialize its Log Term and Index. Leader then will know this Follower has no data (there exists a Log notch from 0 to 5) and it will directly send snapshot to this Follower.<\/li>\n<li>Create when splitting: When a Region splits into two Regions, one of the Regions will inherit the metadata before splitting and just modify its Range while the other will create relevant meta information. The corresponding Peer of this newly-created Region and the initial Log Term and Index is also 5. The reason is that by then Leader and Follower both have the latest data and don&#8217;t need snapshot. (Note: Actually, the Split process is much more complicated and the situation of sending snapshot may occur. But I&#8217;m not going to elaborate in this article.)<\/li>\n<\/ol>\n<p>Then you need to pay attention to snapshot. Both generating and applying snapshot are time-consuming operations. <code>PeerStore<\/code> will only synchronize the meta information related to the snapshot to avoid the situation that the whole Raft thread will get stuck and obstruct the subsequent Raft process. Instead, <code>PeerStore<\/code> asynchronously performs snapshot on another thread and it maintains the state of snapshot:<\/p>\n<pre><code>\n  pub enum SnapState {\n\n      Relax,\n\n      Generating(Receiver&lt;Snapshot&gt;),\n\n      Applying(Arc&lt;AtomicUsize&gt;),\n\n      ApplyAborted,\n\n  }\n\n<\/code><\/pre>\n<p><code>Generating<\/code> here is a channel Receiver. Once the asynchronous snapshot is generated, it will send a message to this channel. Thus, during the next Raft check, it can get the snapshot from this channel directly. <code>Applying<\/code> is a shared atomic integer, so we can determine the state of the current <code>applying<\/code> in a multithreading manner.<\/p>\n<pre><code>\npub const JOB_STATUS_PENDING: usize = 0;\n\npub const JOB_STATUS_RUNNING: usize = 1;\n\npub const JOB_STATUS_CANCELLING: usize = 2;\n\npub const JOB_STATUS_CANCELLED: usize = 3;\n\npub const JOB_STATUS_FINISHED: usize = 4;\n\npub const JOB_STATUS_FAILED: usize = 5;\n\n<\/code><\/pre>\n<p>For example, the state <code>JOB_STATUS_RUNNING**<\/code>** indicates that applying snapshot is in progress. Currently, <code>JOB_STATUS_FAILED<\/code> is not allowed. In other words, if the applying snapshot fails, the system would panic.<\/p>\n<h3>Peer<\/h3>\n<p>Peer encapsulates <code>Raft RawNode<\/code>. Those <code>Propose<\/code> and <code>ready<\/code> operations towards Raft are done in Peer.<\/p>\n<p>The <code>propose<\/code> function of Peer is the interface of the external Client command. Peer will determine the type of this command:<\/p>\n<ul>\n<li>If it&#8217;s a read-only operation and Leader is still within the validity period of lease, Leader will provide local read directly without going through Raft.<\/li>\n<li>If it&#8217;s a Transfer Leader operation, Peer will first of all determine whether it is still Leader and whether the log of the Follower that needs to be the new Leader is latest. If so, Peer will call RawNode&#8217;s <code>transfer_leader<\/code> command.<\/li>\n<li>If it&#8217;s a Change Peer operation, Peer will call RawNode&#8217;s <code>propose_conf_change<\/code> command.<\/li>\n<li>For other operations, Peer will directly call RawNode&#8217;s <code>propose<\/code> command.<\/li>\n<\/ul>\n<p>Before <code>propose<\/code>, Peer will also store the corresponding callback into <code>PendingCmd<\/code>. When the corresponding log has been applied, it will call the corresponding callback through the unique UUID in the command and return the corresponding result to Client.<\/p>\n<p>Peer&#8217;s <code>handle_raft_ready<\/code> functions also require extra attention. We&#8217;ve mentioned that in the previous Raft session, when a <code>RawNode<\/code> is ready, we need to do a series of process to the data in <code>ready<\/code>, including writing entries into Storage, sending messages, applying <code>committed_entries<\/code>, <code>advance<\/code>, etc. All of these are done in the <code>handle_raft_ready<\/code> functions of Peer.<\/p>\n<p>As for <code>committed_entries<\/code>, Peer will parse the actual command, call the corresponding process and execute the corresponding function. For example, for <code>exec_admin_cmd<\/code>, Peer executes administering commands like <code>ConfChange<\/code> and <code>Split<\/code>; for <code>exec_write_cmd<\/code>, it executes the common data operation commands towards State Machine. To guarantee the data consistency, Peer will only store the modified data into <code>WriteBatch<\/code> of RocksDB when executing and then atomically write in RocksDB. It cannot modify the corresponding memory metadata unless the write operation is successful. If it fails, we will directly go panic to guarantee the data integrity.<\/p>\n<p>When Peer is handling <code>ready<\/code>, we pass in a <code>Transport<\/code> object for Peer to send message. Below is the definition of the Transport&#8217;s trait:<\/p>\n<pre><code>\npub trait Transport: Send + Clone {\n\n    fn send(&amp;self, msg: RaftMessage) -&gt; Result&lt;()&gt;;\n\n}\n\n<\/code><\/pre>\n<p>It only has one function: <code>send<\/code>. Transport implemented by TiKV will send the needed message to the Server layer which then sends to other nodes.<\/p>\n<h3>Multi-raft<\/h3>\n<p>Peer is a replica of a single Region. TiKV supports Multi-raft, so for a Store, we need to manage multiple Region replicas, which are managed systematically in the Store class.<\/p>\n<p>Store will use <code>region_peers: HashMap&lt;u64, Peer&gt;<\/code> to store all the information of Peers:<\/p>\n<p>The key of <code>region_peers<\/code> is the Region ID and Peer is the Peer replica on this Store of this Region.<\/p>\n<p>Store uses mio to drive the whole process (we will use <code>tokio-core<\/code> to simplify the asynchronous logic processing later).<\/p>\n<p>We have registered a base Raft Tick in mio and call it every 1000ms. Store will traverse all Peers, call the corresponding <code>RawNode tick<\/code> function at a time to drive Raft.<\/p>\n<p>Store accepts the request from the outside Client and Raft message sent by other Stores through the notify mechanism of mio. For example, when receiving <code>Msg::RaftCmd<\/code> message, Store will call <code>propose_raft_command<\/code>, while for <code>Msg::RaftMessage<\/code>, it will call <code>on_raft_message<\/code> .<\/p>\n<p>After each <code>EventLoop<\/code>, i.e. inside the tick call-back of mio, Store will perform <code>on_raft_ready<\/code>:<\/p>\n<ol>\n<li>Store traverses all the ready Peers and calls <code>handle_raft_ready_append<\/code>. We will use a <code>WriteBatch<\/code> to handle all ready append data and store the corresponding result at the same time.<\/li>\n<li>If <code>WriteBatch<\/code> succeeds, it will then call <code>post_raft_ready_append<\/code> successively, mainly for the Follower to send message. (Leader&#8217;s message has been completed in <code>handle_raft_ready_append<\/code>)<\/li>\n<li>Then, Store successively calls <code>handle_raft_ready_apply<\/code> and committed entries related to <code>apply<\/code> and then calls the final result of <code>on_ready_result<\/code>.<\/li>\n<\/ol>\n<h2><span class=\"ez-toc-section\" id=\"Summary\"><\/span>Summary<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>In this blog, I&#8217;ve shared the details about Multi-raft, one of TiKV&#8217;s key technologies. In the subsequent sections, we will introduce Transaction, Coprocessor, and how Placement Drivers schedules the entire cluster. Stay tuned!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The goal of TiKV is to support 100 TB+ of data and it is impossible for one Raft group to make it, we need to use multiple Raft groups, which is called Multi-raft.<\/p>","protected":false},"author":8,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ub_ctt_via":"","footnotes":""},"categories":[6],"tags":[23,22],"class_list":["post-361","post","type-post","status-publish","format-standard","hentry","category-engineering","tag-rust","tag-tikv"],"acf":[],"featured_image_src":null,"author_info":{"display_name":"TiDB Team","author_link":"https:\/\/www.pingcap.com\/ko\/blog\/author\/pingcap\/"},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.9 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>The Design and Implementation of Multi-raft | TiDB<\/title>\n<meta name=\"description\" content=\"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post &quot;The Design and Implementation of Multi-raft&quot; here.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.pingcap.com\/ko\/blog\/design-and-implementation-of-multi-raft\/\" \/>\n<meta property=\"og:locale\" content=\"ko_KR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"The Design and Implementation of Multi-raft | TiDB\" \/>\n<meta property=\"og:description\" content=\"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post &quot;The Design and Implementation of Multi-raft&quot; here.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.pingcap.com\/ko\/blog\/design-and-implementation-of-multi-raft\/\" \/>\n<meta property=\"og:site_name\" content=\"TiDB\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/facebook.com\/pingcap2015\" \/>\n<meta property=\"article:published_time\" content=\"2017-08-15T00:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-05-22T14:38:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/static.pingcap.com\/files\/2024\/09\/11005522\/Homepage-Ad.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1440\" \/>\n\t<meta property=\"og:image:height\" content=\"714\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"TiDB Team\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@PingCAP\" \/>\n<meta name=\"twitter:site\" content=\"@PingCAP\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"TiDB Team\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11\ubd84\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/\"},\"author\":{\"name\":\"TiDB Team\",\"@id\":\"https:\/\/www.pingcap.com\/#\/schema\/person\/b17c1fde961eebd318de8729d595df74\"},\"headline\":\"The Design and Implementation of Multi-raft\",\"datePublished\":\"2017-08-15T00:00:00+00:00\",\"dateModified\":\"2024-05-22T14:38:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/\"},\"wordCount\":1973,\"publisher\":{\"@id\":\"https:\/\/www.pingcap.com\/#organization\"},\"keywords\":[\"Rust\",\"TiKV\"],\"articleSection\":[\"Engineering\"],\"inLanguage\":\"ko-KR\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/\",\"url\":\"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/\",\"name\":\"The Design and Implementation of Multi-raft | TiDB\",\"isPartOf\":{\"@id\":\"https:\/\/www.pingcap.com\/#website\"},\"datePublished\":\"2017-08-15T00:00:00+00:00\",\"dateModified\":\"2024-05-22T14:38:00+00:00\",\"description\":\"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post \\\"The Design and Implementation of Multi-raft\\\" here.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/#breadcrumb\"},\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.pingcap.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"The Design and Implementation of Multi-raft\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.pingcap.com\/#website\",\"url\":\"https:\/\/www.pingcap.com\/\",\"name\":\"TiDB\",\"description\":\"TiDB | SQL at Scale\",\"publisher\":{\"@id\":\"https:\/\/www.pingcap.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.pingcap.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ko-KR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.pingcap.com\/#organization\",\"name\":\"PingCAP\",\"url\":\"https:\/\/www.pingcap.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\/\/www.pingcap.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/static.pingcap.com\/files\/2021\/11\/pingcap-logo.png\",\"contentUrl\":\"https:\/\/static.pingcap.com\/files\/2021\/11\/pingcap-logo.png\",\"width\":811,\"height\":232,\"caption\":\"PingCAP\"},\"image\":{\"@id\":\"https:\/\/www.pingcap.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/facebook.com\/pingcap2015\",\"https:\/\/x.com\/PingCAP\",\"https:\/\/linkedin.com\/company\/pingcap\",\"https:\/\/youtube.com\/channel\/UCuq4puT32DzHKT5rU1IZpIA\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.pingcap.com\/#\/schema\/person\/b17c1fde961eebd318de8729d595df74\",\"name\":\"TiDB Team\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\/\/www.pingcap.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/static.pingcap.com\/files\/2022\/10\/17234942\/avatar.jpg\",\"contentUrl\":\"https:\/\/static.pingcap.com\/files\/2022\/10\/17234942\/avatar.jpg\",\"caption\":\"TiDB Team\"},\"url\":\"https:\/\/www.pingcap.com\/ko\/blog\/author\/pingcap\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"The Design and Implementation of Multi-raft | TiDB","description":"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post \"The Design and Implementation of Multi-raft\" here.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.pingcap.com\/ko\/blog\/design-and-implementation-of-multi-raft\/","og_locale":"ko_KR","og_type":"article","og_title":"The Design and Implementation of Multi-raft | TiDB","og_description":"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post \"The Design and Implementation of Multi-raft\" here.","og_url":"https:\/\/www.pingcap.com\/ko\/blog\/design-and-implementation-of-multi-raft\/","og_site_name":"TiDB","article_publisher":"https:\/\/facebook.com\/pingcap2015","article_published_time":"2017-08-15T00:00:00+00:00","article_modified_time":"2024-05-22T14:38:00+00:00","og_image":[{"width":1440,"height":714,"url":"https:\/\/static.pingcap.com\/files\/2024\/09\/11005522\/Homepage-Ad.png","type":"image\/png"}],"author":"TiDB Team","twitter_card":"summary_large_image","twitter_creator":"@PingCAP","twitter_site":"@PingCAP","twitter_misc":{"Written by":"TiDB Team","Est. reading time":"11\ubd84"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/#article","isPartOf":{"@id":"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/"},"author":{"name":"TiDB Team","@id":"https:\/\/www.pingcap.com\/#\/schema\/person\/b17c1fde961eebd318de8729d595df74"},"headline":"The Design and Implementation of Multi-raft","datePublished":"2017-08-15T00:00:00+00:00","dateModified":"2024-05-22T14:38:00+00:00","mainEntityOfPage":{"@id":"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/"},"wordCount":1973,"publisher":{"@id":"https:\/\/www.pingcap.com\/#organization"},"keywords":["Rust","TiKV"],"articleSection":["Engineering"],"inLanguage":"ko-KR"},{"@type":"WebPage","@id":"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/","url":"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/","name":"The Design and Implementation of Multi-raft | TiDB","isPartOf":{"@id":"https:\/\/www.pingcap.com\/#website"},"datePublished":"2017-08-15T00:00:00+00:00","dateModified":"2024-05-22T14:38:00+00:00","description":"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post \"The Design and Implementation of Multi-raft\" here.","breadcrumb":{"@id":"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/#breadcrumb"},"inLanguage":"ko-KR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.pingcap.com\/blog\/design-and-implementation-of-multi-raft\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.pingcap.com\/"},{"@type":"ListItem","position":2,"name":"The Design and Implementation of Multi-raft"}]},{"@type":"WebSite","@id":"https:\/\/www.pingcap.com\/#website","url":"https:\/\/www.pingcap.com\/","name":"\ud2f0DB","description":"TiDB | SQL at Scale","publisher":{"@id":"https:\/\/www.pingcap.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.pingcap.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ko-KR"},{"@type":"Organization","@id":"https:\/\/www.pingcap.com\/#organization","name":"PingCAP","url":"https:\/\/www.pingcap.com\/","logo":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.pingcap.com\/#\/schema\/logo\/image\/","url":"https:\/\/static.pingcap.com\/files\/2021\/11\/pingcap-logo.png","contentUrl":"https:\/\/static.pingcap.com\/files\/2021\/11\/pingcap-logo.png","width":811,"height":232,"caption":"PingCAP"},"image":{"@id":"https:\/\/www.pingcap.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/facebook.com\/pingcap2015","https:\/\/x.com\/PingCAP","https:\/\/linkedin.com\/company\/pingcap","https:\/\/youtube.com\/channel\/UCuq4puT32DzHKT5rU1IZpIA"]},{"@type":"Person","@id":"https:\/\/www.pingcap.com\/#\/schema\/person\/b17c1fde961eebd318de8729d595df74","name":"TiDB Team","image":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.pingcap.com\/#\/schema\/person\/image\/","url":"https:\/\/static.pingcap.com\/files\/2022\/10\/17234942\/avatar.jpg","contentUrl":"https:\/\/static.pingcap.com\/files\/2022\/10\/17234942\/avatar.jpg","caption":"TiDB Team"},"url":"https:\/\/www.pingcap.com\/ko\/blog\/author\/pingcap\/"}]}},"grav_blocks":false,"card_markup":"<a class=\"card-resource bg-white\" href=\"https:\/\/www.pingcap.com\/ko\/blog\/design-and-implementation-of-multi-raft\/\"><div class=\"card-resource__content-container\"><div class=\"card-resource__content-head\"><div class=\"card-resource__category\">Engineering<\/div><\/div><h5 class=\"card-resource__title\">The Design and Implementation of Multi-raft<\/h5><\/div><\/a>","_links":{"self":[{"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/posts\/361","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/comments?post=361"}],"version-history":[{"count":2,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/posts\/361\/revisions"}],"predecessor-version":[{"id":17106,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/posts\/361\/revisions\/17106"}],"wp:attachment":[{"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/media?parent=361"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/categories?post=361"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/tags?post=361"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}