Redis调用Lua脚本并测试

   2023-02-09 学习力0
核心提示:一、为什么使用Lua脚本    为了一次通信执行多个Redis命令,我们可以用pipline ,但是多个命令间没有逻辑联系 。    Lua脚本可以一次通信执行多个Redis命令,而且内部可以写自己的逻辑,整个脚本执行是原子性的。 二、命令行调用Lua脚本EVAL script numk

一、为什么使用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 );
    }
}

 

 

 

 

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • LUA解析json小demo
    需要修改的json数据gui-config.json{"configs": [{"server": "JP3.ISS.TF","server_port": 443,"password": "58603228","method": "aes-256-cfb","remarks": ""},{"serv
    03-16
  • 第二十三篇:在SOUI中使用LUA脚本开发界面
    像写网页一样做客户端界面可能是很多客户端开发的理想。做好一个可以实现和用户交互的动态网页应该包含两个部分:使用html做网页的布局,使用脚本如vbscript,javascript做用户交互的逻辑。当需求变化时,只需要在服务端把相关代码调整一下,用户即可看到新的
    03-16
  • windows下编译lua源码"><转>windows下编译lua源
    因为之前一直使用 lua for windows 来搭建lua的使用环境,但是最新的 lua for windows 还没有lua5.2,我又想用这个版本的lua,所以被逼无奈只能自己编一下lua源码。首先从 lua的官网 下载你想要使用的lua源码,比如我下载的就是lua5.2。解压后内容如下:
    03-16
  • lua:使用Lua处理游戏数据
    在之前lua学习:lua作配置文件里,我们学会了用lua作配置文件。其实lua在游戏开发中可以作为一个强大的保存、载入游戏数据的工具。 比如说,现在我有一份表单:data.xls用什么工具解析这个Excel文件并将数据载入游戏?我们可以使用Lua来完成这个工作。不过要
    03-16
  • 第1课 - 学习 Lua 的意义
    第1课 - 学习 Lua 的意义
    第1课 - 学习 Lua 的意义1.Lua 简介           (1) 1993年、巴西(2) 小巧精致的脚本语言,大小只有 200K(3) 用标准C语言写成,能够在所有的平台上编译运行(4) 发明的目标是嵌入在C/C++中,为应用程序提供灵活的扩展和定制功能(5) 不适合用于开发
    03-16
  • RedisTemplate 常用API+事务+陷阱+序列化+pipeline+LUA
    RedisTemplate 常用API+事务+陷阱+序列化+pipel
    https://www.jianshu.com/p/7bf5dc61ca06/https://blog.csdn.net/qq_34021712/article/details/79606551https://www.jianshu.com/p/c9f5718e58f0dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/depe
    03-08
  • Nginx动态路由的新姿势:使用Go取代lua nginx路由规则
    Nginx动态路由的新姿势:使用Go取代lua nginx路
    导语: 在Nitro 中, 我们需要一款专业的负载均衡器。 经过一番研究之后,Mihai Todor和我使用Go构建了基于Nginx、Redis 协议的路由器解决方案,其中nginx负责所有繁重工作,路由器本身并不承载流量。 这个解决方案过去一年在生产环境中运行顺畅。 以下是我
    03-08
  • cocos2d-lua 控制台输入Lua指令方便调试
    用脚本进行开发,如果不能实时去输入指令,就丧失了脚本的一大特色,所以对cocos2d-x程序稍微修改下,使其可以直接从控制台读入lua指令,方便调试。1 首先在行首加入lua的引用,如下1 #include "main.h"2 #include "AppDelegate.h"3 #include "cocos2d.h"4 #i
    02-09
  • lua_touserdata
    void *lua_touserdata(lua_State*L,intindex);如果给定索引处的值是一个完整的userdata,函数返回内存块的地址。如果值是一个lightuserdata,那么就返回它表示的指针。否则,返回NULL。例如: 在CCLuaStack::executeFunction()函数中有一段代码是用来获取c++
    02-09
  • Lua 5.2 中文参考手册
    闲来无事,发现Lua更新到了5.2.2,参考手册也更到了5.2,在网上发现只有云风翻译的5.1版,花了几天时间翻译了一些。参考手册有点长,又要随时修改,所以在github上建了项目,有需要的朋友可以看看,同时也欢迎指正。中文手册:Lua 5.2中文参考手册
    02-09
点击排行