栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Redis

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Redis

NoSQL数据库简介

用NoSQL打破了传统的关系型数据库,以业务逻辑为依据处理存储模式,针对不同数据结构的类型改变以性能为最优先的存储方式,目的就是提高性能

技术的分类:
1.解决功能性的问题(实现一个功能用的这些技术):Java、Jsp、RDBMS、Tomcat、HTML、Linux、JDBC、SVN
2.解决扩展性的问题(加入、修改功能需要用到的技术):Struts、Spring、SpringMVC、Hibrenate、Mybatis
3.解决性能的问题(解决用户量竞争访问,解决性能需要用到的技术):NoSQL、Java线程、Hadoop、Nginx、MQ、ElasticSearch

session的共享问题:
第一种方案:存储到客户端中,或是放在cookie中,好处:每次请求都会带有cookie中,里面都会有用户信息,能保证session共享,缺点:存到客户端中,安全问题

第二种方案:session复制,在第一台服务器登录了,产生了session对象,然后把session对象复制了多份到其他台服务器中,能保证session是同步的,缺点:session是复制的,复制的意思表示session对象是一样的,造成空间极大的浪费,每个里面都存储相同的对象

第三种方案:NoSQL数据库,可以吧用户信息存储到NoSQL数据库中,比如第一次登录后存储,第二次访问就看开NoSQL有没有信息,有的话就登陆,没有就不能登录,好处:不需要经过IO操作,数据完全存到内存中,读的速度更快,解决CPU和内存的方案

NoSQL解决IO压力

NoSQL数据库 NoSQL数据库概述

NoSQL(NoSQL = Not only SQL),意思是“不仅仅是SQL”,泛指非关系型数据库
NoSQL不依赖业务逻辑方式存储,而以简单的key-value模式存储,因此大大的增加了数据库的扩展能力

  • 不遵循SQL标准
  • 不支持ACID(原子性、可见性、隔离性、有序性)
  • 远超于SQL的性能
NoSQL适用场景
  • 对数据高并发的读写
  • 海量数据的读写
  • 对数据高可扩展性
NoSQL不适用场景
  • 需要事务支持
  • 基于sql的结构化查询存储吗,处理复杂的关系,需要即席查询
    (用不着sql的和用不了sql也不行的情况,请考虑用NoSQL)


行式存储数据库 行式数据库

列式数据库

Redis概述

配合关系型数据库做高速缓存
  • 高频次,热门访问的数据,降低数据库IO
  • 分布式架构,做session共享
多样的数据结构存储持久化数据

Redis安装

1.首先利用Xshell进入linux
2.安装c语言编译环境,gcc版本

yum install gcc

3.查询版本

gcc --version

4.进入opt文件夹(这里我是放在这个文件夹的)

5.解压redis压缩包

tar -zxvf 文件名

6.进入解压后的文件

7.使用make编译安装
注意:如果没有C语言编译环境,make会报错

进入src目录下执行make install

8.安装后进入 usr/local/bin 目录下有这么几个文件:

分别是:

前台启动:(不推荐)

redis-server

后台启动:(推荐)

  1. 回到 解压后 redis的文件夹
  2. 复制redis.conf文件到etc目录下
cp redis.conf /etc/redis.conf
  1. 后台启动设置daemonize no 改成 yes
vim redis.conf

进入文件夹

找到daemonize no改成yes

再次启动redis服务,并指定启动服务配置文件

 redis-server /etc/redis.conf

启动成功!

比如吧窗口关掉了,redis还在启动,因为是后台启动

  1. redis-cli 通过后端连接redis关闭,使用shutdown命令
Redis相关知识

端口6379从何而来:Alessia Merz(九键6379的对位)

Redis:单线程+多线IO复用

常用五大数据类型 Redis键(Key)
  1. keys * 查看当前库所有key
  2. exists key 判断某个key是否存在 返回1就表示有 返回0就是没有
  3. type key 查看你的key是什么数据类型
  4. del key 删除指定的key数据
  5. unlink key 根绝value选择非阻塞删除
  6. set key键 value值 增加操作
  7. expire key 10 为指定的key设置过期时间
  8. ttl key 查看还有多少s过期 -1永不过期 -2表示已过期
  9. select 切换库
  10. dbsize 查看当前库里又多少key
常用数据类型 字符串(String)

