This article mainly introduces the Redis cluster specification detailed, we will from the most basic of what is the Redis cluster and the function of Redis cluster solution, involving node failure detection, cluster status detection, from the node election and other related content, more detailed, the need for friends can reference, hope to help everyone.
Introduction
This document is a specification (specification) document for the Redis Clustering feature under development, and the document is divided into two sections:
The first section describes those features that are currently implemented in the unstable branch.
The second section describes those features that are not yet implemented.
The contents of each part of the document may change with the design modification of the cluster function, where the chance of non-implementation modification is higher than that of the implemented function.
This specification contains all the knowledge you need to write the client library, but please note that some of the details listed here may change in the future.
What is a Redis cluster?
A Redis cluster is a distributed (distributed), fault tolerant (fault-tolerant) Redis implementation that can be used by a cluster as a subset (subset) of the functionality that ordinary single-machine Redis can use.
There is no central node or proxy node in the Redis cluster, and one of the main design goals of the cluster is to achieve linear scalability (linear scalability).
Redis Cluster sacrifices a part of the fault tolerance for consistency (consistency): The system maintains data consistency as much as possible with limited (limited) resistance to network disconnection (net split) and node failure.
The cluster treats node invalidation as one of the special cases of network disconnection.
The fault-tolerant functionality of a cluster is achieved by using the nodes (node) of both the primary node (master) and the Slave (slave) roles (role):
The master and Slave nodes use exactly the same server implementations, and their functions (functionally) are identical, but the slave node is typically used only to replace the failed master node.
However, if you do not need to guarantee the consistency of the "write first, read after" operation (Read-after-write consistency), you can use the slave node to perform a read-only query.
Functional subset of Redis cluster implementations
The Redis cluster implements all commands that handle a single database key in a single-machine redis.
Complex computation operations for multiple database keys, such as set-set operations and collection operations, are not implemented, and commands that theoretically require multiple database keys to be used by multiple nodes are not implemented.
In the future, users may be able to perform read-only operations on multiple database keys in the cluster's compute nodes (computation node) through the MIGRATE COPY command, but the cluster itself does not implement complex multi-key commands that require multiple database keys to be moved across multiple nodes.
Redis clusters do not support multi-database functions like single-machine Redis, the cluster uses only the default number NO. 0 database, and the SELECT command is not available.
Clients and servers in the Redis cluster protocol
The nodes in a Redis cluster have the following responsibilities:
Holds key-value pairs of data.
Record the status of the cluster, including the key to the correct node mapping (mapping keys to right nodes).
Automatically discovers other nodes, identifies the nodes that are not working properly, and, if necessary, elects a new master node from the node.
To perform the tasks listed above, each node in the cluster establishes a "Cluster connection (cluster bus)" With the other node, which is a TCP connection that communicates using the binary protocol.
The GOSSIP protocol is used between nodes to perform the following tasks:
Propagate (propagate) information about the cluster in order to discover the new node.
Send PING packets to other nodes to check that the target node is functioning properly.
Sends cluster information when a particular event occurs.
In addition, cluster connections are used to publish or subscribe to information in a cluster.
Because the cluster node cannot proxy command requests, the client should forward the command request to the other node itself when the node returns a-moved or-ask steering (redirection) error.
Because the client is free to send a command request to any node in the cluster and can forward the command to the correct node when necessary, based on the information provided by the steering error, the client is theoretically not required to save the cluster state information.
However, if the client can save the mapping information between the key and the node, it can effectively reduce the number of possible turns and improve the efficiency of the command execution.
Key Distribution Model
The key space of a Redis cluster is divided into 16,384 slots (slots), and the maximum number of nodes in the cluster is 16,384.
The recommended maximum number of nodes is about 1000.
Each master node is responsible for processing a portion of the 16,384 hash slots.
When we say that a cluster is in a "stable" state, it means that the cluster is not performing a reconfiguration (reconfiguration) operation, and each hash slot is processed by only one node.
Reconfiguration refers to moving one or some slots from one node to another node.
A master node can have any number of slave nodes, which are used to replace the primary node when the primary node is disconnected or the node fails.
The following is the algorithm that is responsible for mapping keys to slots:
Hash_slot = CRC16 (key) mod 16384
The following parameters are used by the algorithm:
Name of the algorithm: XMODEM (also known as ZMODEM or Crc-16/acorn)
Length of result: 16 bit
Number of entries (Poly): 1021 (also x16 + x12 + x5 + 1)
Initialization value: 0000
Reflection input byte (Reflect input byte): False
TX Output CRC (Reflect output CRC): False
XOR constant for CRC output value (constant to output CRC): 0000
The algorithm for the output of input "123456789": 31c3
The implementation of the CRC16 algorithm used by the cluster is given in Appendix A.
The 14 bits in the 16-bit output generated by the CRC16 algorithm are used.
In our tests, the CRC16 algorithm can well distribute various types of keys smoothly into 16,384 slots.
Cluster Node properties
Each node has a unique ID in the cluster, which is a hexadecimal 160-bit random number that is generated by/dev/urandom the first time the node is started.
The node will save its ID to the configuration file, and as long as the configuration file is not deleted, the node will continue to follow this ID.
The node ID is used to identify each node in the cluster. A node can change its IP and port number without changing the node ID. The cluster can automatically identify changes to the ip/port number and broadcast this information to other nodes through the GOSSIP protocol.
The following are the associated information for each node, and the node sends that information to the other nodes:
The IP address and TCP port number used by the node.
The flag of the node (flags).
The node is responsible for processing the hash slot.
The time at which the node last sent PING packets (packet) using a cluster connection.
The last time a node received a PONG packet in a reply.
The time at which the cluster marks the node as offline.
The number of nodes from the node.
If the node is from a node, then it records the node ID of the master node. If this is a master node, then the value of the primary node ID column is 0000000.
Part of the above information can be obtained by sending the CLUSTER NODES command to any node in the cluster (either the master node or the slave node).
The following is an example of sending the CLUSTER NODES command to the master node in the cluster, which consists of three nodes:
$ redis-cli Cluster nodesd1861060fe6a534d42d8a19aeb36600e18785e04:0 myself-0 1318428930 connected 0-13643886e65cc906bfd9b1f7e7bde468726a052d1dae 127.0.0.1:6380 master-1318428930 1318428931 connected 1365-2729d289c575dcbc4bdd2931585fd4339089e461a27d 127.0.0.1:6381 master-1318428931 1318428931 connected 2730-4095
In the three rows listed above, the fields from left to right are: node ID, IP address and port number, flag (flag), the last time the PING was sent, the last time the PONG was received, the connection status, the node is responsible for processing the slot.
Node handshake (implemented)
The node always answers (accept) The connection request from the cluster connection port and replies to the received Ping packet, even if the ping packet is from an untrusted node.
However, in addition to pinging, the node rejects all other packets that are not from the cluster node.
To allow one node to recognize another node as belonging to a cluster, there are only two ways to do this:
A node can force the node that receives the message to acknowledge that the node that sends the message is a part of the cluster by sending MEET information to the other node. A node sends MEET information to another node only when the administrator explicitly sends the CLUSTER MEET IP Port command to it.
In addition, if a trusted node propagates information from a third node to another node, the node that receives the message also recognizes the third node as a part of the cluster. That is, if a knows B, B knows C, and B propagates information about C to a, then a also identifies C as a part of the cluster and attempts to connect to C.
This means that if we add a/some new nodes to a cluster, then this/these new nodes will eventually be connected to all the other nodes already in the cluster.
This means that the cluster can automatically discover the other nodes as long as the administrator explicitly specifies the trusted relationship using the CLUSTER MEET command.
This node recognition mechanism makes the cluster more robust by preventing unexpected syndication (mix) of different Redis clusters due to IP address changes or other network events.
When a node's network connection is disconnected, it actively connects to other known nodes.
MOVED Steering
A Redis client can send command requests to any node in the cluster, including the slave node. The node parses the command request, and if the command is a command that the cluster can execute, the node looks for the slot where the key to be processed by the command is located.
If the hash slot you are looking for happens to be handled by the node that receives the command, the node executes the command directly.
On the other hand, if the slot you are looking for is not processed by that node, the node looks at the mapped record of the hash slot to the node ID that is stored internally and
End reply to a MOVED error.
Here is an example of a MOVED error:
GET x-moved 3999 127.0.0.1:6381
The error message contains the hash slot 3999 that the key x belongs to, and the IP and port number 127.0.0.1:6381 of the node responsible for processing the slot. The client needs to resend the GET command request to the owning node based on the IP and port number.
Note that even if the client waits a very long time before resending the GET command, the cluster again changes the configuration so that the node 127.0.0.1:6381 no longer handles slot 3999, and when the client sends the GET command to the node 127.0.0.1:6381 , the node returns a MOVED error to the client, indicating that the node that is now responsible for processing slot 3999.
Although we use IDs to identify the nodes in the cluster, in order to make the client's steering operation as simple as possible, the node returns the IP and port number of the target node directly in the MOVED error instead of the target node ID.
Although not required, a client should record (memorize) the "slot 3999 is handled by node 127.0.0.1:6381" information so that when another command needs to execute on slot 3999, the client can speed up the search for the correct node.
Note that when the cluster is in a stable state, all clients will eventually save a hash slot-to-node mapping record (map of hash slots to nodes), making the cluster very efficient: The client can send command requests directly to the correct node without having to turn, Agent or any other entity (entiy) that may have a single point of failure (failure).
In addition to the MOVED steering error, a client should also be able to handle the ASK steering error described later.
Cluster online reconfiguration (live reconfiguration)
Redis clusters support the addition or removal of nodes during cluster run.
In fact, the addition of nodes and the deletion of nodes can be abstracted into the same operation, that is, to move the hash slot from one node to another node:
Adding a new node to the cluster is equivalent to moving the slots of other existing nodes into a new, empty node.
Removing a node from the cluster is equivalent to moving all the slots of the removed node to the other nodes of the cluster.
Therefore, the core of implementing Redis cluster online reconfiguration is the ability to move slots from one node to another. Because a hash slot is actually a collection of keys, what the Redis cluster really does when it hashes (rehash) is to move some keys from one node to another.
To understand how a Redis cluster moves slots from one node to another, we need to introduce the individual subcommands of the CLUSTER command, which manages the slot conversion table for the cluster nodes (slots translation table).
The following are the available subcommands for the CLUSTER command:
CLUSTER addslots slot1 [Slot2] ... [Slotn] CLUSTER delslots slot1 [Slot2] ... [Slotn] CLUSTER setslot slot node Nodecluster setslot slot migrating nodecluster setslot slot importing NODE
The first two commands, Addslots and delslots, are used to assign to nodes (assign) or remove nodes, and when the slots are assigned or removed, the node propagates this information through the GOSSIP protocol to the entire cluster. The Addslots command is typically used as a means to quickly assign individual slots to individual nodes when a new cluster is created.
The CLUSTER setslot Slot node node subcommand assigns the specified slot slot to node nodes.
As for the CLUSTER Setslot slot migrating node command and the CLUSTER setslot slot importing node command, the former is used to migrate a slot slot in a given node to a node, which is used to transfer a given Slot slot Import to node nodes:
When a slot is set to the migrating state, the node that originally held the slot will continue to accept command requests for that slot, but the node will handle the command request only if the key that the command is processing still exists at the node.
If the key used by the command does not exist with the node, then the node returns a-ask steering (redirection) error to the client informing the client of the migration target node to send the command request to the slot.
When a slot is set to the importing State, the node accepts a command request for the slot only after it receives the asking command.
If the client does not send the asking command to the node, the node uses the-moved steering error to redirect the command request to the node that is really responsible for processing the slot.
The above instructions on migrating and importing are somewhat difficult to understand, let's illustrate with a practical example.
Suppose we now have a and B two nodes, and we want to move slot 8 from Node A to Node B, so we:
Send command to Node B CLUSTER setslot 8 Importing A
Send command to Node A CLUSTER setslot 8 migrating B
Each time the client sends a command request to the other node about hash slot 8, the nodes return to the client the steering information pointing to node A:
If the key to be processed by the command already exists in slot 8, then this command will be processed by node A.
If the key to be processed by the command does not exist in slot 8 (for example, to add a new key to the slot), then this command is handled by node B.
This mechanism will cause node A to no longer create any new keys about slot 8.
At the same time, a special client Redis-trib and the Redis cluster configuration program (Configuration Utility) move the keys inside slot 8 in node A to node B.
The move operation of the key is performed by the following two commands:
CLUSTER Getkeysinslot Slot Count
The above command causes the node to return the keys in count slots, and for each key returned by the command, Redis-trib sends a MIGRATE command to Node A, which moves the specified key atomically (atomic) from Node A to node B (during the move key , two nodes will be blocked to avoid a race condition.
The following is how the MIGRATE command works:
MIGRATE target_host target_port key target_database ID Timeout
The node executing the MIGRATE command connects to the target node and sends the serialized key data to target, and once the target returns OK, the node deletes its key from the database.
From the perspective of an external client, at some point in time, the key key either exists at Node A, or exists in Node B, but does not exist at both Node A and Node B.
Because the Redis cluster uses only number NO. 0 databases, the Target_database value is always 0 when the MIGRATE command is used to perform cluster operations.
The Target_database parameter exists to make the MIGRATE command a generic command that can be used for functions other than the cluster.
We have optimized the MIGRATE command so that it can remain efficient even when it transmits complex data such as a list key with multiple elements.
However, although MIGRATE is very efficient, cluster reconfiguration can take a significant amount of time on a cluster with a very large number of keys and a very high number of key data, which can lead to the cluster not adapting to applications that have stringent response times.
ASK Steering
Before introducing the MOVED steering, we said that there was another ASK turn, in addition to the MOVED steering.
When a node needs to allow a client to send a command request for a slot to another node for a long time (permanently), the node returns MOVED to the client.
On the other hand, the node returns an ask turn to the client when it needs to allow the client to move to the other node only in the next command request.
For example, in the example of slot 8 in our previous section, because slot 8 contains keys that are scattered across Node A and Node B, when the client does not find a key in Node A, it should go to node B to look for it, but this steering should affect only one command query, rather than having the client each time Go straight to find Node B: Before Node A has all of the keys that belong to slot 8 not all migrated to Node B, the client should first access node A and then Access Node B.
Since this steering only targets one of the slots in 16,384 slots, the performance loss from the steering to the cluster is an acceptable range.
For these reasons, if we continue to find Node B after finding node A, the client should send a asking command before sending a command request to Node B, otherwise the command request for a slot with a importing state will be rejected by Node B.
The node that receives the client asking command sets a one-time flag (flag) for the client, allowing the client to execute a command request for a slot on the importing state.
From the client's point of view, the full semantics of the ASK steering (semantics) are as follows:
If the client receives an ASK turn, the sending object of the command request is adjusted to the node specified.
Send a asking command before sending a real command request.
You do not have to update the slot 8-to-node mappings that the client logs: Slot 8 should still be mapped to node A, not node B.
Once Node A has completed the migration of slot 8, Node A will return the MOVED steering to the client when it receives the command request for slot 8 again, turning the command request about slot 8 to node B for a long time.
Note that even if the client has a Bug, the slot 8 is mapped prematurely to node B, but as long as the client does not send the asking command, the client will encounter a MOVED error when sending a command request and turn it back to node A.
Fault tolerant
Node failure detection
Here's how to implement a node failure check:
When a node sends a ping to another node, but the target node fails to return a response to the ping command within a given time frame, the node that sends the command marks the target node as PFAIL (possible failure, which may be invalidated).
The time limit for waiting for a PING reply is called a node timeout time frame, which is a node option (node-wise setting).
Each time a node sends a PING to another node, it randomly broadcasts the information of three nodes it knows, one of which is whether the node has been marked as PFAIL or FAIL.
When a node receives information from another node, it writes down those nodes that are marked as invalidated by the other nodes. This is known as the failure report (failure).
If a node has already marked a node as PFAIL and is explicitly based on the failure report received by the node, most of the other master nodes in the cluster also assume that the node is in a failed state, and the node marks the state of that failed node as fail.
Once a node is marked as fail, information about the node that has been invalidated is broadcast to the entire cluster, and all nodes that receive this information mark the failed node as fail.
To put it simply, one node has to mark another node as invalid, and the other node must be asked for comments, and the majority of the master node will agree.
Because an expired invalidation report is removed, the primary node must mark a node as fail, and the most recently received failure reports should be used as a basis.
In the following two cases, the FAIL state of the node is removed:
If the From node is marked as fail, the fail flag is removed when the node is back online.
It is meaningless to keep (retaning) the fail state from the node because it does not handle any slots, and whether a slave node is in a fail state determines whether the slave node can be promoted to the primary node if necessary.
If a primary node is marked with fail, after four times times the node timeout period, and after 10 seconds, the failover operation for the slot for the master node is still incomplete, and the primary node has been re-launched, then the fail token for this node is removed.
In the second case, if the failover fails to complete successfully and the primary node is back online, the cluster will continue to use the original master node, thereby eliminating the need for administrator intervention.
Cluster status detection (partially implemented)
Each node in the cluster scans (scan) for the nodes it knows whenever a configuration change occurs in the cluster (it could be a hash slot update or a node goes into a failed state).
Once the configuration has been processed, the cluster will enter one of the following two states:
Fail: The cluster is not working properly. When a node in the cluster enters a failed state, the cluster cannot process any command requests, and the cluster node returns an error reply for each command request.
OK: The cluster works correctly, and none of the nodes that are responsible for processing all 16,384 slots are marked as FAIL.
This means that even if only a subset of the hash slots in the cluster are not working properly, the entire cluster will stop processing any commands.
However, the cluster will still function properly during the time the node has been in trouble and marked as FAIL, so at some point it is still possible for the cluster to handle only one subset of the 16,384 slots for command requests.
The following are the two scenarios in which the cluster enters the FAIL state:
At least one hash slot is not available because the node responsible for processing the slot enters the FAIL state.
Most of the primary nodes in the cluster are in the offline state. When most primary nodes enter the PFAIL state, the cluster also enters the FAIL state.
The second check is necessary, because to change a node from the PFAIL state to the FAIL state, it is necessary to have a majority of the master nodes to vote, but when the majority of the main node in the cluster goes into the failed state, a single two node is no way to mark a node as fail state.
Therefore, with the second check condition, as long as most of the primary nodes in the cluster are in the offline state, the cluster can stop processing the command request by judging a node as a FAIL state without requesting these master nodes.
Election from node
Once a master node enters the FAIL state, if the primary node has one or more slave nodes, then one of the slave nodes is promoted to the new master node, and the other slave nodes begin to replicate the new master node.
The new master node is elected by itself from all nodes subordinate to the main node of the downline, and the following are the conditions of the election:
This node is the slave node of the primary node that has been rolled down.
The number of slots that have been processed by the primary node of the downline is not empty.
The data from the node is considered to be reliable, that is, the replication link between the master and slave nodes cannot exceed the node timeout period (nodes timeout) multiplied by redis_cluster_slave_validity_mult The product of the constant.
If a slave node satisfies all of the above conditions, the slave node will send an authorization request to the other master nodes in the cluster, asking them whether to allow themselves (from the node) to be promoted to the new master node.
If the slave node that sends the authorization request satisfies the following properties, the master node returns failover_auth_granted authorization to the slave node, agreeing to the
Upgrade Requirements:
The authorization request is sent from a node, and the primary node to which it belongs is in the FAIL state.
The node ID of this slave node is the smallest in the order of all the slave nodes of the main node that has been downline.
This slave node is in a normal state of operation: it is not marked as FAIL state, nor is it marked as PFAIL state.
Once a node is authorized by the majority of the master node within a given time frame, it begins to perform the following failover operations:
The PONG Packet (packet) informs the other nodes that the node is now the master node.
The PONG packet informs the other node that the node is an upgraded slave node (promoted slave).
Takeover (claiming) all hash slots that are handled by the primary node that has been rolled down.
Explicitly broadcasts an PONG packet to all nodes, speeding up the progress of the node by other nodes, rather than waiting for a timed ping/pong packet.
All other nodes update the configuration accordingly according to the new master node, specifically:
All slots that are taken over by the new master node are updated.
All slave nodes of the main node of the Downline are aware of the promoted flag and begin copying the new master node.
If the primary node of the downline is back online, it perceives the promoted flag and adjusts itself to the slave node of the current master node.
In the life cycle of a cluster, if a primary node with the promoted identity is converted to a slave node for some reason, the node loses the promoted identity it carries.
Publish/subscribe (implemented, but still needs improvement)
In a Redis cluster, the client can subscribe to either node or send information to any node, and the node forwards the information sent by the client.
In the current implementation, the node broadcasts the received information to all other nodes in the cluster, and in future implementations, it may use bloom filter or other algorithms to optimize the operation.
Appendix A:CRC16 the ANSI Implementation reference of the algorithm
/* Copyright 2001-2010 Georges Menie (www.menie.org) * Copyright Salvatore Sanfilippo (adapted to Redis coding Styl e) * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the Follo Wing conditions is met: * * * redistributions of source code must retain the above copyright * Notice, this list of Conditions and the following disclaimer. * * redistributions in binary form must reproduce the above copyright * Notice, this list of conditions and the Follo Wing Disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the University of California, Berkeley nor the * names of its contributors could be used to end Orse or promote products * derived from this software without specific prior written permission. * * This software are provided by the REGENTS and CONTRIBUTORS "as is" and any * EXPRESS OR implied warranties, including , BUT LIMITED to, the implied * warranties of merchantability and FITNESS for A particular PURPOSE is * disclaimed. In NO EVENT shall the REGENTS and CONTRIBUTORS is liable for any * DIRECT, INDIRECT, incidental, special, exemplary, OR CO Nsequential damages * (including, but not LIMITED to, procurement of substitute GOODS OR SERVICES; * LOSS of Use, DATA, OR Profits; or business interruption) however caused and * on any theory of liability, WHETHER in contract, STRICT liability, OR TORT * (including negligence OR OTHERWISE) arising in any-out-of-the-----the-this * software, even IF advised of the Possibi Lity of SUCH DAMAGE. *//* CRC16 Implementation acording to CCITT standards. * * Note by @antirez: The actually the XMODEM CRC algorithm, using the * following parameters: * * Name : "XMODEM", also known as "ZMODEM", "crc-16/acorn" * width:16 bit * poly:1021 (that's actually X ^16 + x^12 + x^5 + 1) * initialization:0000 * Reflect INPUT byte:false * Reflect output Crc:false * Xor constant to Output crc:0000 * output for "123456789": 31c3 */static Const uint16_t crc16tab[256]= {0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, 0x8108,0x9129, 0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, 0X1231,0X0210,0X3273,0X2252,0X52B5,0X4294,0X72F7,0X62D6, 0x9339, 0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695, 0X46B4, 0XB75B,0XA77A,0X9719,0X8738,0XF7DF,0XE7FE,0XD79D,0XC7BC, 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861, 0x2802,0x3823, 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71, 0x0a50,0x3a33,0x2a12, 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, 0X6CA6,0X7C87,0X4CE4,0X5CC5, 0x2c22,0x3c03,0x0c60,0x1c41, 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, 0X9188,0X81A9,0XB1CA, 0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, 0x83b9,0x9398, 0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, 0xb5ea, 0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, 0XA7DB,0XB7FA,0X8799,0X97B8,0XE75F,0XF77E,0XC71D,0XD73C, 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615, 0x5634, 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1, 0X3882,0X28A3, 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, 0X4A75,0X5A54,0X6A37,0X7A16,0X0AF1, 0x1ad0,0x2ab3,0x3a92, 0XFD2E,0XED0F,0XDD6C,0XCD4D,0XBDAA,0XAD8B,0X9DE8,0X8DC9, 0X7C26,0X6C07,0X5C64,0X4C45, 0X3CA2,0X2C83,0X1CE0,0X0CC1, 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, 0x6e17,0x7e36,0x4e55, 0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0};uint16_t CRC16 (const char *buf, int len) {int counter; uint16_t CRC = 0; for (counter = 0; counter < Len; counter++) CRC = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++) &0x00FF]; return CRC;}