一、Redis介绍 现存问题:
关系型数据查询效率问题 单体架构搭建集群后,数据不同步(Session数据不共享) 单体架构搭建集群后,或者分布式架构中,传统的锁操作问题 高并发读写数据问题,海量数据问题 NoSQL:
Not only SQL Redis是一个key-value的非关系型数据库 Redis介绍:
Redis是基于C语言编写的。 Redis是基于Key-Value存储数据的,并且对Value提供了丰富的数据结构。 Redis是基于内存存储数据的,并且提供了响应的持久化操作。 Redis在接收客户端请求时,是单线程接收处理,后续操作还是多线程。 Redis还提供了各种主从,哨兵,集群的架构模式,方便弹性伸缩。 Redis的读写能力,读的速度是110000次/s,写的速度是81000次/s 。 二、安装Redis docker-compose.yml:
version: '3.1'
services:
redis:
restart: always
image: 10.9.12.254:5000/redis:5.0.7
container_name: redis
ports:
- 6379:6379
复制
通过Redis容器内部的redis-cli命令连接Redis服务
进入Redis容器:docker exec -it redis bash 执行Redis客户端命令:redis-cli
图形化界面连接Redis(Redis DeskTop Manager)
三、Redis的存储结构 最常用的五种:
key-string:value就是存储一个值 key-hash:value就是一个Map结构,一般用于存储Java中的对象 key-list:value就是一个列表,理解为是一个ArrayList,允许重复,存取有序,有下标 key-set:value就是一个集合,理解为HashSet,不允许重复,存取无序,没有下标 key-zset:value就是一个有序的集合,在HashSet的基础上,给每一个值提供一个分数,根据分数排序 不常用的三种:
HyperLogLog:用来做统计运算的,在丢失一部分精准度的前提下,占用更少的内存,更高效的运算出统计结果。 GEO:存储经纬度的。 位图:存储bitmap结构。 四、Redis常用命令 set key value:针对string结构,添加一个key和value get key:针对string结构,通过key获取value setex key second value:针对string结构,添加一个key和value的同时,设置生存时间,单位是秒 expire key second :针对key,给key设置生存时间 del key:针对key,删除key和具体的value hset key field value:针对hash结构,设置一个key和一个field以及value hget key field:针对hash结构,通过key和field获取一个value hmset key field value [field value …]: 针对hash结构,批量添加操作 hgetall key:针对hash结构,获取全部的field value数据 五、Java操作Redis 创建项目 导入依赖 junit,jedis,lombok,spring-context 编写测试类 六、Redis的其他命令 存值: set key value:设置一个key,value mset key value [key value …]:批量添加一个/多个key,value setex key second value:设置key,value的同时,给key设置生存时间 setnx key value:当key不存在时,正常的执行set功能,如果key存在,什么事都不做 取值: get key:通过key获取value mget key [key …]:批量获取数据 自增/自减 incr key:针对key的value自增1 decr key:针对key的value自减1 incrby key increment:针对key的value自增increment decrbykey increment:针对key的value自减increment 其他 strlen key:查看key对应的字符串长度 append key value:在key字符串后,追加上value hash的常用命令 存值: hset key field value:设置field value结构数据到hash中 hmset key field value [field value …]:批量添加field和value到hash中 取值 hget key field:通过key和field获取一个value hmget key filed [field]:通过key和一个/多个field获取value hgetall key:通过key获取全部的field和value 其他 hdel key field:删除field,不删除key hlen key:获取当前hash结构中field的数量 list的常用命令 存值: lpush key value [value …]:从列表的头部插入数据 rpush key value [value …]:从列表的尾部插入数据 取值 lrange key start stop:获取指定列表的从start开始查看到stop的全部数据,stop为-1,代表最后一个 lpop key:从头部移除并获取数据结果 rpop key:从尾部移除并获取数据结果 其他操作 lrem key count value:删除当前列表中count个value,count > 0 从头删,count < 0 从尾删,count = 0,删除全部的value ltrim key start stop:保留当前列表从start到stop的数据,其余数据删除 set的常用命令 存值 sadd key member [member …]:存值操作 取值 smembers key:获取全部数据 spop key [count]:随机获取一个值,并删除 srandmember key [count]:随机获取一个值,不删除 集合操作 sinter key [key …]:交集操作 sunion key [key …]:并集操作 sdiff key [key …]:差集操作 其他操作 srem key member [member …]:删除集中的元素 sismember key member:查看当前元素是否在集合中 scard key :查看当前集合长度 zset常用命令 存值: zadd key score member [score member …]:添加数据,并设置分数 取值 基于下标取值 zrange key start stop [withscores]:基于下标范围取值 zrevrange key start stop [withscores]:基于下标,从大到小的范围取值 基于分数取值 zrangebyscore key min max [withscores] [limit offset count]:根据分数的范围,从小到大取 zrevrangebyscore key max min [withscores] [limit offset count]:根据分数的范围,从大到小取 -inf +inf:无穷小,无穷大 (min (max:不带等于效果 其他操作 zincrby key score member:增加某个member的分数 key的常用命令 生存时间: expire key second:给key设置生存时间 pexpire key millionsecond:给key设置生存时间,单位:毫秒 expireat key timestamp:设置key能生存到什么时间节点 pexpireat key milliontimestamp:设置key能生存到什么时间节点,单位:毫秒 ttl key:查看key剩余的生存时间,-2(key不存在),-1(没有生存时间),0~+inf(单位秒) pttl key:查看key剩余的生存时间,-2(key不存在),-1(没有生存时间),0~+inf(单位毫秒) persist key:去除key的生存时间 查看key信息: keys patterns:查看当前库中的全部key,并返回 patterns可以编写通配符 * 删除key: db的常用命令 flushdb:清空当前库 flushall:清空所有库 dbsize:查看key的数量 七、Java操作Redis 使用Jedis对key和value进行操作。 为了存储对象: 基于jackson等json工具,将对象序列化为json字符串,存储到Redis 基于序列化工具,将对象序列化为byte[],存储到Redis 使用JedisPool连接池操作,避免频繁的创建Jedis和销毁Jedis造成的性能的损耗 Jedis的管道操作: 当需要将大量的信息存储到Redis时,如果一次一次的将命令推送给Redis,在传输的过程中,消耗的时间是比较长的。 直接在客户端位置,将大量操作命令封装到管道中,一次性将全部命令发送给Redis服务。 八、改造项目 将WebMaster部署到Linux操作系统中
在Windows下成功启动: 创建了数据库,并且将脚本文件导入到数据库中 将连接数据库的db.properties文件的密码,修改为自己数据库的密码 启动项目,访问功能没有问题 将连接数据库的url等内容修改为Linux操作系统中的 将工程打成war包 将war包部署到Linux操作系统中 构建Dockerfile将openapi工程部署到Tomcat(JDK)的Docker容器中 Dockerfile: FROM daocloud.io/library/tomcat:8.5.55-jdk8
WORKDIR /usr/local/tomcat/webapps
RUN rm -rf *
RUN mkdir ROOT
COPY openapi.war /usr/local/tomcat/webapps/ROOT
WORKDIR /usr/local/tomcat/webapps/ROOT
RUN jar -xf openapi.war
复制
docker-compose.yml:
version:
services:
openapi0:
build: ./openapi
image: openapi:1.0
container_name: openapi
ports:
- 8080:8080
openapi1:
build: ./openapi1
image: openapi1:1.0
container_name: openapi1
ports:
- 8081:8080
mysql:
image: 10.9.12.254:5000/mysql:5.7.24
container_name: mysql
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: root
TZ: Asia/Shanghai
command:
--lower_case_table_names=1
volumes:
- ./mysql_data/:/var/lib/mysql/
nginx:
image: 10.9.12.254:5000/nginx:lastest
container_name: nginx
ports:
- 80:80
volumes:
- ./conf.d/:/etc/nginx/conf.d/
复制
通过Nginx代理到某一个服务器上时,会造成在8080或者8081的Tomcat服务器上登录,Tomcat服务器会给客户端返回一个JSessionID的Cookie值,客户端再次请求时,会携带这个JSessionID,并且会通过JSessionID去Tomcat中找Session,如果找到Session,直接使用,如果找不到,重新创建一个Session,并且需要返回一个全新的JSessionID。
九、Redis的配置信息 给Redis设置密码连接 设置密码连接的方式:
在第一次启动Redis后,可以直接通过客户端设置密码:CONFIG set requirepass password 修改Redis的配置文件,添加:requirepass password 修改docker配置映射Redis配置文件,并保证启动时,加载配置文件
创建数据卷映射Redis容器的目录 添加配置文件:redis.conf,并编写上述配置: 修改docker-compose.yml:
version: '3.1'
services:
redis:
restart: always
image: 10.9.12.254:5000/redis:5.0.7
container_name: redis
ports:
- 6379:6379
volumes:
- ./conf:/conf
command: ["redis-server","/conf/redis.conf"]
复制
三种客户端连接Redis:
图形化界面:在验证选项中,添加密码即可。 redis-cli:需要在执行命令之前,先执行auth password Jedis: jedis.auth(“password”); 使用JedisPool由有参构造设置: public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password) { ...}
复制
十、Redis的事务 Redis的事务是将一系列命令存放到一个队列中,exec后一起执行,该成功的成功,该失败的失败。 multi:开启事务 (开启事务后,所有后续的命令都会被放到队列中) exec:执行事务 discard:取消事务 Redis的事务时相对比较鸡肋的,一般情况下,配置watch去使用Redis的事务 watch key [key …]:会监听一个或多个key的写操作,当有写操作后,可以配置Redis的事务自动取消 unwatch:当事务执行或者取消后,自动执行unwatch 十一、Redis的持久化(重要) RDB持久化机制:
RDB默认开启 RDB存储二进制数据,RDB在持久化和读取持久化文件时,速度较快 RDB持久化的时机: save second keys
# 在second时间内,执行了key次写操作,就执行RDB的持久化
复制
优缺点:持久化效率高,RDB持久化时机导致RDB策略不安全 ,数据可能会丢失。 AOF持久化机制: AOF默认关闭,需要将appendonly yes手动开启 RDB默认持久化日志文件,将每次写操作的命令持久化到本地文件中,在持久化和读取持久化文件时,相对RDB较慢 RDB的持久化时机: appendfsync always # 每次执行写操作,立即执行AOF持久化
appendfsync everysec # 每秒执行一次AOF持久化,(推荐)
appendfsync no # Redis不去执行,由当前操作系统自动时间,时间不确定
复制
优缺点:相对RDB更安全,但是持久化效率文件大小相对RDB较差 官网推荐同时开启RDB和AOF两种持久化机制: 在恢复数据时,AOF的优先级高于RDB RDB在执行持久化时,会通过AOF文件执行,导致AOF文件会覆盖RDB AOF持久化会存储很多无意义的命令,在期间针对一个key进行了多次写操作,可能只有最后一条写操作有效,AOF文件需要重写操作: auto-aof-rewrite-percentage 100 # 默认AOF文件超过基准大小的100%时
auto-aof-rewrite-min-size 64mb # 默认AOF文件超过64M
复制
手动重写:
bgrewriteaof # 手动在客户端执行当前命令,即可重写
#重写后的内容,会以二进制形式存在,再次执行写操作,还时以日志形式存储命令
复制
十二、Redis的主从架构 现存问题: Redis的读写性能的瓶颈,单台Redis最多只能110000/s左右的读取性能,81000/s左右的写性能。 主从架构: Redis的主从架构需要搭建多台Redis服务,并且由一台作为Master,其他作为Slave Master节点负责读写操作,Slave节点只负责读操作 Slave会主动找Master同步数据,并且多台Slave之间没有关联 一台Master可以由多个Slave,一台Slave只能属于一个Master 搭建主从架构: replicaof <masterip> <masterport> # 设置master节点的ip和port
masterauth <master-password> # 设置master节点的AUTH密码
复制
十三、Redis的哨兵 现存问题: 主从架构虽然可以提升Redis的读取数据的瓶颈,但是当Master节点宕机后,主从架构无法进行写操作。 主从 + 哨兵: 哨兵的搭建是在主从架构基础上的,目的是为了解决主从的单点故障问题。 需要在每台Redis节点上都搭建一个哨兵,并且让哨兵之间可以相互通讯。 当Master节点宕机后,需要根据哨兵的投票结果,来确定Master是否真的宕机。 搭建主从 + 哨兵: 由于使用Docker搭建Redis的主从 + 哨兵,需要使用yml文件中的links顺序,来确定容器的名称,并且使用容器内部的端口。 准备yml文件: version: "3.1"
services:
redis1:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis1
environment:
- TZ=Asia/Shanghai
ports:
- 7001:6379
volumes:
- ./conf/redis1.conf:/usr/local/redis/redis.conf # 提前将文件构建出来
- ./conf/sentinel1.conf:/data/sentinel.conf # 添加的内容
command: ["redis-server","/usr/local/redis/redis.conf"]
redis2:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis2
environment:
- TZ=Asia/Shanghai
ports:
- 7002:6379
volumes:
- ./conf/redis2.conf:/usr/local/redis/redis.conf
- ./conf/sentinel2.conf:/data/sentinel.conf # 添加的内容
links:
- redis1:master
command: ["redis-server","/usr/local/redis/redis.conf"]
redis3:
image: daocloud.io/library/redis:5.0.7
restart: always
container_name: redis3
environment:
- TZ=Asia/Shanghai
ports:
- 7003:6379
volumes:
- ./conf/redis3.conf:/usr/local/redis/redis.conf
- ./conf/sentinel3.conf:/data/sentinel.conf # 添加的内容
links:
- redis1:master
command: ["redis-server","/usr/local/redis/redis.conf"]
复制
准备redis.conf和sentinel.conf文件
#redis.conf (从)
replicaof master 6379
# ============================================================
# sentinel.conf
# 哨兵需要后台启动
daemonize yes
# 指定Master节点的ip和端口(主)
sentinel monitor master localhost 6379 2
# 指定Master节点的ip和端口(从)
sentinel monitor master master 6379 2
# 哨兵每隔多久监听一次redis架构
sentinel down-after-milliseconds master 10000
复制
十四、Redis集群(重要) Redis集群的特点 搭建过程 准备Redis的配置文件
# redis.conf
# 指定redis的端口号
port 端口号
# 开启Redis集群
cluster-enabled yes
# 集群信息的文件
cluster-config-file 集群节点名称
# Docker安装需要配置
# 集群的对外ip地址
cluster-announce-ip 192.168.11.11
# 集群的对外port
cluster-announce-port 7006
# 集群的总线端口
cluster-announce-bus-port 17006
复制
准备2n + 1个节点,再配上至少1个slave节点 启动6个Redis节点后,集群并没有启动,启动集群需要执行: redis-cli --cluster create ip:port ... ipN:portN --cluster-replicas <args>
复制
客户端连接Redis集群 redis-cli: redis-cli -h ip地址 -p 端口号 -c 图形化界面: 连接任意一个几点即可,查看到整个Redis集群中的数据 Java中通过Jedis连接集群: 十五、Redis的常见问题(重要) 删除策略: Redis中的key到了生存时间,一定会被删除吗?
定期删除:默认情况下每100ms查询3个设置了生存时间的key,查看是否到期。 惰性删除:当你去查询一个设置了生存时间的key时,Redis会查看生存时间是否到期,如果到期,直接删除当前key,并且返回一个空。 淘汰机制 volatile(设置生存时间的key),lru(最近最少使用),lfu(最近最少频次使用) volatile-lru -> Evict using approximated LRU among the keys with an expire set. allkeys-lru -> Evict any key using approximated LRU. volatile-lfu -> Evict using approximated LFU among the keys with an expire set. allkeys-lfu -> Evict any key using approximated LFU. volatile-random -> Remove a random key among the ones with an expire set. allkeys-random -> Remove a random key, any key. volatile-ttl -> Remove the key with the nearest expire time (minor TTL) noeviction -> Don’t evict anything, just return an error on write operations,抛异常 缓存的各种问题: version: "3.1"
services:
elasticsearch:
image: daocloud.io/library/elasticsearch:7.6.2
restart: always
container_name: elasticsearch
ports:
- 9200:9200
environment:
- "discovery.type=single-node"
- "ES_JAVA_OPTS=-Xms256m -Xmx256m"
volumes:
- ./data:/usr/share/elasticsearch/data
kibana:
image: daocloud.io/library/kibana:7.6.2
restart: always
container_name: kibana
ports:
- 5601:5601
environment:
- elasticsearch_url=http://你虚拟机的ip地址:9200
depends_on:
- elasticsearch
复制