当前位置:网站首页>Customize redis connection pool
Customize redis connection pool
2022-07-02 09:21:00 【niceyz】
A big factory interview question : Examine the service design and some interface requirements .
Interface II problem solving , Demand one Current limiting ; Requirement 2 Interface idempotent ; Requirement 3 Network programming timeout setting ; Requirement 4 Current limiting ;
Demand five solve HttpClient Thread safety problem , Idea customization HttpClient Connection pool .
Wrong writing : In a concurrent scenario , Come on 1000 Requests , establish 1000 Secondary connection , Connection overhead is fatal .
We use it socket Define a httpclient, Let's demonstrate socket Thread insecurity :
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* Description: Socket The network is connected to redis, Need to use redis Protocol to connect
* Author: yz
* Date: Created in 2021/1/6 11:14
*/
public class Connetion {
private String host;
private int post;
private Socket socket; // Thread unsafe
private InputStream inputStream;
private OutputStream outputStream;
public Connetion(String host, int post) {
this.host = host;
this.post = post;
}
/**
* Determine whether the connection has been established , Determine whether the connection is initialized , Or the connection is not disconnected
*/
public boolean isConnection(){
if(socket !=null && inputStream !=null && socket.isClosed()){
return true;
}
try {
socket = new Socket(host,post);
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* dispatch orders
*/
public String sendCommand(byte[] command){
if(isConnection()){
try {
// The client writes data first
outputStream.write(command);
// Read server response
byte[] res = new byte[1024];
int length = 0;
while ((length=inputStream.read(res))>0){
return new String(res,0,length);
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
/**
* Description: redis Protocol tool class
* Author: yz
* Date: Created in 2021/1/6 11:41
*/
public class RedisProtocolUtils {
public static final String DOLIER = "$";
public static final String ALLERTSTIC = "*";
public static final String CRLE = "\r\n";
public static byte[] buildRespByte(Command command,byte[]... bytes){
StringBuilder sb = new StringBuilder();
sb.append(ALLERTSTIC).append(bytes.length+1).append(CRLE);
sb.append(DOLIER).append(command.name().length()).append(CRLE);
sb.append(command.name()).append(CRLE);
for (byte[] arg : bytes) {
sb.append(DOLIER).append(arg.length).append(CRLE);
sb.append(new String(arg)).append(CRLE);
}
return sb.toString().getBytes();
}
/**
* redis set,get command
*/
public enum Command{
SET,GET
}
}
/**
* Description:
* Author: yz
* Date: Created in 2021/1/6 15:01
*/
public class ClientRunalbe implements Runnable {
private BatRedisClient client;
private String value;
public ClientRunalbe(BatRedisClient client, String value) {
this.client = client;
this.value = value;
}
@Override
public void run() {
client.set("ant",value);
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description: redis The connection client contains redis The protocol and socket
* Author: yz
* Date: Created in 2021/1/6 11:53
*/
public class BatRedisClient {
private Connetion connetion;
public BatRedisClient(String host,int port){
connetion = new Connetion(host,port);
}
public String set(String key,String value){
String result = connetion.sendCommand(
RedisProtocolUtils.buildRespByte(RedisProtocolUtils.Command.SET,key.getBytes(),value.getBytes()));
System.out.println("Thread name:"+Thread.currentThread().getName()
+"[result]:"+result.replace("\r\n","")+"[value]:"+value);
return result;
}
public String get(String key){
String result = connetion.sendCommand(
RedisProtocolUtils.buildRespByte(RedisProtocolUtils.Command.GET,key.getBytes(),key.getBytes()));
return result;
}
public static void main(String[] args) {
BatRedisClient client = new BatRedisClient("localhost",6379);
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 20; i++) {
// Existing phenomenon : The current thread reads redis Response data returned to other threads
pool.execute(new ClientRunalbe(client,"123"+i));
}
}
}
perform mian Method test ,20 Threads executing concurrently , give the result as follows :1, Not implemented 20 Time ,2,redis The returned results are sticky , In fact, one request gets the result of another request
1, Not implemented 20 Time : Multiple threads share one socket, When a thread is half written ,cpu The time slice is used up when scheduling , The second thread gets cup Time slice , Data will also be written , These unfinished data will also be redis Read , But it cannot be parsed ,redis Can't return response , The thread cannot read the response , Get into io Blocking .
2,redis The returned results are sticky : The amount of data sent is relatively small , The packets sent by the thread are complete , Give to the redis Then it can be parsed into two requests , It is also normal to return data , If a thread 1 Get cup Right to use , stay read When reading data , You may read all the data in the buffer at one time , After parsing, it is found that +OK+OK This is the form
Use custom thread pool to solve socket Multithreading is unsafe , hold client Objects in the pool In the pool
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque; // The bidirectional queue
import java.util.concurrent.LinkedBlockingQueue; // One way queue
/**
* Description: redis Connection pool
* Author: yz
* Date: Created in 2021/1/6 15:19
*/
public class RedisClientPool {
private List<BatRedisClient> allObject;
private LinkedBlockingQueue<BatRedisClient> linkedBlockingQueue;
public RedisClientPool(String host,int port,int connectionCount){
allObject = new ArrayList<>();
this.linkedBlockingQueue = new LinkedBlockingQueue<>(10);
for (int i = 0; i < connectionCount; i++) {
BatRedisClient client = new BatRedisClient(host,port);
linkedBlockingQueue.add(client);
allObject.add(client);
}
}
/**
* obtain client Connect
*/
public BatRedisClient getClient(){
try {
return linkedBlockingQueue.take(); // or poll
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
/**
* take client Return to connection pool
*/
public void returnClient(BatRedisClient client){
if(client == null){
return;
}
if(!allObject.contains(client)){
throw new IllegalStateException(
"Returned object not currently part of this pool");
}
try {
linkedBlockingQueue.put(client);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* Description: Use customization redis Connection pool
* Author: yz
* Date: Created in 2021/1/6 15:28
*/
public class ClientPoolRunable implements Runnable {
private RedisClientPool pool;
private String value;
public ClientPoolRunable(RedisClientPool pool, String value) {
this.pool = pool;
this.value = value;
}
@Override
public void run() {
BatRedisClient client = pool.getClient();
client.set("ant",value);
pool.returnClient(client);
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description: test redis Connection pool
* Author: yz
* Date: Created in 2021/1/6 15:30
*/
public class Main {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
RedisClientPool redisClientPool = new RedisClientPool("localhost",6379,10);
for (int i = 0; i < 20; i++) {
pool.execute(new ClientPoolRunable(redisClientPool,"123"+i));
}
}
}
perform main Method test , give the result as follows , Just in time for 20 Time , No more +OK+OK There is a phenomenon
Expanding knowledge : queue
边栏推荐
- Sentinel reports failed to fetch metric connection timeout and connection rejection
- [go practical basis] how to bind and use URL parameters in gin
- Machine learning practice: is Mermaid a love movie or an action movie? KNN announces the answer
- Oracle delete tablespace and user
- MYSQL安装出现问题(The service already exists)
- Programmers with ten years of development experience tell you, what core competitiveness do you lack?
- Talk about the secret of high performance of message queue -- zero copy technology
- 【Go实战基础】gin 如何自定义和使用一个中间件
- 知识点很细(代码有注释)数构(C语言)——第三章、栈和队列
- Hengyuan cloud_ Can aiphacode replace programmers?
猜你喜欢
Say goodbye to 996. What are the necessary plug-ins in idea?
[go practical basis] how to customize and use a middleware in gin
机器学习实战:《美人鱼》属于爱情片还是动作片?KNN揭晓答案
hystrix 实现请求合并
Solution to amq4036 error in remote connection to IBM MQ
西瓜书--第五章.神经网络
Matplotlib swordsman Tour - an artist tutorial to accommodate all rivers
《统计学习方法》——第五章、决策树模型与学习(上)
Troubleshooting and handling of an online problem caused by redis zadd
[staff] time sign and note duration (full note | half note | quarter note | eighth note | sixteenth note | thirty second note)
随机推荐
破茧|一文说透什么是真正的云原生
Multi version concurrency control mvcc of MySQL
微服务实战|熔断器Hystrix初体验
During MySQL installation, mysqld Exe reports that the application cannot start normally (0xc000007b)`
View the port of the application published by was
Gocv image cutting and display
JVM instruction mnemonic
CSDN Q & A_ Evaluation
Function ‘ngram‘ is not defined
Knife4j 2.X版本文件上传无选择文件控件问题解决
Long summary (code with comments) number structure (C language) -- Chapter 4, string (Part 1)
From concept to method, the statistical learning method -- Chapter 3, k-nearest neighbor method
知识点很细(代码有注释)数构(C语言)——第三章、栈和队列
Leetcode sword finger offer brush questions - day 23
Win10 uses docker to pull the redis image and reports an error read only file system: unknown
我服了,MySQL表500W行,居然有人不做分区?
Insight into cloud native | microservices and microservice architecture
Oracle modify database character set
Chrome用户脚本管理器-Tampermonkey 油猴
【Go实战基础】gin 如何自定义和使用一个中间件