常用命令
  • set key value 添加键值对(设置相同的key就把之前的覆盖了)
  • get key 查询对应键值对
  • append key 将给的value值追加到原值的末尾
  • strlen key 获得值的长度
  • setnx key value 只有在key不存在时 设置key的值
  • incr key 将key中存储的数字值增1 只能对数字值操作,如果为空,新增值为1
  • decr key 将key中存储的数字值捡1 只能对数字值操作,如果为空,新增值为-1
  • incrby decrby key 步长 将key中存储的数字值增减 自定义步长 只能对数字值操作(步长:自定义数字)

原子操作

  • mset key1 key2… 同时设置一个或者多个key-value对
  • mget 同时获取一个或者多个key-value对
  • msetnx 同时设置一个或多个key-value对 仅当所有给定key都不存在
    原子性,有一个失效,都会失效
  • getrange key 起始位置 结束位置;获取值的范围(含头含尾)
  • setrange key 位置 覆盖的值 ;覆写key所存储的字符串值
  • setex key 过期时间 value值
  • getset key value 以新值换旧值
String数据结构


什么叫动态字符串?
就可以修改字符串的值

Redis 列表 (List)

常用命令

  • lpus/rpush key value1 value2 ;从左边/右边插入一个或多个值

    v1本来是在第一个格子,然后v2进来吧v1挤到第二个格子,v2就在第一个格子 以此类推
Redis列表(List) 常用命令


数据结构

quickList
List数据结构快速链表 quickList
首先在列表元素较少的情况会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表

它将所有的元素紧挨着一起存储,分配的是一块连续的内存

当数据量比较多的时候才会改成quickList

因为普通的链表需要的附加指针空间太大,会比较浪费空间,比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next


Redis将链表和ziplist结合起来组成了quicklist,也就是将多个ziplist使用双向指针串起来使用,这样既满足了快速的插入删除性能,又不会出现太大的空间冗余

Redis集合(Set)

Redis Set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的

Redis的set是string类型的无序集合,它底层其实是一个value为null的hash表,所以添加、删除、查找的复杂度是0(1)

一个算法,随着数据的增加,执行时间的长短,如果是0(1),数据增加,查找数据的时间不变

常用命令
  • sadd key value 将一个或者多个member元素加入到集合key中,已经存在的member元素将被忽略
  • smenbers key 取出该集合的所有值
  • sismember key value 判断集合key是否为含有该value值 有1 没有0
  • scard key 返回该集合的元素个数
  • srem key value 删除集合中的某个元素
  • spop key 随机从该集合中吐出一个值
  • srandmember key n 随机从该集合中取出n个值,不会从集合中删除
  • smove source destination value 吧集合中一个值从一个集合移动到另一个集合
  • sinter key1 key2 返回两个集合的交集*(相同的)元素
  • sunion key1 key2 返回两个集合的并集(所有的)元素
set数据结构

Java中HashSet内部实现使用的是HashMap,只不过所有的value都指向同一个对象,Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值

Redis哈希(Hash)

Redis hash是一个键值对集合

Redis hash是一个string类型的field合value的映射表,hash特别适合用于存储对象类似java里面的Map

用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构赖存储
主要有以下两种存储方式:

最好用hash存储方式:

通过key(用户ID)+field(属性标签)就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题

常用命令
  • hset key filed value 给key集合中的field键赋值value值
  • hget key field 从key1集合field取出value
  • hmset key1 field1 value1 field2 value2 批量设置hash的值
  • hexists ke1 field 查看哈希表key中,给定域field是否存在,真返回1 假返回0
  • hkeys key 列出该hash集合所有的field
  • hvals key 列出该hash集合所有的value
  • hincrby key field increment 为哈希表key中的域field的值加上增量1,加值
  • hsetnx key field value 将哈希表中的域field值设置为value 当且仅当域field不存在,field值有就不能加,没有就可以加
数据结构

Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表),当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable

配置文件

单位设置方式:
只支持bytes,不支持bit

网络相关配置:

bind
默认情况bind=127.0.0.1只能接受本机的访问请求
不写的情况下,无限制接受任何ip地址的访问

生产环境肯定要写你应用服务器的地址:服务器是需要远程访问的,所以需要将其注释掉

如果开起来protected-mode,那么在没有设定bind ip且没有设密码的情况下,Redis只允许接受本机的响应

开启保护模式:

改成no就是关闭保护模式,支持远程访问

tcp-backlog
设置tcp的backlog,backlog其实是一个链接队列,backlog队列总和=未完成三次握手队列+已经完成三次握手队列

在高并发环境下你需要意个高backlog值来避免客户端连接问题

