商品类目添加缓存
1)将结果数据保存到redis中,注意key的定义,不要太长,不要相同。将java对象序列化成json字符串,同时可设置生存时间。
2)检测缓存中是否存在,如果存在就返回。不存在就直接去数据库进行查询。(如果有异常,要捕获处理,不能影响正常业务逻辑)
修改ItemCatService.java文件
package com.jt.manage.service;
import java.io.IOException;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jt.common.service.RedisService;
import com.jt.manage.mapper.ItemCatMapper;
import com.jt.manage.pojo.ItemCat;
@Service
public class ItemCatService extends BaseService<ItemCat>{
@Autowired
private ItemCatMapper itemCatMapper;
@Autowired
private RedisService redisService;
//引入java对象和json串转换对象ObjectMapper;全局唯一
private static final ObjectMapper MAPPER = new ObjectMapper();
public List<ItemCat> queryByPid(Integer id) throws IOException{
/*
* 商品分类要使用缓存步骤:
* 1)先判断缓存中是否有数据,如果有数据就读取,直接返回
* 2)如果缓存中没有数据,要继续执行业务,不能抛出异常
* 3)执行完业务,要多一步动作,要把结果放入缓存中string,先把java对象转换成json串,kv写入缓存中。
*/
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
String ITEM_CAT_KEY = "ITEM_CAT_" + id; //唯一性
//从redis中获取数据
String jsonItemCat = redisService.get(ITEM_CAT_KEY);
if(StringUtils.isNotEmpty(jsonItemCat)){
JsonNode jsonNode = MAPPER.readTree(jsonItemCat); //把json串转换JsonNode
//利用jackson提供方法,将json串转成java对象,List<Object>
List<ItemCat> itemCatList = MAPPER.readValue(jsonNode.traverse(),
MAPPER.getTypeFactory().constructCollectionType(List.class, ItemCat.class));
return itemCatList;
}else{
//继续执行业务,一般都是去数据库访问
List<ItemCat> itemCatList = itemCatMapper.queryByPid(id);
//写redis,kv(string,string)
jsonItemCat = MAPPER.writeValueAsString(itemCatList); //将java对象转成json串
redisService.set(ITEM_CAT_KEY, jsonItemCat);
return itemCatList;
}
}
}
Redis主从复制
主从复制
cp redis.conf redis-master.conf #主节点配置
redis-server redis-master.conf #启动主
cp redis.conf redis-slave01.conf #从1配置,修改端口 6380
redis-server redis-slave01.conf #启动从1
redis-cli –p 6380 #登录从1
slaveof 127.0.0.1 6379 #挂接到主
cp redis.conf redis-slave02.conf #从2配置,修改端口6381
redis-server redis-slave02.conf #启动从2
redis-cli –p 6381 #登录从2
slaveof 127.0.0.1 6379 #挂接到主
检查配置
info #查看所有信息
info Replication #只查看Replication片段信息
查看结果,确认状态
127.0.0.1:6379> info Replication
# Replication
role:master #说明master生效
connected_slaves:2 #master主节点下有两个从节点
slave0:ip=127.0.0.1,port=6380,state=online,offset=845,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=845,lag=1
master_repl_offset:845
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:844
127.0.0.1:6379>
测试
127.0.0.1:6379>set name tony
127.0.0.1:6380>get name #读取到同步的信息
127.0.0.1:6381>get name
127.0.0.1:6381>set name hellen #报错,从上不允许设置数据
(error) READONLY You can't write against a read only slave.
Redis哨兵实现HA高可用
哨兵实现实时冗余备份和容灾,但不支持分片。
哨兵sentinel
Redis Sentinel(哨兵)是一个分布式系统,你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息,并使用投票协议(agreement protocols)来决定是否执行自动故障迁移,以及选择哪个从服务器作为新的主服务器。
Sentinel系统用于管理多个Redis服务器(instance),该系统执行以下三个任务:
- 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
- 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时,Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
- 自动故障迁移(Automatic failover):当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作,它会将失效主服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时,集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
哨兵的工作原理
sentinel以每10秒一次的频率向master发送info命令,通过info的回复来分析master信息,master的回复主要包含了两部分信息,一部分是master自身的信息,一部分是master所有的slave(从)的信息,所以sentinel可以自动发现master的从服务。sentinel从master获取到的master自身信息以及master所有的从信息,将会更新到sentinel的sentinelState中及masters(sentinelRedisInstance结构)中的slaves字典中。
哨兵sentinel-实现高可用
哨兵sentinel类似zookeeper。它含有监控,监控每个节点的活跃状态。
上面配置了3个节点,但如果主宕机,整个缓存系统就瘫痪,如何实现主宕机,自动从多个从中选举出一个节点当主呢?redis在3.0版本之后提供了哨兵sentinel。通过哨兵实现高可用。
但一个哨兵也可能宕机,一次启动两个哨兵,自身也实现高可用。
cp sentinel.conf sentinel2.conf #复制哨兵
26379为26380 #修改端口
sentinel monitor mymaster 192.168.163.20 6379 1 #设置访问名称
#最后的数值为选举时过票数量(坑)
redis-sentinel sentinel.conf #启动哨兵
redis-sentinel sentinel2.conf #启动哨兵2,形成哨兵的高可用
ps –ef|grep redis #查看进程
6010 5709 0 00:38 pts/2 00:00:13 redis-server 127.0.0.1:6379
6012 5710 0 00:38 pts/2 00:00:13 redis-server 127.0.0.1:6380
6014 5721 0 00:38 pts/3 00:00:13 redis-server 127.0.0.1:6381
6018 5927 1 00:39 pts/6 00:00:21 redis-server *:26379 [sentinel]
6047 6037 1 00:41 pts/7 00:00:19 redis-server *:26380 [sentinel]
6241 2512 0 01:10 pts/1 00:00:00 grep redis
测试
kill 6010 #可以看到slave的两个节点开始报链接拒绝错误,不一会哨兵将6380切换为主
info #在6380上info命令,可以看到其role:master
kill 6018 #删除一个哨兵,在6380上set数据,6381自动同步
sentinel的坑
开放端口或者关闭防火墙
6379,6380,6381
26379,26380
service iptables stop
protected-mode
默认情况下,Redis node和sentinel的protected-mode都是yes,在搭建集群时,若想从远程连接redis集群,需要将redis node和sentinel的protected-mode修改为no,若只修改redis node,从远程连接sentinel后,依然是无法正常使用的,且sentinel的配置文件中没有protected-mode配置项,需要手工添加。
远程访问拒绝
sentinel.conf默认配置
sentinel monitor mymaster 127.0.0.1 6380 1
当redis和sentinel在一台服务器上时,必须指定实际的IP地址
sentinel monitor mymaster 192.168.163.30 6380 1
选举数
sentinel.conf中96行左右的位置
sentinel monitor mymaster 127.0.0.1 6379 2
最后的2代表选举的个数,这个值非常关键。其中的2表示只有在两个sential进程发现master不可用时才执行failover故障转移。例如:即使一个master宕机,如果投票个数未超过1个,redis不会触发failover,不会触发选举,而是一直等待master恢复,当master恢复,一切又工作正常。只有当投票数大于等于1时,才认为master才会触发选举,自动从众多的slave中选择一个节点升级为master,其他自动从节点自动连接次节点。同时会自动修改sentinel.conf文件
sentinel monitor mymaster 192.168.163.30 6380 1
默认30秒进行切换
修改从节点的选举优先级
redis.conf
slave-priority 100
这样当Master挂掉的时候Sentinel会优先选择slave-priority值较小的作为新的Master。
sentinel.conf配置详解
配置语句 |
说明 |
daemonize yes |
以后台进程模式运行 |
port 26379 |
哨兵的端口号,该端口号默认为26379,不得与任何redis node的端口号重复 |
logfile " /var/log/redis/sentinel.log " |
log文件所在地 |
sentinel monitor master1 192.168.163.30 6379 1 |
(第一次配置时)哨兵对哪个master进行监测,此处的master1为一“别名”可以任意,将来程序访问时使用,如sentinel-26379。然后哨兵会通过这个别名后的IP知道整个该master内的slave关系。因此你不用在此配置slave是什么而由哨兵自己去维护这个“链表”。 |
sentinel monitor master1 192.168.163.30 6379 1 |
最后一个1代表当节点宕机时的触发选举的判断条件,1就代表sentinel认定宕机的个数,必须大于这个个数,选举才开始发生,默认值为2,很坑。 |
sentinel down-after-milliseconds master1 1000 |
如果master在多少秒内无反应哨兵会开始进行master-slave间的切换,使用“选举”机制 |
sentinel failover-timeout master1 5000 |
如果在多少秒内没有把宕掉的那台master恢复,那哨兵认为这是一次真正的宕机,而排除该宕掉的master作为节点选取时可用的node然后等待一定的设定值的毫秒数后再来探测该节点是否恢复,如果恢复就把它作为一台slave加入哨兵监测节点群并在下一次切换时为他分配一个“选取号”。 |
安全访问
redis.conf
masterauth "123456"
requirepass "123456"
sentinel.conf
sentinel auth-pass mymaster 123456
否则在每个的redis-cli中执行语句:
CONFIG SET protected-mode no
jedis访问时
jedis.auth("123456");
jedis访问sentinel
@Test
public void sentinel(){
Set<String> sentinels = new HashSet<String>();
sentinels.add(new HostAndPort("192.168.163.30",26379).toString());
//sentinels.add(new HostAndPort("192.168.163.30",26380).toString());
//mymaster是在sentinel.conf中配置的名称
//sentinel monitor mymaster 192.168.163.30 6380 1
JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels);
System.out.println("当前master:" + pool.getCurrentHostMaster());
Jedis jedis = pool.getResource();
//jedis.auth("123456");
System.out.println(jedis.get("num"));
pool.returnResource(jedis);
pool.destroy();
System.out.println("ok");
}