The actual combat of Redis advanced project has been in 0202, and there is no Redis Java advanced technology route

Posted by RonHam on Sat, 18 Dec 2021 21:21:03 +0100

Everyone has heard of the 10000 hour law, but is this really the case? After 10000 hours of CRUD, don't you only know CRUD? These days, you don't properly update your own technology stack. When you go out to chat and boast with others, you don't lose it (⊙ o ⊙)

Interview topics

What is distributed lock?

First, in order to ensure the availability of distributed locks, at least the following three conditions must be met

  1. Mutex. At any time, only one client can hold the lock
  2. No deadlock occurs. Even if one client runs away without actively unlocking while holding the lock, it can ensure that other subsequent clients can lock
  3. Whoever unties the bell must tie it. Locking and unlocking must be the same client. The client cannot unlock the lock added by others

How to implement distributed locking?

Both implementations are described below

  1. Using lua script to operate distributed locks
  2. The distributed lock is realized by using setnx and setex commands together

Distributed lock scenario

What is distributed lock?

  • Distributed lock is a lock implementation that controls distributed systems or common access to shared resources between different systems
  • If different systems or different hosts of the same system share a resource, mutual exclusion is often used to prevent mutual interference

Why distributed locks? [#](

)

It can ensure that in the distributed application cluster, the same method can only be executed by one thread on * * * * one machine.

Design requirements [#](

)

  1. Reentrant lock (avoid deadlock)
  2. Acquire and release locks are highly available
  3. Acquire and release locks high performance

Implementation scheme [#](

)

  1. To obtain the lock, use setnx(): SETNX key val: if and only if the key does not exist, set a string with key val and return 1
  2. If the key exists, nothing will be done, and [0] will be returned to lock. The value of the lock is the intranet IP number of the current lock server and the splicing task ID
  3. Judge when releasing the lock. And use the expire command to add a timeout time for the lock. If the timeout time is exceeded, the lock will be released automatically
  4. If 1 is returned, the lock is successfully obtained. It also sets a timeout time for acquiring. If it exceeds this time, the acquisition lock will be abandoned. The expiration of setex(key,value,expire) is in seconds
  5. When releasing the lock, judge whether it is the lock (that is, value is the intranet IP number of the current server and the splicing task ID). If it is the lock, execute delete to release the lock

Redis distributed lock implementation [#](

)

Create a SpringBoot project [#](

)

website: https://start.spring.io/

Step [#](

)

1. Annotate the startup class with @ enableshcheduling

2. Annotate the execution method @ Scheduled

Package and upload to Linux server to start [#](

)

Prepare three Linux servers, upload the jar packages to the three servers, and then start

Persistent startup mode of nohub [#](

)

nohup java -jar jar name  &

Check whether all clusters in the cluster are started successfully

1,Install first lsof: yum install lsof 2,verification: lsof -i:8080

TCP triple handshake [#](

)

View local TCP connection status [#](

)

 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

Why three handshakes? [#](

)

It is mainly to prevent the invalid connection request message segment from being suddenly transmitted to B, so the message is disordered. It is assumed that the first connection request message segment sent by A is not lost, but stays in some network nodes for A long time, and does not arrive at B until A certain time after the connection is released. Originally, this is an already invalid message segment. However, after receiving the invalid connection request message segment, B mistakenly thinks that A sends A new connection request, so it sends A confirmation message segment to A and agrees to establish A connection.

Assuming that the triple handshake is not used, as long as B sends A confirmation, the new connection will be established. In this way, it has been waiting for A to send data, and many resources of B are wasted.

Illustration [#](

)

I shook hands three times. Why did I wave four times? [#](

)

Waving for the first time: the active closing party sends a fin to close the data transmission from the active party to the passive Closing Party, that is, the active Closing Party tells the passive closing party that I will no longer send you data (of course, if the data sent before the fin packet does not receive the corresponding ack confirmation message, the active closing party will still resend these data), but, At this time, the active shutdown party can also accept data.
Second wave: after receiving the FIN packet, the passive closing party sends an ACK to the other party, and the confirmation sequence number is the received sequence number + 1 (the same as SYN, one FIN occupies one sequence number).
The third wave: the passive closing party sends a FIN to close the data transmission from the passive closing party to the active Closing Party, that is, tell the active closing party that my data has been sent and will not send data to you again.
Fourth wave: after receiving FIN, the active closing party sends an ACK to the passive Closing Party, and confirms that the serial number is received serial number + 1. So far, four waves are completed.

Function [#](

)

Ensure complete data transmission

Redis distributed lock implementation source code explanation [#](

)

Graphic explanation [#](

)

Step [#](

)

  1. Distributed locks meet two conditions: one is the lock with effective time, and the other is high-performance unlocking
  2. redis commands setnx (set if not exist) and setex (set expire value) are used
  3. The unlocking process cannot be omitted, otherwise the task will never expire when it is executed once
  4. Put the locking code and task logic into the try catch code block, and the unlocking process into the finally code block

Project structure [#](

)

pom.xml[#](

)

<?xml version="1.0" encoding="UTF-8"?>    4.0.0    org.springframework.boot  spring-boot-starter-parent  2.3.3.RELEASE    
     com.cyb  yb-mobile-redis  0.0.1-SNAPSHOT  yb-mobile-redis  Demo project for Spring Boot    

application.properties[#](

)

spring.redis.database=0 spring.redis.host=192.168.199.142 spring.redis.port=6379 spring.redis.password=12345678 server.port=9001

RedisService.java[#](

)