监测心跳:

设置日志的输入路径

默认的库有多少 个

LIMITS限制
设置redis同时可以与多少个客户端进行连接
默认情况下为10000个客户端
如果达到了此限制,redis则会拒绝新的连接请求,并且向这些连接请求方发出max number of client reached 已做回应

Redis发布和订阅

什么是发布和订阅
Redis发布订阅(pub/sub)是一种消息通信 模式:发送者(pub)发送消息,订阅者(sub)接收消息

Redis客户端可以订阅任意数量的频道

发布订阅命令行实现

1.打开一个客户端订阅channe11
SUBSCRIBE channe11

2.打开另一个客户端,给channe11发布消息hello
publish channe11 hello

3.打开第一个客户端可以看到发送的消息

新数据类型-Bitmaps

简介:

Redis提供了Bitmaps这个“数据类型”可以实现对位的操作:
(1)Bitmaps本身不是一种数据类型,实际上它就是字符串(Key-value),但是它可以对字符串的位进行操作
(2)Bitmaps单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同,可以吧Bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在Bitmaps中叫做偏移量

offset:偏移量

格式:
setbit key offset value 设置Bitmaps 中某个偏移量的值(0或1)1设置被访问,0未访问
偏移量从0开始

getbit key offset 获取偏移量是否被访问过

bitcount
统计字符串被设置为1的bit数,一般情况下,给定的整个字符串都会被进行计数,通过指定额外的start或end参数,可以让计数只在特定的位上进行,start和end参数的设置,都可以使用负数值:比如-1 表示最后一个位,而-2表示倒数第二个位,start、end是指bit组的字节的下表述,二者皆包含

bitcount key 统计字符串start字节到end字节的比特值为1(被访问)的数量

bitop and unique:users:and:20201104_03
unique:users:20201103unique:users:20201104

Bitmaps与set对比

用户量大就用Bitmaps:

用户量小用set集合

新数据类型-HyperLogLog

统计页面访问量

在工作当中,我们经常会遇到与统计相关的功能需求,比如统计网站PV(PageView页面访问量),可以使用Redis的incr、incrby轻松实现

但像UV(UniqueVisitor,独立访客)、独立ip数、搜索记录数等需要去重和计数的问题如何解决?这种求集合中不重复元素个数的问题称为基数问题

解决基数问题有很多种方案:
(1)数据存储在MySQL表中,使用distinct count计算不重复个数
(2)使用Redis提供的hash、set、bitmaps等数据结构来处理
以上的方案结果精确,但随着数据不断增加,导致占用空间越来越大,对于非常大的数据集是不切实际的

是否能降低一定的精度来平衡存储空间?Redis推出了HyperLogLog

Redis HyperLogLog是用来做基数统计的算法,HyperLogLog的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的

在Redis里面,每个HyperLogLog键只需要花费12kb内存,就可以计算接近2^64个不同元素的基数,这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比

但是因为HyperLogLog只会根据输入元素来计算基数,而不会储存输入元素本身,所以HyperLogLog不能像集合那样,返回输入的各个元素

什么是基数

比如数据集{1,3,5,7,5,7,8,},那么这个数据集的基数集为{1,3,5,7,8}基数(不重复元素)为5,基数估计就是在误差可接受的范围内,快速计算基数

命令
pfadd key “elemnt” 添加指定元素到HeyperLogLog中, 成功1,失败0

pfcount key 统计基数

pfmerge destkey sourcekey 将一个或多个HLL合并后的结果存储在另一个HLL中,比如每月活跃用户可以使用每天的活跃用户合并计算可得

新数据类型-Geospatial

简介
Redis 3.2中增加了对GEO类型的支持,GEO,Geographic,地理信息的缩写,该类型,就是元素的2维坐标,在地图上就是经纬度,redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度hash等常见操作

有效的经度从-180 到 180度 纬度从-85.05112878到85.05112878

当坐标位置超出指定范围,该命令会返回一个错误,已经添加的数据,是无法再往里面添加的

命令
geoadd key longitude latitude member 添加地理位置

geopos key longitude 获取地理位置

geodist key member1 member2 获取两个位置之间的直线距离

单位: m 米 km 千米 mi 英里 ft 英尺

Redis客户端工具:Jedis操作-测试

Jedis所需要的jar包

		
            redis.clients
            jedis
            3.2.0
        

在Linux中防火墙:

systemctl status firewalld


关闭:

systemctl stop firewalld

