简单的kafkaredis学习之redis

news2024/11/6 5:15:30

简单的kafka&redis学习之redis

2. Redis

2.1 什么是Redis

Redis是一种面向 “Key-Value” 数据类型的内存数据库,可以满足我们对海量数据的快速读写需求,Redis是一个 NoSQL 数据库,NoSQL的全称是not only sql,不仅仅是SQL,泛指非关系型数据库,这种类型的数据库不支持SQL语法。

首先Redis是一种内存数据库,它的数据都是放在内存里面的,然后Redis中存储的数据都是key-value类型的,其中redis中的key只能是字符串,value支持多种数据类型

常见的有string、hash、list、set、sortedset

  1. 字符串 string
  2. 哈希 hash,类似于java中的hashmap
  3. 字符串列表 list
  4. 字符串集合 set 不重复,无序
  5. 有序集合sorted set ,不重复,有序

2.2 Redis的特点

接下来看一下Redis的一些特点

  • 高性能:Redis读的速度是11W次/s,写的速度是8.1W次/s
  • 原子性:保证数据的准确性
  • 持久存储:支持两种方式的持久化,RDB和AOF,可以把内存中的数据持久化到磁盘中
  • 支持主从:master-slave架构,可以实现负载均衡、高可用
  • 支持集群:从3.0版本开始支持

注意:Redis是一个 单线程的服务,作者之所以这么设计,主要是为了保证redis的快速,高效,如果涉及了多线程,就需要使用锁机制来解决并发问题,这样执行效率反而会打折扣。

2.3 Redis安装部署

下面来看一下redis的安装部署,首先下载redis,使用此链接下载,可以显示Redis目前所有的版本 http://download.redis.io/releases/,我们选择目前比较稳定的5.0.9版本。将下载好的安装包上传到bigdata04机器的/data/soft目录下

将下载好的安装包上传到bigdata04机器的/data/soft目录下
1:解压

[root@bigdata04 soft]# tar -zxvf redis-5.0.9.tar.gz

2:编译+安装

[root@bigdata04 soft]# cd redis-5.0.9
[root@bigdata04 redis-5.0.9]# make
[root@bigdata04 redis-5.0.9]# make install

只要不报错就说明编译安装成功。由于redis需要依赖于C语言环境(yum install gcc),如果你安装的centos镜像是精简版,会缺失c语言的依赖,所以需要安装C语言环境才可以编译成功。我们在这使用的centos镜像是完整版,里面是包含C语言环境的,所以就不存在这个问题了。

如果yum install gcc后执行make报 [致命错误:jemalloc/jemalloc.h:没有那个文件或目录] 错误,需要再执行 make MALLOC=libc

3:修改redis.conf配置文件

[root@bigdata04 redis-5.0.9]# vi redis.conf
daemonize yes
logfile /data/soft/redis-5.0.9/log
bind 127.0.0.1 192.168.182.103
  • daemonize参数的值默认是no,表示在前台启动Redis,但是Redis是一个数据库,我们希望把它放到后台运行,所以将参数的值改为yes
  • logfile 参数的值默认为空,表示redis会将日志输出到/dev/null里面,也就是不保存了,建议在这设置一个日志路径记录redis的日志,便于后期排查问题。
  • bind 参数可以绑定指定ip,这样就可以通过这里指定的ip来访问redis服务了,可以在后面指定当前机器的本地回环地址(127.0.0.1)和内网地址(192.168.182.103),指定本地回环地址是为了能够在本机自己连自己比较方便。指定内网地址是为了能够让公司局域网内的其它服务器也能连到这个redis
    如果你这台机器有外网地址的话不建议在这配置,因为使用外网地址的话就不安全了,容易受到网络攻击。

4:启动redis

```shell
[root@bigdata04 redis-5.0.9]# redis-server redis.conf 
```

5:验证

注意:redis不是java程序,所以使用jps命令查不到,需要使用ps命令查看redis的进程

```shell
[root@bigdata04 redis-5.0.9]# ps -ef|grep redis
root       5828      1  0 16:12 ?        00:00:00 redis-server 127.0.0.1:6379
```

6:连接redis数据库

[root@bigdata04 redis-5.0.9]# redis-cli 
127.0.0.1:6379> 

注意:使用redis-cli默认可以连接本地的redis

其实redis-cli后面省略了-h 127.0.0.1-p 6379

[root@bigdata04 redis-5.0.9]# redis-cli -h 127.0.0.1 -p 6379

此时使用内网ip也能连接,这样其实我们就可以在其它安装有redis-cli客户端的机器上连接这个redis服务了。

[root@bigdata04 redis-5.0.9]# redis-cli -h 192.168.182.103 -p 6379
192.168.182.103:6379> 

7:停止redis数据库
暴力一点的方式是使用kill命令直接杀进程
不过redis提供的有停止命令

[root@bigdata04 redis-5.0.9]# redis-cli
127.0.0.1:6379> shutdown
not connected> 

或者这样停止也是可以的

[root@bigdata04 redis-5.0.9]# redis-cli shutdown

2.4 Redis基础命令

下面我们来看一下Redis中的基础命令
先启动redis服务,使用redis-cli客户端连到redis数据库里面

