zoukankan      html  css  js  c++  java
  • Redis调用Lua脚本并测试

    一、为什么使用Lua脚本

        为了一次通信执行多个Redis命令,我们可以用pipline ,但是多个命令间没有逻辑联系 。
        Lua脚本可以一次通信执行多个Redis命令,而且内部可以写自己的逻辑,整个脚本执行是原子性的。
     二、命令行调用Lua脚本
    EVAL script numkeys key [key ...] arg [arg ...]
    
    redis 127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second

    三、Lua脚本文件执行

      1)保存脚本文件为ip_control.lua,用作IP控制的脚本

      

    local times = redis.call('incr',KEYS[1])
    if times == 1 then
        redis.call('expire',KEYS[1], ARGV[1])
    end
    if times > tonumber(ARGV[2]) then
        return 0
    end
    return 1

    2)redis客户端执行脚本

    多次执行此脚本则会触发限流,返回值为0
    redis-cli -h localhost -p 6381 --eval /root/ip_control.lua rate_limit:127.0.0.1 ,  60  3
    
    -h 服务器IP 
    -p 服务器端口
    执行脚本: /root/ip_control.lua
    
    保存的Key: rate_limit:127.0.0.1
    数据存放时间60s则超时 , 限流的数量为3

    四、Java调用Lua脚本进行数据量控制-我用的是spring中的 RedisTemplate,所以里面引入了spring相关的包

        1)maven中的jar引入

    <?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>com.test</groupId>
      <artifactId>test111</artifactId>
      <version>1.0-SNAPSHOT</version>
    
    
      <name>test111</name>
      <!-- FIXME change it to the project's website -->
      <url>http://www.example.com</url>
    
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    
    
      </properties>
    
    
      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
      </parent>
    
    
      <dependencies>
    
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter</artifactId>
        </dependency>
    
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    
    
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>com.squareup.okhttp3</groupId>
          <artifactId>okhttp</artifactId>
          <version>4.2.2</version>
        </dependency>
    
    
        <dependency>
          <groupId>com.google.guava</groupId>
          <artifactId>guava</artifactId>
          <version>27.0.1-jre</version>
        </dependency>
        <dependency>
          <groupId>joda-time</groupId>
          <artifactId>joda-time</artifactId>
          <version>2.10.5</version>
        </dependency>
    
    
        <dependency>
          <groupId>org.testng</groupId>
          <artifactId>testng</artifactId>
          <version>6.10</version>
          <scope>test</scope>
        </dependency>
    
    
        <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-lang3</artifactId>
          <version>3.4</version>
        </dependency>
    
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
          <exclusions>
            <exclusion>
              <groupId>io.lettuce</groupId>
              <artifactId>lettuce-core</artifactId>
            </exclusion>
          </exclusions>
        </dependency>
        <dependency>
          <groupId>redis.clients</groupId>
          <artifactId>jedis</artifactId>
        </dependency>
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-pool2</artifactId>
          <version>2.4.3</version>
        </dependency>
    
    
        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
          <groupId>commons-io</groupId>
          <artifactId>commons-io</artifactId>
          <version>2.7</version>
        </dependency>
    
      </dependencies>
      <profiles>
        <profile>
          <id>dev</id>
          <properties>
            <profiles.active>dev</profiles.active><!--开发环境 -->
          </properties>
          <activation>
            <activeByDefault>true</activeByDefault>
          </activation>
        </profile>
    
    
        <profile>
          <id>test</id>
          <properties>
            <profiles.active>test</profiles.active><!--测试环境 -->
          </properties>
        </profile>
    
    
        <profile>
          <id>prod</id>
          <properties>
            <profiles.active>prod</profiles.active><!--生产环境 -->
          </properties>
        </profile>
      </profiles>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
              <mainClass>test.Server</mainClass>
            </configuration>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <source>${java.version}</source>
              <target>${java.version}</target>
              <encoding>${project.build.sourceEncoding}</encoding>
              <showWarnings>true</showWarnings>
              <showDeprecation>true</showDeprecation>
    
    
            </configuration>
          </plugin>
        </plugins>
        <resources>
          <resource>
            <directory>src/main/properties</directory>
            <filtering>true</filtering>
            <excludes>
              <exclude>application.properties</exclude>
              <!--          <exclude>application-dev.properties</exclude>
                        <exclude>application-test.properties</exclude>
                        <exclude>application-product.properties</exclude>-->
            </excludes>
          </resource>
    
          <resource>
            <directory>src/main/properties</directory>
            <filtering>true</filtering>
            <includes>
              <include>application.properties</include>
              <include>ip_control.lua</include>
              <include>application-${profiles.active}.properties</include>
            </includes>
          </resource>
        </resources>
    
      </build>
    
    </project>
    2)spring的配置文件-application.properties
    这里是哨兵模式引入的
    ####redis的配置信息###
    spring.redis.sentinel.master=mymaster
    spring.redis.sentinel.nodes=192.168.112.131:26379,192.168.112.131:26380,192.168.112.131:26381
    spring.redis.password=
    #采用哪个数据库
    spring.redis.database=0
    # 连接池最大连接数,默认8个,(使用负值表示没有限制)
    spring.redis.pool.max-active=8
    # 连接池最大阻塞等待时间(使用负值表示没有限制)
    spring.redis.pool.max-wait=-1
    # 连接池中的最大空闲连接
    spring.redis.pool.max-idle=8
    # 连接池中的最小空闲连接
    spring.redis.pool.min-idle=0
    # 连接超时时间(毫秒)
    spring.redis.timeout=0

    3)使用redisTemplate调用脚本

    @SpringBootTest
    @RunWith(SpringRunner.class) 
    public class RedisTest
    {
    
        @Resource
        private RedisTemplate redisTemplate;
    
    
        @Test
        public void test2(){
            String luaIpControl = null;
            try {
                //文件路径也可以使用相对路径
                luaIpControl = FileUtils.readFileToString(new File("E:\github\test2\target\classes\ip_control.lua"),"utf-8");
                //RedisTest.class.getClassLoader().getResourceAsStream("ip_control.lua");
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println( luaIpControl );
    
            String key = "rate_limit:127.0.0.1";
            Integer expire = 30;
            Integer maxVisit = 10 ;
            Long result = null;
            for (int i = 0; i < 11; i++) {
                result = invokScript( key , expire ,maxVisit , luaIpControl);
            }
    
            System.out.println( result );
        }
    
    
        public   Long invokScript(String key, int expire ,int maxVisit, String script) {
            // 脚本里的KEYS参数
            List<String> keys = new ArrayList<>();
            keys.add(key);
            // 脚本里的ARGV参数
            List<String> args = new ArrayList<>();
            args.add(Integer.toString(expire));
            args.add(Integer.toString(maxVisit));
    
    
            Long result = (long) redisTemplate.execute(new RedisCallback<Long>() {
                @Override
                public Long doInRedis(RedisConnection connection) throws DataAccessException {
                    Object nativeConnection = connection.getNativeConnection();
                    // 集群模式和单机模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行
                    // 集群模式
                    if (nativeConnection instanceof JedisCluster) {
                        return (Long) ((JedisCluster) nativeConnection).eval(script, keys, args);
                    }
    
    
                    // 单机模式
                    else if (nativeConnection instanceof Jedis) {
                        return (Long) ((Jedis) nativeConnection).eval(script, keys, args);
                    }
                    /*else if (nativeConnection instanceof Redisson) {
                        Redisson redisson = (Redisson)nativeConnection;
                        return redisson.getScript().eval(RScript.Mode.READ_WRITE,STOCK_LUA,RScript.ReturnType.INTEGER, Collections.singletonList(keys), new List[]{args});
                    }*/
                    return null;
                }
            });
            return result;
        }
    
    
        @Test
        public void test1(){
            redisTemplate.opsForValue().set("name","wang" ,100 ,TimeUnit.SECONDS);
    
            String str = (String) redisTemplate.opsForValue().get("name");
            System.out.println( str );
        }
    }
  • 相关阅读:
    Atitit 网络技术体系图 目录 1. 的三网融合是 1 1.1. 电话网、有线电视网 1 1.2. 计算机网 1 2. 计算机网 1 2.1. 互联网 1 2.2. 局域网 1 3. 第1章 计
    Atitit 非结构化数据管理法 目录 1. 什么是非结构化数据? 1 2. 对非结构化数据也即对全文数据的搜索主要有两种方法: 2 2.1. 顺序扫描法(Serial Scanning): 2 2
    Atitit 可视化技术体系题 目录 1. 1. 可视化分类 1 1 1.1. 1.1. 层次可视化 金字塔等 层次降为3层归类可视化 1 1 1.2. 1.2. 高层可视化 鸟瞰可视化 1 1 1
    Atitit 持久化与数据存储标准化规范 目录 1. 存储的附加功能 2 1.1. 基本存取功能 2 1.2. 全文检索(imap 2 1.3. 属性检索 2 1.4. 查询语言 2 2. 基于内容
    Atitit 数据库技术体系 艾提拉总结 目录 1. 2. 初始概念 5 2 1.1. 2.1. 数据库的类型,网状,层次,树形数据库,kv数据库。Oodb 多媒体数据库 5 2 1.2. 2.2.
    Atitit 大数据体系图 大数据 技术 数据采集 gui自动化 爬虫 Nui自动化  Ocr技术 Tts语音处理 文档处理(office zip等) html文档处理解析 转
    Atitit 数据挖掘技术体系 目录 1. 统计分析(分组聚合等 1 2. Tag标注 结构化 1 2.1. · 复杂数据类型挖掘(Text, Web 2 2.2. ,图形图像,视频,音频等) 2
    Atitit  信息管理 艾提拉著 CAPT2 数据存储与分类 聚集.docx 目录 1. 按照存储位置 1 1.1. 网盘 1 1.2. 存储在eml imap中 方便检索 1 1.3. 分散与
    Atitit  信息管理 艾提拉著作 CAPT1信息源数据源 目录 1. 数据元的数据格式 图片 文本 视频 音频 2 2. 按照应用功能使用分类 2 2.1. Diary Cyarlog 2
    Atitit 计算软件简史 艾提拉著 目录 1.1. 第二代软件(1959~1965) 高级语言 第三代软件(1965~1971) os 1 1.2. 第四代软件(1971~1989)结构化的程序
  • 原文地址:https://www.cnblogs.com/lean-blog/p/14149569.html
Copyright © 2011-2022 走看看