操作key,得到redis里面所有的数据

@Test
    public void demo1() {
        Jedis jedis = new Jedis("192.168.255.100", 6379);
        Set keys = jedis.keys("*");
        for (String s : keys) {
            System.out.println(s);
        }
    }

添加key

//添加
    @Test
    public void demo2() {
        Jedis jedis = new Jedis("192.168.255.100", 6379);
        //添加
        jedis.set("name", "lucy");
        //获取
        String name = jedis.get("name");
        System.out.println(name);
        
        Set keys = jedis.keys("*");
        for (String s : keys) {
            System.out.println(s);
        }
    }

Jedis-API:String

//设置多个key-value
        jedis.mset("k1", "v1", "k2", "v2");
        List mget = jedis.mget("k1", "k2");
        System.out.println(mget);

Jedis-API:List

//操作list
    @Test
    public void demo3() {
        Jedis jedis = new Jedis("192.168.255.100", 6379);
        jedis.lpush("key1", "lucy", "mary", "jack");
        List key1 = jedis.lrange("key1", 0, -1);
        System.out.println(key1);
    }

Jedis-API:Set

//操作set
    @Test
    public void demo4() {
        Jedis jedis = new Jedis("192.168.255.100", 6379);
        jedis.sadd("names", "lucy");
        jedis.sadd("names", "mary");
        Set name = jedis.smembers("names");
        System.out.println(name);
    }

Jedis-API:Hash

//操作hash
    @Test
    public void demo5() {
        Jedis jedis = new Jedis("192.168.255.100", 6379);
        jedis.hset("users", "age", "20");
        String hget = jedis.hget("users", "age");
        System.out.println(hget);
    }
事务和锁机制-基本操作

Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序的执行,事务在执行的过程中,不会被其他客户端发送来的命令请求所打断

Redis事务的主要作用就是串联多个命令防止别的命令插队

Multi、Exec、discard

从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行
组队的过程中可以通过discard来放弃组队

事务的基本操作

表示已经开启了事务

新建队列

执行

放弃

事务的错误处理


如果执行某个阶段命令报了错误,则只有报错的命令不会被执行,其他的命令都会执行,不会回滚


组队不会报错,执行会报错,因为incr是自增+1,组队就放进去了,但是v1不是数字就不能加1,所以执行的时候会报错

事务和锁机制-事务冲突(悲观锁和乐观锁) 为什么要做成事务

想想一个场景:有很多人有你的账户,同时去参加双十一抢购

事务冲突的问题

悲观锁


悲观锁(Pessimistic Lock),顾名思义,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁,传统的关系型数据库里面就用到了很多这样的锁机制,比如行锁、表锁等,读锁、写锁等,都是在操作之前先上锁

乐观锁

通过版本号进行操作

乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制,乐观锁适用于多读的应用类型,这样可以提高吞吐量,Redis就是利用这种check-and-set机制实现事务的

演示乐观锁和事务特性

WATCH key[key…]
在执行multi之前,先执行waych key1[key2],可以监视一个(或多个)key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断

第一个:

第二个:

UNWATCH
取消WATCH命令对所有key的监视
如果在执行WATCH命令之后,EXEC命令或DISCARD命令先被执行了的话,那么就不需要在执行UNWATCH了

Redis事务三特性
  • 单独的隔离操作
    • 事务中的所有命令都会序列化、按顺序执行,事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
  • 没有隔离级别的概念
    • 队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行
  • 不保证原子性
    • 事务中如果有一条命令执行失败,其后的命令仍然会被执行,不会回滚
Redis主从复制

主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主

Redis主从复制-搭建一主多从

先在根目录下创建一个文件夹并进入:

复制redis.conf配置文件到文件夹中

配置一主两从的,创建三个配置文件
命名为:redis6379.conf、edis6380.conf、edis6381.conf

从之前conf文件中把appendonly yes改为no

在myredis下创建文件vi redis.conf

在配置文件中写入内容

用同样的方式创建6380、6381

启动三台redis服务器

查看进程的方式

ps -ef | grep redis


三台服务器连接6379 80 81

查看三台主机运行情况

info replication


配从不配主

slaveof ip port

在6380 6381上执行:slaveof 127.0.0.1 6379
加上后就能作为当前6379里面的从机操作



注意:从机里面不能做写操作,只能做读操作

复制原理的一主二从

主机挂掉了,从机也只认这一个主机
主机重新启动还是主服务器

主从复制-薪火相传和反客为主 薪火相传

