1. Introduction
Database read/write separation is a means to optimize application performance. The principle of read/write separation is as follows: The master node is responsible for application write operations (also processing real-time read scenarios), while the slave node is responsible for application read operations. RedisCluster also contains master and slave nodes. Can the slave nodes in the RedisCluster process read requests the same as the slave nodes in the database to achieve read/write separation?
2.RedisCluster
The principle of
How is connection pooling implemented in Jedis? In standalone mode, JedisConnectionFactory initialization will directly create a JedisPool to achieve the management and reuse of connection resources.
public void afterPropertiesSet(a) {
// 1. If a connection pool is configured and the connection mode is not clustered, create a connection pool directly
if(getUsePool() && ! isRedisClusterAware()) {this.pool = createPool();
}
// 2. In cluster mode, create a cluster
if (isRedisClusterAware()) {
this.cluster = createCluster();
this.topologyProvider = createTopologyProvider(this.cluster);
this.clusterCommandExecutor = new ClusterCommandExecutor(this.topologyProvider,
new JedisClusterConnection.JedisClusterNodeResourceProvider(this.cluster, this.topologyProvider), EXCEPTION_TRANSLATION); }}Copy the code
2.1 Connecting Nodes
private void initializeSlotsCache(Set<HostAndPort> startNodes,
int connectionTimeout, int soTimeout, String user, String password, String clientName,
boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, HostnameVerifier hostnameVerifier) {
// 1. Traverse all cluster nodes
for (HostAndPort hostAndPort : startNodes) {
Jedis jedis = null;
try {
// 2. Create a Jedis object based on the node information to operate redis
jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort(), connectionTimeout, soTimeout, ssl, sslSocketFactory, sslParameters, hostnameVerifier);
// 3. Initialize slot
cache.discoverClusterNodesAndSlots(jedis);
break;
} catch (JedisConnectionException e) {
// try next nodes
} finally {
if(jedis ! =null) { jedis.close(); }}}}Copy the code
2.2 the initializationslot
Before analyzing the initialization slot code, execute the Cluster Slots command
Cluster slots returns the start and end values of the slot, the IP address, port, and ID of the master slot, and the IP address, port, and ID of the slave slot. It’s pretty easy to analyze the source code once you know what’s returned
public void discoverClusterNodesAndSlots(Jedis jedis) {
w.lock();
try {
reset();
// 1. Run the clster slots command
List<Object> slots = jedis.clusterSlots();
// 2. The traversal command returns a result
for (Object slotInfoObj : slots) {
List<Object> slotInfo = (List<Object>) slotInfoObj;
if (slotInfo.size() <= MASTER_NODE_INDEX) {
continue;
}
// 3. Obtain the number of slots. For example, the number of the first slot is 501
List<Integer> slotNums = getAssignedSlotArray(slotInfo);
// hostInfos
int size = slotInfo.size();
// 4. Start with the master message
for (int i = MASTER_NODE_INDEX; i < size; i++) {
// 5. Obtain the corresponding IP address, port number, and ID
List<Object> hostInfos = (List<Object>) slotInfo.get(i);
if (hostInfos.isEmpty()) {
continue;
}
// 6. Assemble the HostAndPort based on the IP address and port
HostAndPort targetNode = generateHostAndPort(hostInfos);
// 7. Store IP address: mapping between port and JedisPool
setupNodeIfNotExist(targetNode);
// 8. If the slot is master, the mapping between slot and JedisPool is stored. Therefore, the connection created by JedisPool can only operate mater
if(i == MASTER_NODE_INDEX) { assignSlotsToNode(slotNums, targetNode); }}}}finally{ w.unlock(); }}Copy the code
2.3 IP: Mapping between ports and JedisPool
2.4 Mapping between Slot and JedisPool
2.5 Compute the slot corresponding to the key
public static int getSlot(byte[] key) {
if (key == null) {
throw new JedisClusterOperationException("Slot calculation of null is impossible");
}
int s = -1;
int e = -1;
boolean sFound = false;
for (int i = 0; i < key.length; i++) {
if (key[i] == '{' && !sFound) {
s = i;
sFound = true;
}
if (key[i] == '} ' && sFound) {
e = i;
break; }}if (s > -1 && e > -1&& e ! = s +1) {
return getCRC16(key, s + 1, e) & (16384 - 1);
}
return getCRC16(key) & (16384 - 1);
}
Copy the code
CRC is performed on the key when the command is executed and the and operation is performed to obtain slot values
2.6 Obtaining the JedisPool
public JedisPool getSlotPool(int slot) {
r.lock();
try {
return slots.get(slot);
} finally{ r.unlock(); }}Copy the code
With slot values, you can obtain the corresponding JedisPool from the mapping in section 2.4. The JedisPool obtained is constructed based on the master address. Therefore, you can know that slave nodes of RedisCluster do not provide read services, but only provide high availability.