1、mysql是关系型数据库,他的所有数据都会持久化到本地磁盘上,Redis是非关系型数据库他的数据保存在内存中但是Redis也支持持久化他的数据也可以保存到磁盘上
2、mysql支持事务的四大特性原子性、隔离性、一致性、持久性,而Redis虽然也支持事务,但是他没有同生共死的概念。
3、mysql对于高并发场景不适用,Redis可以支持10万+的并发量
4、Redis支持集群(主从同步)。数据可以主服务器向任意数量从的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。
计数器:比如注册人数,这种需要统计的数据,使用mysql来保存显然不合适因为会造成不必要的资源消耗
实时防攻击系统*:防止暴力破解,如使用工具不间断尝试各种密码进行登录。解决方案使用Redis记录某ip一秒访问到达10次以后自动锁定IP,30分钟后解锁
设定有效期的应用:设定一个数据,到一定的时间失效。验证码,登录过期, 自动解锁,购物券,红包。
自动去重应用:Uniq 操作,获取某段时间所有数据排重值 这个使用 Redis 的 set 数据结构最合适了,只需要不断地将数据往 set 中扔就行了,set 意为 集合,所以会自动排重。
队列:构建队列系统 使用 list 可以构建队列系统,使用 sorted set 甚至可以构建有优先级的队列系统。
秒杀:可以把名额放到内存队列(redis),内存就能处理高并发访问。
消息订阅系统:Pub/Sub 构建实时消息系统 Redis 的 Pub/Sub 系统可以构建实时的消息系统,比如很多用 Pub/Sub 构建的实时聊天系统 的例子。如QQ群
Redis下载链接 傻瓜式安装略过
Redis官方文档
incr key:自增
decr key:自减
.incrby key number:指定数字自增
decrby key number:指定数字自减
expire key secnods:设置指定key的过期时间
flushall:清空整个服务器的数据
select index:切换到指定的数据库,Redis默认有16个数据库当index为1时就是切换到第二个数据库
.flashdb:清除当前数据库
list的数据结构:key ...value
lpush key value value:将一个或多个值 value 插入到列表 key 的表头(最左边)
lrange key start stop:返回列表 key 中指定区间内的元素,查询所有的stop为-1即可
rpush key value value:将一个或多个值 value 插入到列表 key 的表尾(最右边)
lrem key count value:清除该key中前count个value值
lindex key index返回该key中下标为index的值
ltrim key start stop:对一个列表进行修剪 ,保留范围内的,范围外的删除
set的数据结构:key ...value (set会自动去重)
sadd key value value:将一个或多个元素加入到集合 key 当中已经存在于集合的元素将被忽略
smembers key:返回集合 key 中的所有成员。
srem key member:移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略
SCARD key:返回集合存储的key的基数 (集合元素的数量).如果key不存在,则返回 0。
ZSet:在Set基础上增加了“分数”,让set集合有了排序功能
ZSet结构为:key value(score) value(score) value(score)
zadd key value value:将所有指定成员添加到键为key
有序集合(sorted set)里面,如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置
Hash结构:KEY value(key value) (Hash类似于jdk中的Map,一个key下面以键值对的方式存储数据)
HSET key field value:设置 key 指定的哈希集中指定字段的值。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。如果字段在哈希集中存在,它将被重写。
存储对象的两种方式:
使用string结构:set user:1 {id:1,name:zs}
使用hash:hset user:2 {id:2,name:ls}
栈为先进后出,队列为先进先出,利用这个特性使用lpop key(移除并返回列表 key 的最左边元素。)和rpop key(移除并返回列表 key 的最右边元素)这两个命令即可实现
修改配置文件 redis.widows.conf ,查找requirepass将后面的代码改为密码,然后删掉#号
登录Redis:auth 密码
SUBSCRIBE cctv #cctv作为订阅的频道,可以任意定义名字
PUBLISH cctv ‘我是消息,发往cctv频道,over’ :开启一个redis-server 作为消息发送者,往 cctv 频道发布消息
Redis的淘汰策略
volatile-lru :从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据
淘汰策略配置
修改配置redis.window.conf ,修改maxmemory-policy ,放开注释,按情况修改策略
maxmemory-policy noeviction #noeviction 为默认的策略,根据情况修改
下载 jedis.jar
导入依赖
commons-pool2-2.2.jar #连接池
jedis-2.5.2.jar #Jedis核心包
连接池的使用(工具类封装)
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.util.Properties;
/**
* 获取连接池对象
*/
public enum RedisUtils {
//使用枚举实现单例
INSTANCE;
//连接池对象
private static JedisPool jedisPool = null;
static {
//初始化链接池
//1 创建连接池配置对象
JedisPoolConfig config = new JedisPoolConfig();
//2 进行配置-四个配置
最小连接数
config.setMaxIdle(1);
//最大连接数
config.setMaxTotal(11);
//链接最长等待时间
config.setMaxWaitMillis(10 * 1000L);
//测试连接时是否畅通
config.setTestOnBorrow(true);
String host = "127.0.0.1";
int port = 6379;
String password = "123456";
int timeout = 10000;
//创建连接池
jedisPool = new JedisPool(config, host,port,timeout, password);
}
//获取连接
public Jedis getSource() {
return jedisPool.getResource();
}
//关闭资源
public void closeSource(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
/**
* 设置字符值
*
* @param key
* @param value
*/
public void set(String key, String value) {
Jedis jedis = getSource();
jedis.set(key, value);
closeSource(jedis);
}
/**
* 设置字符值
*
* @param key
* @param value
* @param seconds :过期时间
*/
public void setex(String key,int seconds, String value) {
Jedis jedis = getSource();
jedis.setex(key,seconds, value);
closeSource(jedis);
}
/**
* 设置字符值
*
* @param key
*/
public String get(String key) {
Jedis jedis = getSource();
try {
return jedis.get(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeSource(jedis);
}
return null;
}
/**
* 设置
* @param key
* @param value
*/
public void set(byte[] key, byte[] value) {
Jedis jedis = getSource();
jedis.set(key, value);
closeSource(jedis);
}
/**
*
* @param key
* @return
*/
public byte[] get(byte[] key) {
Jedis jedis = getSource();
try {
return jedis.get(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeSource(jedis);
}
return null;
}
}
集群就是多个应用分散在不同的服务器,每个应用跑的是同一套代码做的是相同的工作,以提高系统的整体性能,简单理解"多个人在一起做相同的事情,每个人做的事情都是完整的,有点1+1=2的感觉"
防止单点故障
在没有集群时当一个服务器宕机那么整个项目都会挂掉,而有集群时当一个服务器挂掉时其他的服务器会承载挂掉的服务器的功能,从而使得整个项目还能继续运行
提升作业能力
一个服务器的能力是有限的,当并发量大时单服务器会顶不住压力,而集群可以
假如收银台排队的客户比较多,收银台可能也比较多,后面继续加入排队的客户可能无法选择人数最少的那个收银台进行排队,为了解决这一情况我们增加一个大显示屏来显示每个收银台的排队结账人数,那么结账客户可以就可以根据屏幕显示的人数来选择人数最少的收银台队列
单体应用包含了整个项目的所有代码和服务逻辑,也就是说一个Tomcat需要把整个系统跑起来,
这样就会导致Tomcat的压力非常大,在并发量大的时候就会捉襟见肘了,而分布式可以很好的解决掉这个问题
分布式就是将应用按照业务进行拆分成多个子应用,多个子应用部署在不同的服务器中,多个子应用组成一个完整的系统,所有的子系统一起工作相互通信相互协调才能完成最终的业务流程,缺一不可,简单理解:“多个人在一起做不同的事情,多人和在一起才是一件完整的事情,有点0.5+0.5=1的感觉”
简单说,集群就是“复制”,多个应用代码一样,功能一样,每个应用都是完整的系统,集群中的某个应用宕机也不影响。而分布式就是“拆分”,一个大的应用拆分成多子应用,每个应用代码不一样,功能也不一样,多个应用组合起来才是完整的系统,缺一不可。某个子应用宕机了,整个系统就不健康。
负载均衡
负载均衡能根据负载均衡算法把任务比较均衡地分布到集群环境下的计算和网络资源。
错误恢复
由于某种原因,执行某个任务的资源出现故障,另一服务实体中执行同一任务的资源接着完成任务。这种由于一个实体中的资源不能工作,另一个实体中的资源透明的继续完成任务的过程叫错误恢复。
当访问的服务器挂了时,集群要有能力找可以正常使用额服务器继续提供服务器。
Redis集群方案
Redis有三种集群方案,主从赋值,哨兵,cluster集群,主从复制是指将一台Redis服务器的数据,复制到其他的Redis服务器
。前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主节点到从节点。默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点
数据冗余
:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
故障恢复
:当主节点出现问题时可以由从节点提供服务实现快速的故障恢复;实际上是一种服务的冗余
负载均衡
:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
读写分离
:可以用于实现读写分离,主库写、从库读,读写分离不仅可以提高服务器的负载能力,同时可根据需求的变化,改变从库的数量。
高可用基石
:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
不具备自动容错和恢复功能
:主从宕机会影响前端的部分请求失败,需要重启机器或者手动切换前端IP才能恢复
主机宕机数据丢失
:宕机前部分有部分数据未同步到从机,切换IP后会引入数据不一致降低系统可用性
数据大的问题
:数据量特别大一个主是存储不了