[root@bigdata04 redis-5.0.9]# redis-server redis.conf
[root@bigdata04 redis-5.0.9]# redis-cli 
127.0.0.1:6379> 
  • 获得符合规则的键:keys

    keys 后面可以指定正则表达式

    127.0.0.1:6379> keys *
    (empty list or set)
    127.0.0.1:6379> set a 1
    OK
    127.0.0.1:6379> keys *
    1)"a"
    127.0.0.1:6379> keys a*
    1) "a"
    127.0.0.1:6379> keys a+
    (empty list or set)
    

    注意:在生产环境下建议禁用keys命令,因为这个命令会查询过滤redis中的所有数据,可能会造成服务阻塞,影响redis执行效率。

    如果有类似的查询需求建议使用scan,scan命令用于迭代当前数据库中的key集合,它支持增量式迭代,每次执行只会返回少量元素,所以它可以用于生产环境,而不会出现像keys 命令那样可能会阻塞服务器的问题。

    SCAN命令是一个基于游标的迭代器。这意味着命令每次被调用都需要使用上一次调用返回的游标作为该次调用的游标参数,以此来延续之前的迭代过程
    当SCAN命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束。

    向redis中初始化一批数据

    127.0.0.1:6379> set a1 1
    OK
    127.0.0.1:6379> set a2 1
    OK
    127.0.0.1:6379> set a3 1
    OK
    127.0.0.1:6379> set a4 1
    OK
    127.0.0.1:6379> set a5 1
    OK
    127.0.0.1:6379> set a6 1
    OK
    127.0.0.1:6379> set a7 1
    OK
    127.0.0.1:6379> set a8 1
    OK
    127.0.0.1:6379> set a9 1
    OK
    127.0.0.1:6379> set a10 1
    OK
    

    使用scan迭代数据,后面游标参数指定为0,表示从头开始迭代key

    127.0.0.1:6379> scan 0
    1) "3"
    2)  1) "a9"
        2) "a3"
        3) "a1"
        4) "a10"
        5) "a8"
        6) "a5"
        7) "a4"
        8) "a"
        9) "a7"
       10) "a6"
    

    SCAN 命令的返回值是一个包含两个元素的数组,第一个元素是用于进行下一次迭代的新游标,而第二个元素则是一个数组, 这个数组中包含了所有被迭代出来的元素。默认情况下scan返回10条数据,所以这样执行效果也是一样的

    127.0.0.1:6379> scan 0 count 10
    1) "3"
    2)  1) "a9"
        2) "a3"
        3) "a1"
        4) "a10"
        5) "a8"
        6) "a5"
        7) "a4"
        8) "a"
        9) "a7"
       10) "a6"
    

    scan命令此时返回的游标为3,注意,游标的值并不等于返回的数据量。如果想要继续往下面迭代数据的话,下一次执行scan的时候需要指定之前返回的游标,redis会根据这个游标继续往下面迭代

    127.0.0.1:6379> scan 3 count 10
    1) "0"
    2) 1) "a2"
    

    这一次使用scan命令,返回的游标为0,表示迭代已经结束,整个redis中的key都被迭代完了。redis中一共有11个key,第一次使用scan 0获取到了10个key,第二次获取到了1个key,没有问题。

    注意:大家在下面练习的时候可能会发现你那边第一次返回的游标和我这边显示的不一样,那也很正常,因为你会发现你返回的这个数据集的顺序也是不一样的。

    所以,如果redis中有很多key,我们可以使用scan命令来迭代,一次迭代一部分,不至于造成阻塞,如果redis中的key比较少,那么使用keys * 也是可以的。如果想要在迭代key的时候对key进行过滤,可以在scan后面指定match参数,match后面可以指定正则表达式

    127.0.0.1:6379> scan 0 match a[1-5] count 10
    1) "3"
    2) 1) "a3"
       2) "a1"
       3) "a5"
       4) "a4"
    

    此时实际返回的key的数量是4个,但是游标还是3,相当于还是迭代了10条数据,只不过不满足条件的没有返回而已。

  • 判断键是否存在:exists

    127.0.0.1:6379> exists a
    (integer) 1
    127.0.0.1:6379> exists b
    (integer) 0
    
  • 删除键:del

    127.0.0.1:6379> del a
    (integer) 1
    

    注意:del也支持一次删除多个key

    127.0.0.1:6379> del a1 a2
    (integer) 2
    
  • 获得键值的类型:type

    返回值可能是这五种类型(string,hash,list,set,zset)

    127.0.0.1:6379> set a 1
    OK
    127.0.0.1:6379> type a
    string
    

    这个命令可以帮我们快速识别某一个key中存储的数据是什么类型的,因为针对存储了不同类型值的key,操作的命令是不一样的。

  • 帮助命令:help

    127.0.0.1:6379> help set
      SET key value [EX seconds] [PX milliseconds] [NX|XX]
      summary: Set the string value of a key
      since: 1.0.0
      group: string
    
  • 退出客户端:quit/exit

    127.0.0.1:6379> quit
    

    不过我还是习惯使用ctrl+c退出redis-cli客户端,最后有一点需要注意:Redis的命令不区分大小写,但是key的名称需要区分大小写!

2.5 Redis多数据库特性

Redis默认支持 16 个数据库,通过databases参数控制的
这个参数在redis.conf配置文件中

[root@bigdata04 redis-5.0.9]# cat redis.conf | grep databases
# Set the number of databases. The default database is DB 0, you can select
# dbid is a number between 0 and 'databases'-1
databases 16
# Compress string objects using LZF when dump .rdb databases?

每个数据库对外都是以一个从0开始的递增数字命名,不支持自定义

Redis默认选择的是0号数据库,可以通过 select 命令切换

127.0.0.1:6379> select 0
OK
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> select 2
OK
127.0.0.1:6379[2]> select 15
OK
127.0.0.1:6379[15]> select 16
(error) ERR DB index is out of range

一般在工作中会使用2~3个数据库,可以根据业务类型来分库,不同业务的数据存到不同的库里面,还有一种用法是,一个库作为测试库,一个库作为正式库。

如果没有特殊需求,一般使用0号数据库就可以了,这个库使用起来比较方便,默认就是0号库,不需要使用select切换。具体在工作中怎么用都行,只要理解它的特性就可以了。但是有一点需要注意:多个数据库之间并不是完全隔离的,如果使用flushall命令,则会清空redis中所有数据库内的数据。

并且我们在redis中使用多个库,并不能提高redis的存储能力,因为默认这16个库共用redis的内存存储空间,如果想要提高redis的存储能力,需要给我们的服务器增加内存才可以。

127.0.0.1:6379[15]> set x 1
OK
127.0.0.1:6379[15]> flushall
OK
127.0.0.1:6379[15]> keys *
(empty list or set)
127.0.0.1:6379[15]> select 0
OK
127.0.0.1:6379> keys *
(empty list or set)

如果只想清空当前数据库中的数据,可以使用flushdb