上一个slave可以是下一个slave的master,slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个master可以有效减轻master的写压力,去中心化降低风险

用slaveof ip port
中途变更转向:会清除之前的数据,重新建立拷贝最新的
风险是一旦某个slave宕机,后面的slave都没法备份
主机挂了,从机还是从机,无法写数据了


从机之间连接

反客为主

用slaveof on one 将从机变成主机

哨兵模式

反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库(相当于一个谍报人员,从库加一个哨兵到主机,如果主机挂掉了,这个从库立马变为主机)

还原一主二从的搭建

自定义在/myredis 目录下新建sentinel.conf文件 名字绝不能错

sentinel monitor mymaster 127.0.0.1 6379 1


启动配置文件

redis-sentinel sentinel.conf 


当主机挂掉,从机选举中产生新的主机
先挂掉主机

然后哨兵这边自动显示

故障恢复


偏移量最大的替代被挂掉的主机,偏移量就是主机挂掉之前和某一个从机同步量最高的

集群

Redis集群

容量不够,redis如何进行扩容?

并发写操作吗,redis如何分摊?

另外主从模式,薪火相传模式,主机宕机,导致ip地址发生变化,应用程序中配置需要修改对应的主机地址、端口等信息

之前通过代理主机来解决,但是redis3.0中提供了解决方案,就是无中心化集群配置

任何一台服务器都可以作为集群的入口,比如通过订单进入集群,正好访问的不是用户数据,那么订单该怎么做?订单吧请求转移给用户去操作,比如现在有个操作也不是用户做的,那么用户就转移给商品,商品转移给订单,可以互相进行访问,这就是无中心化集群

什么是集群
Redis集群实现了对Redis的水平扩容,既启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N

Redis集群通过分区(Partition)来提供一定程度的可用性;即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求

搭建Redis集群

删除带有dump63的文件

rm -rf dump63*


更改redis6379的配置文件

复制出同样的几份分别为6380 6381 6389 6390 6391,并在文件里面做响应的修改

启动6379 6380 6381 6389 6390 6391配置文件

查询进程

ps -ef | grep redis


将六个节点合成一个集群
组合之前确保所有redis启动,nodex-xxxx.conf文件都生成正常


进入 /opt/redis/src目录下查找一个集成文件

在src目录下使用命令

redis-cli --cluster create --cluster-replicas 1 192.168.255.100:6379 192.168.255.100:6380 192.168.255.100:6381 192.168.255.100:6389 192.168.255.100:6390 192.168.255.100:6391 

此处不要用127.0.0.1 请用真实ip地址
–replicas 1 采用最简单的方式配置集群,一个主机,一个从机,正好三组

默认分配三组各组的主机

回答yes

-c采用集群策略连接 设置数据会自动切换到相应的写主机
任何一个节点可以作为中心的入口,他们之间可以互相访问

cluster nodes查看节点信息

集群操作和故障恢复

redis cluster如何分配六个节点
一个集群至少要有三个主节点

选项 --cluster-replicas 1 表示我们希望为集群中的每个主节点创建一个从节点

分配原则尽量保证每个主数据库运行在不同的ip地址,每个从库和 主库不在一个ip地址上

什么是slots
一个Redis集群包含16384个插槽(hash slots),数据库中的每个键都属于这16384个插槽的其中一个

集群使用公式CRC16(key)%16384来计算键key属于那个槽,其中CRC16(key)语句用于计算键key的CRC16检验和

如刚刚集群搭建成功给了个插槽:16384 slots covered.

比如刚刚创建的集群就有提示,三个主机每个主机都给了提示的插槽范围

比如set了一个键值

其实插槽就是吧每个值分配到每个插槽里面分摊,让他平均分摊压力

例如随机进入一个主机,新增一个值:

set k1 v1那么她计算后有个提示,【12706】,但是不属于6379插槽范围内,所以他自动切换到6381中,然后往里面添加数据由他来完成

不能一次性添加多个值,他会无法添加

如果想添加多个值,就分成组的形式

查询集群中的值

cluster keyslot k1


查询插槽中有几个键

cluster countkeysinslot 4847

用值返回count个slot槽中的键

getkeysinslot 449 1
故障恢复

主机挂机后,从机替换主机成为主机
先挂掉主机

随意进一台其他的主机

查看状态(6379挂掉了替代的是6381)

重新打开一个服务器重启6379(可以看到取而代之的主机是6381,6379变为了从机)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/446239.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号