【笔记】千万并发-单机41万QPS-Redis-lettuce实践

服务端准备

虚拟机规格

Redis服务启动

tcp调优

root@ubuntu01:/home/zwb# sysctl -p
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_rmem = 4096 8738000 8738000
net.core.rmem_default = 133201920
net.core.rmem_max = 133201920
net.ipv4.tcp_mem = 44379 524208  524288
net.core.wmem_default = 87380000
net.core.wmem_max = 133201920
net.ipv4.tcp_wmem = 4096 87380000  87380000
net.ipv4.tcp_max_reordering = 1024
net.ipv4.tcp_reordering = 1024
net.ipv4.ipfrag_high_thresh = 41943040
net.ipv4.ipfrag_low_thresh = 31457280
net.ipv4.ipfrag_max_dist = 640
net.ipv4.ipfrag_secret_interval = 0
net.ipv4.ipfrag_time = 30
net.core.netdev_max_backlog = 1000000
net.core.optmem_max = 131072000
net.ipv4.tcp_retries1 = 15
net.ipv4.tcp_retries2 = 15
fs.file-max = 10000000
net.core.somaxconn = 10000000
net.ipv4.tcp_max_syn_backlog = 10000000
net.ipv4.tcp_abort_on_overflow = 1
net.ipv4.tcp_max_orphans = 128000

客户端准备

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>RedisTemplateTest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>3.3.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>5.1.4</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j2-impl -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
            <version>2.23.1</version>
<!--            <scope>test</scope>-->
        </dependency>

        <!-- https://mvnrepository.com/artifact/io.lettuce/lettuce-core -->
        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
            <version>6.4.0.RELEASE</version>
        </dependency>





    </dependencies>

</project>

org.example.LettcueNative

这里的代码用了4个连接,其实多次压测后,用1个连接压测也能稳定在40万QPS,连接数不是瓶颈,1个连接就能满足高并发要求。

package org.example;

import io.lettuce.core.ClientOptions;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisFuture;
import io.lettuce.core.SocketOptions;
import io.lettuce.core.api.async.RedisStringAsyncCommands;
import io.lettuce.core.api.StatefulRedisConnection;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class LettcueNative {


    private static final ExecutorService printer = Executors.newFixedThreadPool(1,
            (r)->{
                Thread thread = new Thread(r);
                thread.setName("Thread-printer-" + thread.getId());
                return thread;
            });

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        int requests = args.length > 0 ? Integer.parseInt(args[0]) : 1000 ;

        RedisClient redisClient = RedisClient.create("redis://192.168.253.176:6379");


        SocketOptions socketOptions = SocketOptions.builder()
                .tcpNoDelay(false)
                .build();

        ClientOptions options = ClientOptions.builder()
                .socketOptions(socketOptions)
                .build();
        redisClient.setOptions(options);


        StatefulRedisConnection<String, String> connection1 = redisClient.connect();
        StatefulRedisConnection<String, String> connection2 = redisClient.connect();
        StatefulRedisConnection<String, String> connection3 = redisClient.connect();
        StatefulRedisConnection<String, String> connection4 = redisClient.connect();
//        StatefulRedisConnection<String, String> connection5 = redisClient.connect();

        RedisStringAsyncCommands<String, String> asyncCommands1 = connection1.async();
        RedisStringAsyncCommands<String, String> asyncCommands2 = connection2.async();
        RedisStringAsyncCommands<String, String> asyncCommands3 = connection3.async();
        RedisStringAsyncCommands<String, String> asyncCommands4 = connection4.async();
//        RedisStringAsyncCommands<String, String> asyncCommands5 = connection5.async();

        RedisStringAsyncCommands<String, String>[] asyncCommandsArray =
                new RedisStringAsyncCommands[]{
                        asyncCommands1, asyncCommands2, asyncCommands3, asyncCommands4};

        // 异步设置键值对
        RedisFuture<String> setFuture = asyncCommands1.set("count", "0");

        setFuture.thenAccept(result -> {
            System.out.println("Key 'count' set successfully.");
        }).exceptionally(ex -> {
            System.out.println("Error occurred while setting key: " + ex.getMessage());
            return null;
        });

        // 异步获取键对应的值
        RedisFuture<String> getFuture2 = asyncCommands2.get("count");
        RedisFuture<String> getFuture3 = asyncCommands3.get("count");
        RedisFuture<String> getFuture4 = asyncCommands4.get("count");
//        RedisFuture<String> getFuture5 = asyncCommands4.get("count");

        getFuture2.thenAccept(value -> {
            System.out.println("Value for count: " + value);
        }).exceptionally(ex -> {
            System.out.println("Error occurred while getting key: " + ex.getMessage());
            return null;
        });

        // 等待所有异步操作完成
        getFuture2.get();
        getFuture3.get();
        getFuture4.get();
//        getFuture5.get();


        int size = asyncCommandsArray.length;

        CountDownLatch latch = new CountDownLatch(requests);
//        AtomicInteger backpressure = new AtomicInteger(100);
        long begin = System.currentTimeMillis();
        for (int i = 0; i < requests; i++) {

            RedisFuture<Long> count = asyncCommandsArray[requests % size].incr("count");
//            backpressure.decrementAndGet();

            count.thenAccept(result -> {
//                backpressure.incrementAndGet();
                latch.countDown();
                printer.execute(()->{
                    if( result % 100000 == 0 ) {
                        System.out.println("count: " + result);
                    }
                });
            });

//            if( backpressure.get() < 0 )
//            {
//                Thread.yield();
//            }
        }
        latch.await();
        long end = System.currentTimeMillis();

        long delta = end - begin;

        Thread.sleep(1000);

        System.out.println("总计" + requests+"次请求");
        System.out.println("总计耗时" + delta + "ms");
        System.out.println("平均耗时" + delta / requests + "ms");
        System.out.println("QPS:" + requests * 1000L / delta);


        connection1.close();
        connection2.close();
        redisClient.shutdown();

        System.exit(0);
    }

}

运行配置

10000000次并发请求

压测结果

猜你喜欢

转载自blog.csdn.net/shumeizwb/article/details/140894701