127.0.0.1:6379> select 15
OK
127.0.0.1:6379[15]> set a 1
OK
127.0.0.1:6379[15]> keys *
1) "a"
127.0.0.1:6379[15]> flushdb
OK

2.6 Redis数据类型

下面来看一下redis中的常用数据类型,这些数据类型都是针对于redis中的value而言的,因为key都是字符串

  • string
  • hash
  • list
  • set
  • sorted set
2.6.1 Redis数据类型之string

字符串类型是redis中最基本的数据类型,它能存储任何形式的内容,包含二进制数据,甚至是一张图片
一个字符串类型的值存储的最大容量是1GB,一般情况下我们存储的单条数据肯定是达不到的这个限值的,所以大家不用担心
string类型比较适合存储类型单一的数据
针对string类型主要有下面这些常见命令:

命令格式解释
setset key value给key设置一个Value(字符串类型的)
getget key获取key的值
incrincr key对key的值递加+1(值必须是数字)
decrdecr key对key的值递减-1(值必须是数字)
strlenstrlen key获取key值的长度

添加数据 set

127.0.0.1:6379> set str a
OK

查询数据 get

127.0.0.1:6379> get str
"a"

一次添加多条数据

127.0.0.1:6379> mset str1 a1 str2 a2
OK

一次查询多条数据

127.0.0.1:6379> mget str1 str2
1) "a1"
2) "a2"

递增1

127.0.0.1:6379> set num 1
OK
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> get num
"2"

递减1

127.0.0.1:6379> decr num
(integer) 1
127.0.0.1:6379> get num
"1"

递增指定数值(整数类型)

127.0.0.1:6379> incrby num 2
(integer) 3
127.0.0.1:6379> get num
"3"
127.0.0.1:6379> incrby num 2.1
(error) ERR value is not an integer or out of range[注意:增量数值只支持integer类型]

递减指定数值(整数类型)

127.0.0.1:6379> decrby num 2
(integer) 1
127.0.0.1:6379> get num
"1"

递增指定数值(float类型)

127.0.0.1:6379> incrbyfloat num 2.1
"3.1"
127.0.0.1:6379> get num
"3.1"

获取指定key的value长度

127.0.0.1:6379> get str
"a"
127.0.0.1:6379> strlen str
(integer) 1
127.0.0.1:6379> set str abcd
OK
127.0.0.1:6379> strlen str
(integer) 4
2.6.2 Redis数据类型之hash

hash类型的值存储了字段和字段值的映射,字段和字段值只能是字符串,不支持其他数据类型。hash类型的值至多存储2的32次方-1个字段,一般情况下我们也达不到这个极限,hash类型比较适合存储对象,因为对象里面是有一些属性和值的,我们就可以把这些属性和值存储到这个hash类型里面
针对hash类型主要有下面这些常见命令:

命令格式解释
hsethset key field value向hash中添加字段和值
hgethget key field获取hash中指定字段的值
hgetallhgetall key获取hash中所有的字段和值
hexistshexists key field判断hash中是否包含指定字段
hincrbyhincrby key field num对hash中指定字段的值递增
hdelhdel key field删除hash中指定的字段
hkeys/hvalshkeys/hvals key获取hash中所有字段或字段值
hlenhlen key获取hash中所有字段的数量

添加数据 hget

127.0.0.1:6379> hset user:1 name zs
(integer) 1

查询数据 hget

127.0.0.1:6379> hget user:1 name
"zs"

向一个hash中同时添加多个k-v hmset

127.0.0.1:6379> hmset user:2 name lisi age 18
OK

查询一个hash数据中多个k的值 hmget

127.0.0.1:6379> hmget user:2 name age
1) "lisi"
2) "18"

查询一个hash数据中的所有k-v hgetall

127.0.0.1:6379> hgetall user:2
1) "name"
2) "lisi"
3) "age"
4) "18"

判断一个hash数据中是否存在指定k hexists

127.0.0.1:6379> hexists user:2 name
(integer) 1
127.0.0.1:6379> hexists user:2 city
(integer) 0

对一个hash数据中指定k的v进行递增 hincrby

127.0.0.1:6379> hincrby user:2 age 1
(integer) 19
127.0.0.1:6379> hget user:2 age
"19"

删除一个hash数据中的指定k hdel

127.0.0.1:6379> hset user:2 city beijing
(integer) 1
127.0.0.1:6379> hdel user:2 city
(integer) 1

获取一个hash数据中的所有k hkeys

127.0.0.1:6379> hkeys user:2
1) "name"
2) "age"

获取一个hash数据中的所有v hvals

127.0.0.1:6379> hvals user:2
1) "lisi"
2) "19"

获取一个hash数据中有多少个k hlen

127.0.0.1:6379> hlen user:2
(integer) 2
2.6.3 Redis数据类型之list

list是一个有序的字符串列表,列表内部是使用双向链表(linked list)实现的,list列表类型的值最多可以存储2的32次方-1个元素,一般我们也达不到这个限值。list类型比较适合作为队列使用,使用lpush+rpop可以实现先进先出的队列

针对list类型主要有下面这些常见命令:

命令格式解释
lpushlpush key value从列表左侧添加元素
rpushrpush key value从列表右侧添加元素
lpoplpop key从列表左侧弹出元素
rpoprpop key从列表右侧弹出元素
llenllen key获取列表的长度
lrangelrange key start stop获取列表指定区间的元素
lindexlindex key index获取列表指定角标的元素
lsetlset key index value修改列表中指定角标的元素

添加元素(左侧添加) lpush

127.0.0.1:6379> lpush list1 a
(integer) 1
127.0.0.1:6379> lpush list1 b
(integer) 2

取出元素(左侧取元素) lpop

127.0.0.1:6379> lpop list1
"b"
127.0.0.1:6379> lpop list1
"a"
127.0.0.1:6379> lpop list1
(nil)

添加元素(右侧添加) rpush

127.0.0.1:6379> rpush list2 x
(integer) 1
127.0.0.1:6379> rpush list2 y
(integer) 2

取出元素(右侧取元素) rpop

