In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly explains "how to use Raft components". The content in the article is simple and clear, and it is easy to learn and understand. Please follow the editor's ideas to study and learn "how to use Raft components".
I. compilation
Github can download Ratis and mvn clean package directly. If there is an error in the compilation process, you can clean install ratis-proto first.
2. Examples
There are three examples that come with Ratis:
Arithmetic
Counter
Filestore
In the ratis-examples module, it is convenient for arithmetic and filestore. You can test it by starting Server and Client quickly through the shell script in the main/bin directory.
For Raft, we all know that multiple instances are needed to form a cluster to test. It is useless for you to start an instance. Even choosing a master is a problem. The start-all under the Bin directory supports the name of example and the corresponding command. For example, filestore server stands for server that launches the application of filestore. The corresponding command parameters are parsed in the cli in the corresponding example. At the same time, three server are launched at a time to form a cluster and complete the election within the cycle.
In the case of counter, there is no script to quickly start the three server, which we can start as parameters from the command line or in IDE.
III. Analysis
Let's take a look at how Raft Server works in an example.
For the counter example, when we start, we need to pass in a parameter that represents the number of the current server, in order to know from the peers list which IP + port to use to start it. Here we can find that the peers list is set up in advance in the code. Of course, there is no problem when you talk about dynamic configuration, and the other two examples are passed in through the configuration in common in the shell script.
So, the first step we see is that when Raft Server starts, it will know the existence of peer through "configuration". Only in this way can we communicate with each other, let others vote for themselves or vote for others, and complete the election in the Term. In addition, the Log sent by Leader can be received and applied locally.
Second, let's take a look at how Client and the cluster communicate. There may be multiple instances of the entire Raft cluster, and we know that writes must be done through Leader. So how do you know who Leader is? Is there anything you can do?
The common ideas are as follows:
Before writing, go to the cluster to find out who is Leader, and then write
Take one at random to write, not another one, keep trying, there will always be a success.
Of course, way two is not very efficient to try this way. So after this random attempt, the cluster will return the current Leader information to Client, and then Client will communicate directly through this connection.
In Ratis, when Client calls a non-Leader node, it will receive an exception thrown by Server. The exception will contain a message called suggestLeader, indicating the current correct Leader. Just click this button to connect it. Of course, if the Leader changes during this process, a new suggestLeader will come back and try again.
Let's look at the implementation in the example of Counter.
The common Common code of Server and Client contains the declaration of peers
Public final class CounterCommon {public static final List PEERS = new ArrayList (3); static {PEERS.add (new RaftPeer (RaftPeerId.getRaftPeerId ("N1"), "127.0.0.1 new ArrayList 6000")); PEERS.add (new RaftPeer (RaftPeerId.getRaftPeerId ("N2"), "127.0.0.1 new ArrayList 6001"); PEERS.add (RaftPeerId.getRaftPeerId ("N2"), "127.0.0.1 new ArrayList 6002");}
Three nodes are declared here.
When started from the command line, index is passed directly in, with a value of 1-3 for index.
Java-cp * .jar org.apache.ratis.examples.counter.server.CounterServer {serverIndex}
Then when Server starts, get the corresponding configuration information.
/ / find current peer object based on application parameter RaftPeer currentPeer = CounterCommon.PEERS.get (Integer.parseInt (args [0])-1)
Then set up the storage directory
/ / set the storage directory (different for each peer) in RaftProperty object File raftStorageDir = new File (". /" + currentPeer.getId () .toString ()); RaftServerConfigKeys.setStorageDir (properties, Collections.singletonList (raftStorageDir))
Let's focus on this. Every Server has a state machine "CounterStateMachine", where our "business logic" is usually placed.
/ / create the counter state machine which hold the counter value CounterStateMachine counterStateMachine = new CounterStateMachine ()
The commands sent by the client will be executed in this state machine, and these commands will be copied to other nodes in the form of Log, and the Log of each node will be executed in its own state machine, thus ensuring the consistency of the state of each node.
Finally, according to these configurations, the Raft Server instance is generated and started.
/ / create and start the Raft server RaftServer server = RaftServer.newBuilder () .setGroup (CounterCommon.RAFT_GROUP) .setProperties (properties) .setServerId (currentPeer.getId ()) .setStateMachine (counterStateMachine) .build (); server.start ()
In CounterStateMachine, we first check whether the command is legal, and then execute the command by applying the counting code.
/ / check if the command is valid String logData = entry.getStateMachineLogEntry (). GetLogData () .toString (Charset.defaultCharset ()); if (! logData.equals ("INCREMENT")) {return CompletableFuture.completedFuture (Message.valueOf ("Invalid Command"));} / / update the last applied term and index final long index = entry.getIndex (); updateLastAppliedTermIndex (entry.getTerm (), index) / / actual execution of the command: increment the counter counter.incrementAndGet (); / / return the new value of the counter to the client final CompletableFuture f = CompletableFuture.completedFuture (Message.valueOf (counter.toString (); / / if leader, log the incremented value and it's log index if (trx.getServerRole () = = RaftProtos.RaftPeerRole.LEADER) {LOG.info ("{}: Increment to {}", index, counter.toString ());}
Let's take a look at the implementation of Client.
Similar to Server, create an instance by configuring properties
Private static RaftClient buildClient () {RaftProperties raftProperties = new RaftProperties (); RaftClient.Builder builder = RaftClient.newBuilder () .setProperties (raftProperties) .setRaftGroup (CounterCommon.RAFT_GROUP) .setClientRpc (new GrpcFactory (new Parameters ()) .newRaftClientRpc (ClientId.randomId (), raftProperties)); return builder.build ();}
Then you can send a command to Server to get to work.
RaftClient.send (Message.valueOf ("INCREMENT"))
Counter's state machine supports both INCREMENT and GET commands. So example finally executed a command of GET to get the final count result.
RaftClientReply count = raftClient.sendReadOnly (Message.valueOf ("GET"))
IV. Internal partial realization
In RaftClientImpl, you will initially choose one from the peers list and request it as a leader.
RaftClientImpl (ClientId clientId, RaftGroup group, RaftPeerId leaderId, RaftClientRpc clientRpc, RaftProperties properties, RetryPolicy retryPolicy) {this.clientId = clientId; this.clientRpc = clientRpc; this.peers = new ConcurrentLinkedQueue (group.getPeers ()); this.groupId = group.getGroupId (); this.leaderId = leaderId! = null? LeaderId:! peers.isEmpty ()? Peers.iterator (). Next (). GetId (): null;.}
After that, it will be handled separately according to the different exceptions returned by server.
Private RaftClientReply sendRequest (RaftClientRequest request) throws IOException {RaftClientReply reply; try {reply = clientRpc.sendRequest (request);} catch (GroupMismatchException gme) {throw gme;} catch (IOException ioe) {handleIOException (request, ioe);} reply = handleLeaderException (request, reply, null); reply = handleRaftException (reply, Function.identity ()); return reply;}
For example, in handleLeaderException, there are several cases, because when communicating with Server through Client, one of the peers is randomly selected as the leader to request. If the Server returns an exception and says it is not leader, use the following code to randomly select one of the other peer to request.
Final RaftPeerId oldLeader = request.getServerId (); final RaftPeerId curLeader = leaderId; final boolean stillLeader = oldLeader.equals (curLeader); if (newLeader = = null & & stillLeader) {newLeader = CollectionUtils.random (oldLeader, CollectionUtils.as (peers, RaftPeer::getId));} static T random (final T given, Iterable iteration) {Objects.requireNonNull (given, "given = = null"); Objects.requireNonNull (iteration, "iteration = = null") Final List list = StreamSupport.stream (iteration.spliterator (), false) .filter (e->! given.equals (e)) .filter (Collectors.toList ()); final int size = list.size (); return size = = 0? Null: list.get (ThreadLocalRandom.current (). NextInt (size);}
Does it feel inefficient. If at this time, the message returned by server tells client who is leader, then client can be connected directly.
/ * * @ return null if the reply is null or it has * {@ link NotLeaderException} or {@ link LeaderNotReadyException} * otherwise return the same reply. * / RaftClientReply handleLeaderException (RaftClientRequest request, RaftClientReply reply, Consumer handler) {if (reply = = null | | reply.getException () instanceof LeaderNotReadyException) {return null;} final NotLeaderException nle = reply.getNotLeaderException (); if (nle = = null) {return reply;} return handleNotLeaderException (request, nle, handler) } RaftClientReply handleNotLeaderException (RaftClientRequest request, NotLeaderException nle, Consumer handler) {refreshPeers (nle.getPeers ()); final RaftPeerId newLeader = nle.getSuggestedLeader () = = null? Null: nle.getSuggestedLeader () .getId (); handleIOException (request, nle, newLeader, handler); return null;}
We will see that in the abnormal information, if a suggestedLeader can be extracted, it will be used as a new leaderId, and it will be connected directly next time.
Thank you for your reading, the above is the content of "how to use Raft components", after the study of this article, I believe you have a deeper understanding of how to use Raft components, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.