当前位置:网站首页>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

边栏推荐
- Webflux responsive programming
- Dix ans d'expérience dans le développement de programmeurs vous disent quelles compétences de base vous manquez encore?
- 以字节跳动内部 Data Catalog 架构升级为例聊业务系统的性能优化
- A detailed explanation takes you to reproduce the statistical learning method again -- Chapter 2, perceptron model
- 队列管理器running状态下无法查看通道
- 长篇总结(代码有注释)数构(C语言)——第四章、串(上)
- 京东面试官问:LEFT JOIN关联表中用ON还是WHERE跟条件有什么区别
- Programmers with ten years of development experience tell you, what core competitiveness do you lack?
- 【Go实战基础】gin 如何设置路由
- gocv opencv exit status 3221225785
猜你喜欢

Watermelon book -- Chapter 6 Support vector machine (SVM)

机器学习实战:《美人鱼》属于爱情片还是动作片?KNN揭晓答案

京东面试官问:LEFT JOIN关联表中用ON还是WHERE跟条件有什么区别

深入剖析JVM是如何执行Hello World的

Matplotlib swordsman line - layout guide and multi map implementation (Updated)
![[go practical basis] how to set the route in gin](/img/23/f38d68c4fd238d453b9a7670483002.png)
[go practical basis] how to set the route in gin

【Go实战基础】gin 如何绑定与使用 url 参数

微服务实战|熔断器Hystrix初体验

队列管理器running状态下无法查看通道

Chrome浏览器标签管理插件–OneTab
随机推荐
[staff] time mark and note duration (staff time mark | full note rest | half note rest | quarter note rest | eighth note rest | sixteenth note rest | thirty second note rest)
Redis installation and deployment (windows/linux)
【Go实战基础】如何安装和使用 gin
Knife4j 2.X版本文件上传无选择文件控件问题解决
微服务实战|原生态实现服务的发现与调用
C4D quick start tutorial - C4d mapping
Matplotlib swordsman line - first acquaintance with Matplotlib
数构(C语言)——第四章、矩阵的压缩存储(下)
【Go实战基础】gin 如何获取 GET 和 POST 的请求参数
Chrome video download Plug-in – video downloader for Chrome
Talk about the secret of high performance of message queue -- zero copy technology
"Redis source code series" learning and thinking about source code reading
微服务实战|熔断器Hystrix初体验
Micro service practice | introduction and practice of zuul, a micro service gateway
How to realize asynchronous programming in a synchronous way?
远程连接IBM MQ报错AMQ4036解决方法
知识点很细(代码有注释)数构(C语言)——第三章、栈和队列
《统计学习方法》——第五章、决策树模型与学习(上)
[go practical basis] how to verify request parameters in gin
During MySQL installation, mysqld Exe reports that the application cannot start normally (0xc000007b)`