127.0.0.1:6379> rpop list2
"y"
127.0.0.1:6379> rpop list2
"x"

列表长度 llen

127.0.0.1:6379> lpush list3 a b c d
(integer) 4
127.0.0.1:6379> llen list3
(integer) 4

获取列表中的元素 lrange

127.0.0.1:6379> lrange list3 0 -1
1) "d"
2) "c"
3) "b"
4) "a"

查询指定角标元素 lindex

127.0.0.1:6379> lindex list3 1
"c"

修改指定角标元素 lset

127.0.0.1:6379> lset list3 1 m
OK
127.0.0.1:6379> lrange list3 0 -1
1) "d"
2) "m"
3) "b"
4) "a"
2.6.4 Redis数据类型之set

set是一个集合,set集合中的元素都是不重复的,无序的。set集合类型的值最多可以存储2的32次方-1个元素。set集合比较适合用在去重的场景下,因为它里面的元素是都不重复的

针对set类型主要有下面这些常见命令:

命令格式解释
saddsadd key value向集合中添加元素
smemberssmembers key获取集合中所有元素
sremsrem key value从集合中删除指定元素
sismembersismember key value判断集合中是否包含指定元素
sdiffsdiff key1 key2获取两个集合的差集
sintersinter key1 key2获取两个集合的交集
sunionsunion key1 key2获取两个集合的并集
scardscard key获取集合中元素的数量

向集合中添加元素 sadd

127.0.0.1:6379> sadd set1 a
(integer) 1
127.0.0.1:6379> sadd set1 b
(integer) 1

获取集合中所有元素 smembers

127.0.0.1:6379> smembers set1
1) "b"
2) "a"

删除集合中的元素 srem

127.0.0.1:6379> srem set1 a
(integer) 1

判断元素是否存在集合中 sismember

127.0.0.1:6379> sismember set1 b
(integer) 1
127.0.0.1:6379> sismember set1 a
(integer) 0

两个集合取差集 sdiff

127.0.0.1:6379> sadd set2 a b c
(integer) 3
127.0.0.1:6379> sadd set3 a b x
(integer) 3
127.0.0.1:6379> sdiff set2 set3
1) "c"
127.0.0.1:6379> sdiff set3 set2
1) "x"

两个集合取交集 sinter

127.0.0.1:6379> sinter set2 set3
1) "b"
2) "a"

两个集合取并集 sunion

127.0.0.1:6379> sunion set2 set3
1) "c"
2) "a"
3) "x"
4) "b"

获取集合长度(获取集合中元素的个数) scard

127.0.0.1:6379> scard set3
(integer) 3
2.6.5 Redis数据类型之sorted set

有序集合,在集合类型的基础上为集合中的每个元素都关联了一个分数,根据分数进行排序,这样就实现了有序。sorted set比较适合用在获取TopN的场景,因为它里面的数据是有序的

针对sorted set类型主要有下面这些常见命令:

命令格式解释
zaddzadd key value向集合中添加元素
zscorezscore key value获取集合中指定元素的分值
zrangezrange key value获取集合指定元素的排名(正序)
zrevrange格式同上获取集合指定元素的排名(倒序)
zincrbyzincrby key num value给集合中指定元素增加分值
zcardzcard key获取集合中元素的数量
zremzrem key value从集合中删除指定元素

向集合中添加元素 zadd

127.0.0.1:6379> zadd zset1 5 a
(integer) 1
127.0.0.1:6379> zadd zset1 3 b
(integer) 1
127.0.0.1:6379> zadd zset1 4 c
(integer) 1

查询集合中指定元素的分值 zscore

127.0.0.1:6379> zscore zset1 a
"5"

根据角标获取集合中的元素(按照正序) zrange

127.0.0.1:6379> zrange zset1 0 -1
1) "b"
2) "c"
3) "a"

根据角标获取集合中的元素(按照倒序) zrevrange

127.0.0.1:6379> zrevrange zset1 0 -1
1) "a"
2) "c"
3) "b"

对集合中元素的分值进行递增 zincrby

127.0.0.1:6379> zincrby zset1 3 a
"8"
127.0.0.1:6379> zscore zset1 a
"8"

获取集合中元素的个数 zcard

127.0.0.1:6379> zcard zset1
(integer) 3

删除集合中的元素 zrem

127.0.0.1:6379> zrem zset1 a
(integer) 1
127.0.0.1:6379> zrange zset1 0 -1
1) "b"
2) "c"

sorted set使用注意点:

  • 1:+inf(正无穷) -inf(负无穷),在给集合中的元素设置分值的时候可以使用这两个特殊数值。
  • 2:set命令:如果key持有其它类型值,set会覆盖旧值,无视类型
2.6.6 eg:存储高一班的学员信息

需求:将学员的姓名、年龄、性别、住址信息保存到Redis中,分析一下:

在这里我们可以把学生认为是一个对象,学生对象具备了多个属性信息,姓名,年龄,性别,住址信息
所以针对学生信息非常适合使用hash类型进行存储
我们可以给学生生成一个编号拼接到key里面,姓名、年龄、性别、住址信息存储到hash类型的value中

注意:这里面针对key的命名,stu是student的简写,尽量不要写太多字符,否则会额外占用内存空间的,后面的:1,表示这个学生的编号是1,后期如果我们想获取所有学员的key,就可以使用这个规则进行过滤了。

这个规则进行过滤了。

127.0.0.1:6379> hmset stu:1 name xiaoming age 18 sex 0 address beijing
OK
127.0.0.1:6379> hgetall stu:1
1) "name"
2) "xiaoming"
3) "age"
4) "18"
5) "sex"
6) "0"
7) "address"
8) "beijing"
127.0.0.1:6379> hget user:1 age
"18"

2.7 JAVA操作redis

在这我们以java代码为例,演示一下如何使用java代码操作redis,我们需要借助于第三方jar包jedis来操作,首先在idea中创建maven项目db_redis。在pom.xml文件中添加jedis依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.3.0</version>
</dependency>
2.7.1 单连接方式