package com.cyb.ybmobileredis.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.*; import org.springframework.stereotype.Service; import java.io.Serializable; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; /** * @ClassName: RedisService
 * @Description: TODO
 * @Author: chenyb
 * @Date: 2020/8/16 5:39 afternoon
 * @Versiion: 1.0 */ @Service public  class RedisService  {  @Autowired private RedisTemplate redisTemplate; private  static  double size =  Math.pow(2,  32); /** * Write cache
     *
     * @param key
     * @param offset   Bit 8Bit=1Byte
     * @return  */  public  boolean setBit(String key,  long offset,  boolean isShow)  { boolean result =  false; try {  ValueOperations

LockNxExJob.java[#](

)

package com.cyb.ybmobileredis.schedule; import com.cyb.ybmobileredis.service.RedisService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.util.Enumeration; /** * @ClassName: LockNxExJob
 * @Description: Distributed lock acquisition and release
 * @Author: chenyb
 * @Date: 2020/8/16 5:44 afternoon
 * @Versiion: 1.0 */ @Service public  class LockNxExJob  { private  static  final  Logger logger =  LoggerFactory.getLogger(LockNxExJob.class);  @Autowired private RedisService redisService;  @Autowired private RedisTemplate redisTemplate; private  static  String LOCK_PREFIX =  "prefix_";  @Scheduled(fixedRate =  8000) public  void lockJob()  {  String  lock = LOCK_PREFIX +  "LockNxExJob"; boolean nxRet=false; try{ //redistemplate setnx operation nxret = redistemplate opsForValue(). setIfAbsent(lock,getHostIp());   Object lockValue = redisService. get(lock);   System. out. println(lockValue); // Failed to obtain lock if (! Nxret) {string value = (string) redisservice.get (lock); / / print the server IP logger.info (system. Currenttimemillis() + "get lock fail, lock long to: {}", value) currently occupying the lock; return;  } Else {redistemplate. Opsforvalue(). Set (lock, gethostip(), 3600); / / successful lock acquisition logger.info (system. Currenttimemillis() + "start lock locknxexjob success"); thread.sleep (4000);}} catch (Exception e){ logger.error("lock error",e);  } Finally {if (nxret) {system.out.println ("lock released successfully"); redisService.remove(lock);}}} / * ** Method for obtaining local intranet IP address
     * @return  */  private  static String getHostIp(){ try{  Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces(); while (allNetInterfaces.hasMoreElements()){  NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();  Enumeration addresses = netInterface.getInetAddresses(); while (addresses.hasMoreElements()){  InetAddress ip = (InetAddress) addresses.nextElement(); if  (ip !=  null  && ip instanceof Inet4Address &&  !ip.isLoopbackAddress()  //Loopback address is the local address. The loopback range of IPv4 is 127.0 0.0 ~ 127.255. 255.255  && ip. getHostAddress(). indexOf(":")==-1){ return ip.getHostAddress();  }  }  }  } catch(Exception e){ e.printStackTrace();  }  return  null;  }  }

Verify [#](

)

Run one jar on Linux, one locally, one successfully obtains the lock, and the other fails to obtain the lock

Possible problems with Redis distributed locks [#](

)

We have implemented the distributed lock function with code above. Only one lock can be successfully obtained at the same time. It can be seen from the above figure that in extreme cases, after the first Server successfully obtains the lock, the service or Redis goes down, which will lead to the problem that the Redis lock cannot be released, and other servers always fail to obtain the lock.

Simulate server acquisition lock downtime [#](

)

First run the project and obtain the lock, immediately kill -9 process id and kill the current process. Then, when running the project, the console will always prompt that obtaining the lock failed.

Solutions (key) [#](

)

  1. If you execute one command at a time, this will not happen. Use Lua script
  2. Since 2.6, Redis supports the combination of setnx and setex

lua script [#](

)

  1. Add a suffix to the redource directory lua ending file
  2. Writing lua scripts
  3. key and arg passed in lua script
  4. Call redistemplate The execute method executes the script

Writing lua scripts

local lockKey = KEYS[1]  local lockValue = KEYS[2] -- setnx info local result_1 = redis.call('SETNX',lockKey,lockValue) if result_1 ==  true then  local result_2 = redis.call('SETEX',lockKey,3600,lockValue) return result_1 else  return result_1 end

Encapsulate and call lua script methods

last

Before the interview, you must brush the questions. In order to facilitate your review, I share a collection of personal interviews

CodeChina open source project: [analysis of Java interview questions of front-line large manufacturers + core summary learning notes + latest explanation Video]

  • Java core knowledge sorting

Java core knowledge

  • Spring family bucket (Practical Series)

  • Other e-book materials

Step 3: Brush questions

Since it's an interview, I have to brush questions. In fact, I can't go anywhere after the Spring Festival. I brush a lot of interview questions myself, so I can know what knowledge points and high-frequency questions will be asked in the interview process. Therefore, brushing questions is a very important point in the early preparation of the interview.

The following is my private interview question bank:

Spring family bucket (Practical Series)

[external chain picture transferring... (IMG ovuoqrz8-1630306228601)]

  • Other e-book materials

[external chain picture transferring... (img-FYm6fPfp-1630306228602)]

Step 3: Brush questions

Since it's an interview, I have to brush questions. In fact, I can't go anywhere after the Spring Festival. I brush a lot of interview questions myself, so I can know what knowledge points and high-frequency questions will be asked in the interview process. Therefore, brushing questions is a very important point in the early preparation of the interview.

The following is my private interview question bank:

[external chain picture transferring... (img-231cxDEZ-1630306228602)]

Topics: Java Redis Back-end lua