赞
踩
缓存是改善性能的第一手段
no only sql : 泛指一切非关系型数据库
内容 | 意义 | |
---|---|---|
daemonize | 是否开启守护程序默认 | daemonize no |
port | 端口号 | port 6379 |
databases | 开启多少个数据库 | databases 16 |
maxmemory | 配置内存大小 | maxmemory 200mb |
requirepass | 设置请求密码 | requirepass 123456 |
2.docker启动redis
docker start redis #底层也是通过redis-server启动
# 进入容器
docker exec -it redis bash
# 正常连接redis
redis-cli
# 指定IP端口连接
redis-cli -h 127.0.0.1 -p 6379
命令 | 作用 |
---|---|
exit | 退出 |
shutdown | 关闭 |
keys | 键(keys * 查看所有数据) |
select | 更换数据库 |
exists | 判断一个键是否存在 |
del | 删除一个键或者多个 |
type | 获取键值的数据类型 |
flushall | 清空所有数据库 |
flushdb | 清除当前数据库 |
两种数据持久化方案,分别为rdb和aof
# 打开redis.conf文件,找到save 位置,去配置持久化
save 60 1000 # 每隔60秒,1000个数据发生改变就持久化
# redis配置文件redis.conf
appendonly yes # redis每次接收到一条写命令,就会写入日志文件中
区别:
3. 一个是持续的用日志记录写操作, crash(崩溃)后利用日志恢复, 愿意一些性能, 换取更高的缓存一致性(aof)
4. 一个是平时写操作的时候不触发写, 只有手动提交save命令, 或者是shutdown关闭命令时, 才触发备份操作, 操作频繁的时候, 不启用备份来换取更高的性能(rdb)
命令 | 作用 |
---|---|
multi | 开启事务 |
exec | 提交事务 |
discard | 取消事务 |
watch | 监控,如果监控的值发生变化,则提交事务时会失败 |
unwatch | 去掉监控 |
1.Expire (设置生效时长-单位秒)
语法:EXPIRE key seconds
2.Persist(取消时长设置)
语法:PERSIST key
3.pexpire(单位毫秒)
语法:PEXPIRE key milliseconds
应用于秒杀场景
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.2</version>
</dependency>
@Test
void testRedisStringOper(){
Jedis jedis=new Jedis("192.168.126.130", 6379);
//jedis.auth("123456");假如你的redis设置了密码
jedis.set("id", "101");
jedis.set("name", "tony");
System.out.println("set ok");
String id=jedis.get("id");
String name=jedis.get("name");
System.out.println("id="+id+";name="+name);
jedis.incr("id");
jedis.incrBy("id", 2);
System.out.println(jedis.strlen("name"));
//......
}
@Test void testJedisPool(){ // 构建连接池配置信息 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); // 设置最大连接数 jedisPoolConfig.setMaxTotal(200); // 构建连接池 JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.174.130", 6379); // 从连接池中获取连接 Jedis jedis = jedisPool.getResource(); // 读取数据 System.out.println(jedis.get("name")); // 释放连接池 jedisPool.close(); }
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring:
redis:
host: 192.168.126.130
port: 6379
@SpringBootTest public class StringRedisTemplateTests { /**此对象为spring提供的一个用于操作redis数据库中的字符串的一个对象*/ @Autowired private StringRedisTemplate stringRedisTemplate; @Test void testRedisStringOper()throws Exception{ //获取用于操作字符串的值对象 ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue(); //向redis中存储数据 valueOperations.set("ip", "192.168.174.130"); valueOperations.set("state","1",1, TimeUnit.SECONDS); valueOperations.decrement("state"); // Thread.sleep(2000); //从redis中取数据 String ip=valueOperations.get("ip"); System.out.println("ip="+ip); String state=valueOperations.get("state"); System.out.println("state="+state); } }
@SpringBootTest public class RedisTemplateTests { /** * 通过此对象操作redis中复杂数据类型的数据,例如hash结构 */ @Autowired private RedisTemplate redisTemplate; @Test void testSetData(){ SetOperations setOperations=redisTemplate.opsForSet(); setOperations.add("setKey1", "A","B","C","C"); Object members=setOperations.members("setKey1"); System.out.println("setKeys="+members); //........ } @Test void testListData(){ //向list集合放数据 ListOperations listOperations = redisTemplate.opsForList(); listOperations.leftPush("lstKey1", "100"); //lpush listOperations.leftPushAll("lstKey1", "200","300"); listOperations.leftPush("lstKey1", "100", "105"); listOperations.rightPush("lstKey1", "700"); Object value= listOperations.range("lstKey1", 0, -1); System.out.println(value); //从list集合取数据 Object v1=listOperations.leftPop("lstKey1");//lpop System.out.println("left.pop.0="+v1); value= listOperations.range("lstKey1", 0, -1); System.out.println(value); } /**通过此方法操作redis中的hash数据*/ @Test void testHashData(){ HashOperations hashOperations = redisTemplate.opsForHash();//hash Map<String,String> blog=new HashMap<>(); blog.put("id", "1"); blog.put("title", "hello redis"); hashOperations.putAll("blog", blog); hashOperations.put("blog", "content", "redis is very good"); Object hv=hashOperations.get("blog","id"); System.out.println(hv); Object entries=hashOperations.entries("blog"); System.out.println("entries="+entries); } }
Redis中的分片思想就是把鸡蛋放到不同的篮子中进行存储。因为一个redis服务的存储能力是有限。分片就是实现redis扩容的一种有效方案。
docker run -p 6379:6379 --name redis01 \
-v /usr/local/docker/redis02/data:/data \
-v /usr/local/docker/redis02/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf
docker run -p 6380:6379 --name redis02 \
-v /usr/local/docker/redis03/data:/data \
-v /usr/local/docker/redis03/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf
docker run -p 6381:6379 --name redis03 \
-v /usr/local/docker/redis03/data:/data \
-v /usr/local/docker/redis03/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf
@Test //分片 public void shard(){ //构造各个节点链接信息,host和port List<JedisShardInfo> infoList = new ArrayList<JedisShardInfo>(); JedisShardInfo info1 = new JedisShardInfo("192.168.126.130",6379); //info1.setPassword("123456"); infoList.add(info1); JedisShardInfo info2 = new JedisShardInfo("192.168.126.130",6380); infoList.add(info2); JedisShardInfo info3 = new JedisShardInfo("192.168.126.130",6381); infoList.add(info3); //分片jedis JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(500); //最大链接数 ShardedJedisPool pool = new ShardedJedisPool(config, infoList); //ShardedJedis jedis = new ShardedJedis(infoList); ShardedJedis jedis = pool.getResource(); //从pool中获取 for(int i=0;i<10;i++){ jedis.set("n"+i, "t"+i); } System.out.println(jedis.get("n9")); jedis.close(); }
缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。
解决:
双缓存的实现过程:从缓存 A 读数据库,有则直接返回;A 没有数据,直接从 B 读数据,直接返回,并且异步启动一个更新线程,更新线程同时更新缓存 A 和缓存 B。
最经典的操作是:Cache Aside Pattern旁路缓存方案
第一种方案:采用延时双删策略
在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。
1.具体的步骤就是:
2.设置缓存过期时间
从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。所有的写操作以数据库为准,只要到达缓存过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。
3.该方案的弊端
结合双删策略+缓存超时设置,这样最差的情况就是在超时时间内数据存在不一致,而且又增加了写请求的耗时。
第二种方案:异步更新缓存(基于消息队列)
订阅binlog消息的同步机制
binlog: mysql 的二进制日志文件
实现思路: MySQL binlog增量订阅消费 --> 消息队列 --> 增量数据更新到redis
操作:
读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。
这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。
其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据一致性。
消息队列: rabbitmq rocketmq
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。