接下来使用单连接的方式操作redis,代码如下:

package cn.git.redis;

import redis.clients.jedis.Jedis;

/**
 * 单连接方式操作redis
 * Created by lixuchun
 */
public class RedisSingle {
    /**
     * 注意:此代码能够正常执行的前提是
     * 1:redis所在服务器的防火墙需要关闭
     * 2:redis.conf中的bind参数需要指定192.168.182.103
     * @param args
     */
    public static void main(String[] args) {
        //获取jedis连接
        Jedis jedis = new Jedis("192.168.182.103",6379);
        //向redis中添加数据,key=git,value=hello bigdata!
        jedis.set("git","hello bigdata!");
        //从redis中查询key=git的value的值
        String value = jedis.get("git");
        System.out.println(value);
        //关闭jedis连接
        jedis.close();
    }
}

代码执行效果如下:hello bigdata!,此时到redis中确认一下:

127.0.0.1:6379> keys *
1) "git"
127.0.0.1:6379> get git
"hello bigdata!"

其实在这你会发现,我们前面讲的那些在redis-cli中使用的命令,和jedis中提供的函数名称是一一对应的。切换到代码中来使用也是可以直接上手的。

2.7.2 连接池方式

接下来使用连接池的方式操作redis,代码如下:

package cn.git.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * 连接池的方式操作redis
 * Created by lixuchun
 */
public class RedisPool {
    public static void main(String[] args) {
        //创建连接池配置对象
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        //连接池中最大空闲连接数
        poolConfig.setMaxIdle(10);
        //连接池中创建的最大连接数
        poolConfig.setMaxTotal(100);
        //创建连接的超时时间
        poolConfig.setMaxWaitMillis(2000);
        //表示从连接池中获取连接的时候会先测试一下连接是否可用,这样可以保证取出的连接都是可用的
        poolConfig.setTestOnBorrow(true);

        //获取jedis连接池
        JedisPool jedisPool = new JedisPool(poolConfig, "192.168.182.103", 6379);

        //从jedis连接池中取出一个连接
        Jedis jedis = jedisPool.getResource();
        String value = jedis.get("git");
        System.out.println(value);
        //注意:此处的close方法有两层含义
        //1:如果jedis是直接创建的单连接,此时表示直接关闭这个连接
        //2:如果jedis是从连接池中获取的连接,此时会把这个连接返回给连接池
        jedis.close();
        
        //关闭jedis连接池
        jedisPool.close();
    }
}

执行结果:hello bigdata!

2.7.3 提取RedisUtils工具类

基于redis连接池的方式提取RedisUtils工具类

package cn.git.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * 基于redis连接池提取redis工具类
 * Created by lixuchun
 */
public class RedisUtils {
    //私有化构造函数,禁止new
    private RedisUtils(){}

    private static JedisPool jedisPool = null;

    //获取连接
    public static synchronized Jedis getJedis(){
        if(jedisPool==null){
            JedisPoolConfig poolConfig = new JedisPoolConfig();
            poolConfig.setMaxIdle(10);
            poolConfig.setMaxTotal(100);
            poolConfig.setMaxWaitMillis(2000);
            poolConfig.setTestOnBorrow(true);
            jedisPool = new JedisPool(poolConfig, "192.168.182.103", 6379);
        }
        return jedisPool.getResource();
    }

    //向连接池返回连接
    public static void returnResource(Jedis jedis){
        jedis.close();
    }

}

使用工具类代码

package cn.git.redis;

import redis.clients.jedis.Jedis;

/**
 * Created by lixuchun
 */
public class TestRedisUtils {
    public static void main(String[] args) {
        //获取连接
        Jedis jedis = RedisUtils.getJedis();
        String value = jedis.get("git");
        System.out.println(value);
        //向连接池返回连接
        RedisUtils.returnResource(jedis);
    }
}

2.8 高级特性

2.8.1 expire 生存时间

Redis中可以使用expire命令设置一个键的生存时间,到时间后Redis会自动删除它

它的一个典型应用场景是:手机验证码

我们平时在登录或者注册的时候,手机会接收到一个验证码,上面会提示验证码的过期时间,过了这个时间之后这个验证码就不能用了。

expire支持以下操作

命令格式解释
expireexpire key seconds设置key的过期时间(单位:秒)
ttlttl key获取key的剩余有效时间
persistpersist key取消key的过期时间
expireatexpireat key timestamp设置UNIX时间戳的过期时间

设置key的过期时间

127.0.0.1:6379> set abc 123
OK
127.0.0.1:6379> expire abc 200
(integer) 1

获取key的剩余有效时间

127.0.0.1:6379> ttl abc
(integer) 192

取消key的过期时间

127.0.0.1:6379> persist abc
(integer) 1

此时再查看这个key的剩余有效时间,返回的值是-1,-1表示这个key是一个永久存在的key

127.0.0.1:6379> ttl abc
(integer) -1

还可以通过expireat指定key在指定时间点过期
先获取当前时间戳

[root@bigdata04 ~]# date +%s
1768618628

127.0.0.1:6379> expireat abc 1768618638
(integer) 1

过一会再查看这个key的剩余有效时间,返回的是-2,表示这个key被删除了,不存在了

127.0.0.1:6379> ttl abc
(integer) -2
127.0.0.1:6379> exists abc
(integer) 0

总结一下:
当key永久存在的时候,执行ttl返回的是-1,
当key被设置了过期时间之后,执行ttl返回的就是这个key剩余的有效时间
当key已经被删除了,不存在的时候,执行ttl返回的是-2

2.8.2 pipeline 管道

针对批量操作数据或者批量初始化数据的时候使用,效率高,Redis的pipeline功能在命令行中没有实现,在Java客户端(jedis)中是可以使用的

它的原理是这样的

不使用管道的时候,我们每执行一条命令都需要和redis服务器交互一次
使用管道之后,可以实现一次提交一批命令,这一批命令只需要和redis服务器交互一次,所以就提高了性能。
这个功能就类似于mysql中的batch批处理。

接下来看一个案例,案例:初始化10万条数据,需求:使用普通方式一条一条添加和使用管道批量初始化进行对比分析

