[如有侵权联系删除]
建议redis【3.2.11版本】
redis-cli默认登录127.0.0.1:6379【./redis-cli -p 6380(访问127.0.0.1的6380)】
如果想连接其它的redis【另外开启一个虚拟机,装redis,配置,即可连接】
jedis客户端测试代码
@Test
public void hashN(){
//模拟生成大量的数据,存储6379 6380 6381
//准备三个连接对象
Jedis jedis1=new Jedis("192.168.253.129",6379);
Jedis jedis2=new Jedis("192.168.253.129",6380);
Jedis jedis3=new Jedis("192.168.253.129",6381);
for (int i = 0; i < 100; i++) {
String key=UUID.randomUUID().toString();
String value="value_"+i;
int result=(key.hashCode()&Integer.MAX_VALUE)%3;
if(result==0){//6379
jedis1.set(key, value);
}else if(result==1){//6380
jedis2.set(key, value);
}else{//6381
jedis3.set(key, value);
}
}
@Test
public void shardedJedis(){
//使用jedis客户端实现大量数据存储在6379 6380 6381
//收集的所有节点
List<JedisShardInfo> list=new ArrayList<JedisShardInfo>();
list.add(new JedisShardInfo("192.168.253.129",6379));
list.add(new JedisShardInfo("192.168.253.129",6380));
list.add(new JedisShardInfo("192.168.253.129",6381));
//通过节点信息 创建分片对象
ShardedJedis sJedis=new ShardedJedis(list);
sJedis.set("name", "王老师");
System.out.println(sJedis.get("name"));
}
会导致雪崩
@Test
public void shardedJedis(){
//使用jedis客户端实现大量数据存储在6379 6380 6381
//收集的所有节点
List<JedisShardInfo> list=new ArrayList<JedisShardInfo>();
list.add(new JedisShardInfo("192.168.253.129", 6379, 1000, 1000, 5));//设置了6379节点的权重,6379:5 6380:1 6381:1
//list.add(new JedisShardInfo("192.168.253.129",6379));
list.add(new JedisShardInfo("192.168.253.129",6380));
list.add(new JedisShardInfo("192.168.253.129",6381));
//通过节点信息 创建分片对象
ShardedJedis sJedis=new ShardedJedis(list);
sJedis.set("name", "王老师");
System.out.println(sJedis.get("name"));
//通过存储1000个数据看数据存在了哪个端口里边,6379里多的多
for (int i = 0; i < 1000; i++) {
String key=UUID.randomUUID().toString();
sJedis.set("key", "");
}
}
4.分片连接池
【哈希 散列到对应端口的redis里边】
@Test
public void pool(){
//收集节点信息
List<JedisShardInfo> list=new ArrayList<JedisShardInfo>();
list.add(new JedisShardInfo("192.168.253.129",6379));
list.add(new JedisShardInfo("192.168.253.129",6380));
list.add(new JedisShardInfo("192.168.253.129",6381));
//使用连接池的配置对象,配置连接池的各种属性
//最大的空闲,最小空闲,最大连接数量
GenericObjectPoolConfig config=new GenericObjectPoolConfig();
config.setMaxIdle(8);
config.setMinIdle(3);
config.setMaxTotal(200);
//list config 构造了一个包装了多个分片连接对象的连接池对象
ShardedJedisPool pool=new ShardedJedisPool(config, list);
//从池中获取连接资源
ShardedJedis sJedis=pool.getResource();
sJedis.set("location", "北京");
}
5.2配置类
package cn.tedu.user.config;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix="redis.2021")//原先写的redis.1906
public class PoolConfigRedis {
private List<String> nodes;
//192.168.253.129:6379,192.168.253.129:6380,192.168.253.129:6381
private Integer maxTotal;
private Integer maxIdle;
private Integer minIdle;
public List<String> getNodes() {
return nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
public Integer getMaxTotal() {
return maxTotal;
}
public void setMaxTotal(Integer maxTotal) {
this.maxTotal = maxTotal;
}
public Integer getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(Integer maxIdle) {
this.maxIdle = maxIdle;
}
public Integer getMinIdle() {
return minIdle;
}
public void setMinIdle(Integer minIdle) {
this.minIdle = minIdle;
}
}
#redis config
redis.2021.nodes=192.168.253.129:6379,192.168.253.129:6380,192.168.253.129:6381
redis.1906.maxTotal=200
redis.1906.maxIdle=8
redis.1906.minIdle=3
5.3初始化对象(ShardedJedisPool)
package cn.tedu.user.config;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedisPool;
//配置类读取到配置文件里的属性和值
@Configuration
@ConfigurationProperties(prefix="redis.2021")//原先写的redis.1906
public class PoolConfigRedis {
private List<String> nodes;
//192.168.253.129:6379,192.168.253.129:6380,192.168.253.129:6381
private Integer maxTotal;
private Integer maxIdle;
private Integer minIdle;
//构造一个连接池初始化的方法
@Bean
public ShardedJedisPool initShardPool(){
//收集节点信息
List<JedisShardInfo> list=new ArrayList<JedisShardInfo>();
for (String node : nodes) {
//node="192.168.253.129:6973"
String host=node.split(":")[0];
int port=Integer.parseInt(node.split(":")[1]);
list.add(new JedisShardInfo(host, port));
}
//配置对象
GenericObjectPoolConfig config=new GenericObjectPoolConfig();
config.setMaxIdle(maxIdle);
config.setMaxTotal(maxTotal);
config.setMinIdle(minIdle);
return new ShardedJedisPool(config, list);
}
public List<String> getNodes() {
return nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
public Integer getMaxTotal() {
return maxTotal;
}
public void setMaxTotal(Integer maxTotal) {
this.maxTotal = maxTotal;
}
public Integer getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(Integer maxIdle) {
this.maxIdle = maxIdle;
}
public Integer getMinIdle() {
return minIdle;
}
public void setMinIdle(Integer minIdle) {
this.minIdle = minIdle;
}
}
5.4user的登录功能版本二
@Autowired
private ShardedJedisPool pool;
public String doLogin(User user) {
//判断登录的权限检验select where user_name and password
//加密
user.setUserPassword(MD5Util.md5(user.getUserPassword()));
User exist=userMapper.selectUserByUserNameAndPassword(user);
String ticket="";
//判断对象是否存在
if(exist==null){
//登录失败
return ticket;
}else{
//登录成功
//生成ticket redis 的key,生成value userJson
//ticket生成公式:“EM_TICKET”+currentTime+userId
ticket="EM_TICKET"+System.currentTimeMillis()+exist.getUserId();
//Jedis jedis=new Jedis("192.168.253.129", 6379);
ShardedJedis jedis = pool.getResource();
try {
//获取user的json值
String userJson=MapperUtil.MP.writeValueAsString(exist);
//设置超时存储
//jedis.setex(ticket, 60*60*2, userJson);
} catch (Exception e) {
e.printStackTrace();
return "";
}finally{
//jedis.close();
pool.returnResource(jedis);
}
//存储在redis,将ticket返回
return ticket;
}
}
public String queryTicket(String ticket) {
//Jedis jedis=new Jedis("192.168.253.129", 6379);
ShardedJedis jedis = pool.getResource();
try {
******
} catch (Exception e) {
e.printStackTrace();
return null;
}finally{
//jedis.close();
pool.returnResource(jedis);
}
}
高可用集群
1.三个节点分布式集群的问题
单节点故障,导致的集群不可用的问题
当前的分布式结构,单节点结构不是高可用(high avavlibility)
2.哨兵集群
[root@localhost02 bin]# cp redis.conf redis6382.conf
[root@localhost02 bin]# cp redis.conf redis6383.conf
[root@localhost02 bin]# cp redis.conf redis6384.conf
[root@localhost02 bin]# ls
6379redis.log dump6381.rdb redis6381.conf redis-check-aof redis-sentinel
6380redis.log dump.rdb redis6382.conf redis-check-dump redis-server
6381redis.log redis2.conf redis6383.conf redis-cli set
dump6379.rdb redis6379.conf redis6384.conf redis.conf
dump6380.rdb redis6380.conf redis-benchmark redis.log
[root@localhost02 bin]# ./redis-server redis6382.conf
[root@localhost02 bin]# ./redis-server redis6383.conf
[root@localhost02 bin]# ./redis-server redis6384.conf
//查看是否启动成功
[root@localhost02 bin]# ps -ef|grep redis
root 1474 1 0 13:28 ? 00:00:04 ./redis-server *:6379
root 1479 1 0 13:28 ? 00:00:05 ./redis-server *:6380
root 1483 1 0 13:28 ? 00:00:04 ./redis-server *:6381
root 1896 1451 0 14:35 pts/1 00:00:00 ./redis-cli -p 6381
root 2044 1 0 15:31 ? 00:00:00 ./redis-server *:6382
root 2048 1 0 15:31 ? 00:00:00 ./redis-server *:6383
root 2052 1 0 15:31 ? 00:00:00 ./redis-server *:6384
root 2057 1427 0 15:32 pts/0 00:00:00 grep redis
//查看是否启动成功
[root@localhost02 bin]# ps -ef|grep redis
[root@localhost02 bin]# ./redis-cli -p 6382
127.0.0.1:6382> info replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
查看主从:
设置挂接到6382节点:
127.0.0.1:6383> slaveof 192.168.253.129 6382
OK
127.0.0.1:6383> info replication
# Replication
role:slave
master_host:192.168.253.129
master_port:6382
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:1
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
关闭6382的redis
127.0.0.1:6382> shutdown
not connected> quit
redis3.0.7没有保护模式【这里没有配置】
[root@localhost02 redis-3.0.7]# vim sentinel.conf
默认:
Linux,编辑状态撤销操作,需要从编辑状态用键盘上的Esc键切换到“一般模式”
在一般模式中,按下一次字母U键就可以撤销一次上次的输入。
提示:编辑模式是无法执行命令的。
3.2启动3个哨兵进程
前提:主从结构正常运行
拷贝模板文件三份
修改各自的端口26380 26381
[root@localhost02 redis-3.0.7]# cp sentinel.conf sentinel01.conf
[root@localhost02 redis-3.0.7]# cp sentinel.conf sentinel02.conf
[root@localhost02 redis-3.0.7]# cp sentinel.conf sentinel03.conf
sentinel02.conf
sentinel03.conf
启动哨兵进程观察日志
注意:
redis-sentinel sentinel01.conf【3.2.11】redis-3.2.11目录下执行
./redis-sentinel /usr/local/redis/redis-3.0.7/sentinel01.conf或者./redis-sentinel …/redis-3.0.7/sentinel01.conf【3.0.7版本】bin目录下执行
[root@localhost02 bin]# ./redis-sentinel ../redis-3.0.7/sentinel02.conf
[root@localhost02 bin]# ./redis-sentinel /usr/local/redis/redis-3.0.7/sentinel01.conf
日志:
redis3.0.7版本的日志
2547:X 27 Apr 17:34:50.586 * Increased maximum number of open files to 10032 (it was originally set to 1024).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.0.7 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 26380
| `-._ `._ / _.-' | PID: 2547
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
2547:X 27 Apr 17:34:50.629 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
2547:X 27 Apr 17:34:50.629 # Sentinel runid is a2eaf4abc20c3f6d0fef8d0f11adb8540e4f0667
2547:X 27 Apr 17:34:50.629 # +monitor master mymaster 192.168.253.129 6382 quorum 2
2547:X 27 Apr 17:34:51.655 * +slave slave 192.168.253.129:6383 192.168.253.129 6383 @ mymaster 192.168.253.129 6382
2547:X 27 Apr 17:34:51.665 * +slave slave 192.168.253.129:6384 192.168.253.129 6384 @ mymaster 192.168.253.129 6382
2547:X 27 Apr 17:34:52.365 * +sentinel sentinel 192.168.253.129:26379 192.168.253.129 26379 @ mymaster 192.168.253.129 6382
主节点宕掉,从节点顶替【因为有哨兵,如果没有哨兵,从节点啥也不做;主节点回来后挂载到从节点上完成主从功能】
//逻辑时钟值
2539:X 27 Apr 20:57:46.724 # +new-epoch 1
3.4jedis可以连接哨兵访问主从集群
在这个主从结构下,6383为主,6382为从,所以现役节点为6383,如果6383宕机,短时间为6383【检测中】,过一会报错,再过一会现役节点为6382
@Test
public void sentinel(){
//收集哨兵信息,连接哨兵获取集群master-slave的使用信息
//给一个哨兵,指定多个,选一个可连接的节点使用
Set<String> sentinels=new HashSet<String>();
sentinels.add(new HostAndPort("192.168.253.129", 26379).toString());
sentinels.add(new HostAndPort("192.168.253.129", 26380).toString());
//哨兵连接池
JedisSentinelPool pool=new JedisSentinelPool("mymaster", sentinels);
System.out.println("当前现役master:"+pool.getCurrentHostMaster());
Jedis jedis=pool.getResource();
jedis.set("name", "刘老师");
System.out.println(jedis.get("name"));
pool.returnResource(jedis);
pool.destroy();
System.out.println("ok");
}
高可用和分布式【redis-cluster】