代码如下:

package cn.git.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;

/**
 * pipeline(管道)的使用
 * Created by lixuchun
 */
public class PipelineOp {
    public static void main(String[] args) {
        // 1:不使用管道
        Jedis jedis = RedisUtils.getJedis();
        long start_time = System.currentTimeMillis();
        for(int i=0;i<100000;i++){
            jedis.set("a"+i,"a"+i);
        }
        long end_time = System.currentTimeMillis();
        System.out.println("不使用管道,耗时:"+(end_time-start_time));

        // 2:使用管道
        Pipeline pipelined = jedis.pipelined();
        start_time = System.currentTimeMillis();
        for(int i=0;i<100000;i++){
            pipelined.set("b"+i,"b"+i);
        }
        pipelined.sync();
        end_time = System.currentTimeMillis();
        System.out.println("使用管道,耗时:"+(end_time-start_time));

        RedisUtils.returnResource(jedis);
    }

}

结果如下:

不使用管道,耗时:40887
使用管道,耗时:180

在代码执行的过程中,我们可以使用info命令观察数据库中的数据条数

127.0.0.1:6379> info
# Keyspace
db0:keys=200000,expires=1,avg_ttl=389945

从这可以看出来,针对海量数据的初始化,管道可以显著提高初始化性能。

2.8.3 info命令

这里面参数比较多,在这我们主要关注几个重点的参数

# Redis 服务器版本
redis_version:5.0.9
# Redis服务的可执行文件路径
executable:/data/soft/redis-5.0.9/redis-server
# 启动Redis时使用的配置文件路径
config_file:/data/soft/redis-5.0.9/redis.conf
# 已连接客户端的数量
connected_clients:1
# Redis目前存储数据使用的内容
used_memory_human:15.01M
# Redis可以使用的内存总量,和服务器的内存有关
total_system_memory_human:1.78G
# db0表示0号数据库,keys:表示0号数据库的key总量,expires:表示0号数据库失效被删除的key总量
db0:keys=200001,expires=1,avg_ttl=389945
2.8.4 Redis的持久化

Redis持久化简单理解就是把内存中的数据持久化到磁盘中 可以保证Reids重启之后还能恢复之前的数据,Redis支持两种持久化,可以 单独使用 或者 组合使用

RDB 和 AOF

2.8.4.1 Redis持久化之RDB

RDB是Redis默认的持久化机制,RDB持久化是通过快照完成的,当符合一定条件时Redis会自动将内存中的所有数据执行快照操作并存储到硬盘上,默认存储在dump.rdb文件中

[root@bigdata04 redis-5.0.9]# ll
....
-rw-r--r--.  1 root root 2955661 Jan 17 12:12 dump.rdb
......

Redis什么时候会执行快照?Redis执行快照的时机是由以下参数控制的,这些参数是在redis.conf文件中的

save 900 1
save 300 10
save 60 10000

save 900 1 表示900秒内至少一个key被更改则进行快照,这里面的三个时机哪个先满足都会执行快照操作。

RDB持久化的优缺点:

  • RDB的优点:由于存储的有数据快照文件,恢复数据很方便
  • RDB的缺点:会丢失最后一次快照以后更改的所有数据,因为两次快照之间是由一个时间差的,这一段时间之内修改的数据可能会丢。
2.8.4.2 Redis持久化之AOF

AOF持久化是通过日志文件的方式,默认情况下没有开启,可以通过appendonly参数开启

[root@bigdata04 redis-5.0.9]# vi redis.conf 
....
appendonly yes
....

AOF日志文件的保存位置和RDB文件相同,都是dir参数设置的,默认的文件名是appendonly.aof

注意:dir参数的值为. 表示当前目录,也就是说我们在哪个目录下启动redis,rdb快照文件和aof日志文件就产生在哪个目录下。

可以试验一下,换一个目录启动redis,发下redis中的数据是空的。关闭之后,重新在之前的目录启动redis,数据又回来了。

AOF方式只会记录用户的写命令,添加、修改、删除之类的命令,查询命令不会记录,因为查询命令不会影响数据的内容。

那redis什么时候会把用户的写命令同步到aof文件中呢?

# appendfsync always
# appendfsync everysec
# appendfsync no

三种配置解释如下:

  • appendfsync everysec,默认是每秒钟执行一次同步操作。
  • appendfsync always,实现每执行一次写操作就执行一次同步操作,但是这样效率会有点低。
  • appendfsync no,表示不主动进行同步,由操作系统来做,30秒执行一次。

如果大家对数据的丢失确实是0容忍的话,可以使用always。不过一般情况下,redis中存储的都是一些缓存数据,就算丢了也没关系,程序还会继续往里面写新数据,不会造成多大影响。

2.9 Redis 的安全策略

2.9.1 设置数据库密码

默认情况下访问redis只要网络能通就可以直接访问,这样其实是有一些不安全的,不过我们一般会限制只能在内网访问,这样其实问题也不大。

redis针对这个问题,也支持给数据库设置密码,在redis.conf中配置

[root@bigdata04 redis-5.0.9]# vi redis.conf 
....
requirepass admin
....

重启redis服务

[root@bigdata04 redis-5.0.9]# redis-cli shutdown
[root@bigdata04 redis-5.0.9]# redis-server redis.conf

重新连接redis

[root@bigdata04 redis-5.0.9]# redis-cli 
127.0.0.1:6379> get git
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth admin
OK
127.0.0.1:6379>get git
hello bigdata!

在代码层面,以后在使用的时候时候就需要使用auth方法先校验权限了。

package com.git.redis;

import redis.clients.jedis.Jedis;

/**
 * 单连接方式操作redis
 * Created by xuwei
 */
public class RedisSingle {
    /**
     * 注意:此代码能够正常执行的前提是
     * 1:redis所在服务器的防火墙需要关闭
     * 2:redis.conf中的bind参数需要指定192.168.182.103
     * @param args
     */
    public static void main(String[] args) {
        // 获取jedis连接
        Jedis jedis = new Jedis("192.168.182.103",6379);
        // 使用密码
        jedis.auth("admin");
        // 向redis中添加数据,key=git,value=hello bigdata!
        jedis.set("git","hello bigdata!");
        // 从redis中查询key=git的value的值
        String value = jedis.get("git");
        System.out.println(value);
        //关闭jedis连接
        jedis.close();
    }
}

注意:在实际工作中一般不会设置密码,因为我们在这设置的密码是明文的,其实意义也不大,针对别有用心的人,你这样设置是没有意义的。

所以在实际工作中我们一般只需要控制好redis服务器的访问权限就可以了,redis服务器的访问权限其实就是使用bind参数来设置的。所以再把刚才设置的密码取消掉,直接把对应的配置注释掉即可。

所以再把刚才设置的密码取消掉,直接把对应的配置注释掉即可

[root@bigdata04 redis-5.0.9]# vi redis.conf 
#requirepass admin
2.9.2 bind参数的应用

在实际工作中,我们的服务器至少会有3个ip地址

  • 127.0.0.1 这个是本机回环地址
  • 192.168.10.14 这个是本机的内网地址
  • 还有一个是外网地址

我们一般会使用bind绑定内网ip,这样其实就限制了redis服务器的访问范围,不会暴露在外网,只需要运维同学做好网络的访问限制就可以了,此时我们就可以认为redis是安全的了。

2.9.3 命令重命名

咱们前面讲过一个命令是flushall,这个命令是很危险的,它可以把redis中的所有数据全部清空
所以在实际工作中一般需要将这个命令给禁用掉,防止误操作。

在redis.conf配置文件中进行设置

[root@bigdata04 redis-5.0.9]# vi redis.conf 
....
rename-command flushall ""
....

这样修改之后,就把flushall命令给禁用掉了,重启redis服务

[root@bigdata04 redis-5.0.9]# redis-cli shutdown
[root@bigdata04 redis-5.0.9]# redis-server redis.conf

重新连接redis

[root@bigdata04 redis-5.0.9]# redis-cli 
127.0.0.1:6379> flushall
(error) ERR unknown command `flushall`, with args beginning with: 
127.0.0.1:6379> 

此时会提示未知命令。其实我们还可以选择,在重命名的时候给这个命令起一个别名,这样后期如果想使用的时候也是可以使用的。我们现在在后面直接指定的是空字符串 就是直接禁用了,如果指定一个其它字符串,就相当于起别名了。

2.9.4 Redis实例最多存多少key

一个Redis实例最多能存放多少key?有没有限制?Redis本身是不会限制存储多少key的,但是Redis是基于内存的,它的存储极限是系统中的可用内存值,如果内存存满了,那就无法再存储key了。

2.9.5 Redis监控命令-monitor

这个monitor命令是一把双刃剑。在实际工作中要慎用。先演示一下:

[root@bigdata04 redis-5.0.9]# redis-cli 
127.0.0.1:6379> monitor
OK

执行代码RedisSingle.java中的代码,然后会发现monitor监控到我们对redis的所有操作

[root@bigdata04 redis-5.0.9]# redis-cli 
127.0.0.1:6379> monitor
OK
1768628815.007443 [0 192.168.182.1:60633] "SET" "git" "hello bigdata!"
1768628815.007797 [0 192.168.182.1:60633] "GET" "git"

monitor可以监控我们对redis的所有操作,如果在线上的服务器上打开了这个功能,这里面就会频繁打印出来我们对redis数据库的所有操作,这样会影响redis的性能,所以说要慎用。

但是在某些特殊的场景下面它是很有用的,之前在工作中我遇到过一个很奇怪的问题,redis中的一个key总是会莫名其妙的消失,我的一个程序会定时向redis中写入一个key,但是我发现这个key刚写进去,然后一会就没了,很奇怪,当时我仔细排查了我的代码,里面既没有设置失效时间,也没有使用删除功能。

所以这个key不是我的代码删的,肯定是有其它的代码会删除这个key,但是到底是哪的代码?这个时候就不好排查了,我们的业务机有几十台,根本无从下手。
这个时候我突然想到了monitor这个命令,虽然开启monitor会影响redis的性能,但是这个时候需要排查问题,使用一会也是可以接受的。

所以就打开了monitor,打开之后屏幕上就打印出来很多命令,这样根本就看不清,没办法追踪,数据太多了。所以又想到了这个办法,结合grep命令来操作,这样就可以过滤出来对指定key的所有操作了。

[root@bigdata04 redis-5.0.9]# redis-cli monitor | grep key
1768629282.484868 [0 192.168.182.1:52364] "del" "key"

通过这条数据我们可以分析出来到底是哪台机器上的程序删除了这个key。然后再排查这台机器上都有哪些程序,对应的去排查代码,这样就快多了,最终发现是有一个代码里面会定时删除这个key。这个就是monitor的典型应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2229327.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无人机之卫星通信技术篇

无人机的卫星通信技术是一种利用人造地球卫星作为中继站来转发无线电波&#xff0c;从而实现无人机与地面控制站之间通信的技术。 一、技术概述 卫星通信系统主要由通信卫星和经该卫星连通的地球站两部分组成。在无人机应用中&#xff0c;卫星通信技术能够确保无人机在全球范围…

网鼎杯 misc -好久不见4

不嘻嘻&#xff0c;没见过这种题&#xff0c;需要把这个红线还原重组成二维码&#xff0c;搜索一个是这个Peano曲线 from PIL import Image from tqdm import tqdmdef peano(n):if n 0:return [[0, 0]]else:in_lst peano(n - 1)lst in_lst.copy()px, py lst[-1]lst.extend(…

ARM base instruction -- adcs

Add with Carry, setting flags, adds two register values and the Carry flag value, and writes the result to the destination register. It updates the condition flags based on the result. 带进位加法&#xff0c;设置标志&#xff0c;将两个寄存器值和进位标志值相…

笔记本双系统win10+Ubuntu 20.04 无法调节亮度亲测解决

sudo add-apt-repository ppa:apandada1/brightness-controller sudo apt-get update sudo apt-get install brightness-controller-simple 安装好后找到一个太阳的图标&#xff0c;就是这个软件&#xff0c;打开后调整brightness&#xff0c;就可以调整亮度&#xff0c;可…

vue版本太低无法执行vue ui命令

连接 ui和create目前都只支持3.0以后得版本才能使用 https://blog.csdn.net/m0_67318913/article/details/136775252?utm_mediumdistribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-136775252-blog-121204604.235v43pc_blog_bottom_relevance…

萤石私有化设备视频平台EasyCVR视频融合平台如何构建农业综合监控监管系统?

现代农业的迅速发展中&#xff0c;集成监控管理系统已成为提高农业生产效率和优化管理的关键工具。萤石私有化设备视频平台EasyCVR&#xff0c;作为一个具有高度可扩展性、灵活的视频处理能力和便捷的部署方式的视频监控解决方案&#xff0c;为农业监控系统的建设提供了坚实的技…

Pr 视频效果:闪光灯

视频效果/风格化/闪光灯 Stylize/Strobe Light 闪光灯 Strobe Light效果可用于在视频中创建闪烁或频闪的效果&#xff0c;类似于舞台上的频闪灯或摄影中的闪光灯。 ◆ ◆ ◆ 效果选项说明 通过调整各种参数&#xff0c;可以自定义闪光的颜色、频率、持续时间和混合模式&#…

FreeRTOS确定任务栈大小

一、FreeRTOS内存分配 所有任务共用一个堆空间&#xff0c;所以当调用xPortGetFreeHeapSize这个函数时&#xff0c;返回的就是现在所有可用堆空间的消息 所有任务都有自己的栈空间&#xff0c;比如在任务中定义一个uint32_t data[100]的数组&#xff0c;此时调用uxTaskGetSt…

计算机毕业设计Hadoop+Spark+Hive抖音情感分析 抖音可视化 抖音舆情监测 预测算法 抖音爬虫 抖音大数据 情感分析 NLP 自然语言处理

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; HadoopSparkHive抖音情感分…

tcp shutdown, fin_wait1, fin_wait2, close_wait, last_ack, 谢特!

TCP 作为双向传输协议&#xff0c;如果你想只收不发&#xff0c;可以单向关掉发&#xff0c;shutdown(socket.SHUT_WR)&#xff0c;但不建议这么做。 看以下代码&#xff1a; #!/Users/zhaoya/myenv/bin/python3 # client import socketclient_socket socket.socket(socket.…

redis安装使用

1. 下载地址 :::color1 下载最新稳定版本的 redis-windows 7.x 版本(本实例以 7.2.3 为例) ::: # 下载地址 https://download.csdn.net/download/qq827245563/899238402. 解压文件 ![](https://img-blog.csdnimg.cn/img_convert/c094d561f7f8ed6e9d139d07be1271cb.png) 3. …

如果在 Ubuntu 24.04 上安装 Yarn ?

Yarn 是一种快速、可靠、安全的 JavaScript 项目依赖管理工具&#xff0c;它提供了比同类产品更好的缓存机制、网络性能和更直观的用户界面。作为现代 web 开发的基本工具&#xff0c;在系统上安装 Yarn 可以确保您可以有效地管理项目依赖关系。 他的文章将指导您通过 4 种有效…

【React 轮子】文本溢出后显示展开/收起按钮

/** hooks* 用于文本展示时判断是否展示 展开/收起按钮 &#xff08;包含监听 文本变化/页面尺寸变换&#xff09;* param { string } text 需要展示的文本* param { number } maxLength 文本最大展示行数* param { number } lineHeight 文本行高 (单位 px) */ import React, …

Python | Leetcode Python题解之第523题连续的子数组和

题目&#xff1a; 题解&#xff1a; class Solution:def checkSubarraySum(self, nums, k):d {0: -1}pre 0for index, num in enumerate(nums):pre numrem pre % ki d.get(rem, index)if i index:d[rem] indexelif i < index - 2:return Truereturn False

基于Matlab的图像去噪算法仿真

在信息化的社会里&#xff0c;图像在信息传播中所起的作用越来越大。所以&#xff0c;消除在图像采集和传输过程中而产生的噪声&#xff0c;保证图像受污染度最小&#xff0c;成了数字图像处理领域里的重要部分。 本文主要研究分析邻域平均法、中值滤波法、维纳滤波法及模糊小…

【计算机网络 - 基础问题】每日 3 题(五十九)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

滚珠导轨的存放与防锈保养

机床导轨是机床的重要组成部分&#xff0c;如果导轨生锈会影响机床的使用寿命和精度&#xff0c;因此必须采取措施进行防止。导轨生锈的原因主要是受到外界环境中的空气中的氧气和水蒸气等导致金属表面氧化腐蚀&#xff0c;另外&#xff0c;储存不当也会引起生锈。 一、滚珠导轨…

图技术发展简史

图数据库技术的本质是图计算与存储技术&#xff08;事实上所有IT技术在本质上都是计算、存储与网络&#xff0c;因为计算有网络计算、分布式计算&#xff0c;存储有网络存储、分布式存储&#xff0c;因此我们经常省略网络而只说计算和存储&#xff09;​&#xff0c;而图计算&a…

【C/C++】字符/字符串函数(1)——由string.h提供

零.导言 什么是字符/字符串函数呢&#xff1f; 其实就是一类用于处理字符和字符串的函数。 而其中一部分函数包含在头文件 string.h 中&#xff0c;有 strlen strcpy strcat strcmp strncpy strncat strncmp strstr strtok strerror 等等 接下来我将逐个讲解这些函数。 一.str…

【Linux】从内核角度理解 TCP 的 全连接队列(以及什么是 TCP 抓包)

文章目录 概念引入理解全连接队列内核方面理解Tcp抓包方法注意事项 概念引入 我们知道&#xff0c;TCP的三次握手是由TCP协议 自动处理的&#xff0c;建立连接的过程与用户是否进行accept无关&#xff0c;accept()的作用主要是为当前连接创建一个套接字&#xff0c;用于进行后…