集群和分布式的区别
单机结构
当系统业务量很小的时候,我们可以将所有的代码放在一个项目,之后将这个项目部署在一台服务器上就好。整个项目的所有服务都又这台服务器提供,这就是单机结构。
集群
当单机结构到达性能瓶颈时,我们将"单机"复制几分,这样就构成了一个集群。集群中每台服务器就叫做这个集群中的一个"节点",所有节点构成了一个集群,每个节点都提供相同的服务。那么这样系统的处理能力就相当于提升了好多倍(有几个节点就相当于提升了这么多倍)
集群中涉及到用户的请求转发问题,当客户端对服务器进行请求时,应该选择集群下哪个节点处理较合适?理论上选择此刻负载较小的节点来处理,这样使得每个节点的压力都比较平均。我们在所有节点前增加一个"调度者"的角色,用户的所有请求都先交给它,然后它根据当前集群中节点的负载情况,决定将请求派发给谁。这个"调度者"便是负载均衡处理器,通常由Nginx实现。
分布式
从单机结构到集群结构,代码基本不需要改动,只需要多部署几台服务器即可,每台服务器上运行相同的代码。但是当集群结构演进至分布式结构,代码就需要发生较大的改动,升级成微服务架构。
==分布式结构就是将一个完整的系统,按照业务功能,拆分成独立的子系统。在分布式结构中,每个子系统被称为"服务"==这些子系统能够独立运行在Web容器中,它们之间通过RPC方式通信。
举个例子,假设需要开发一个在线商城。按照微服务的思想,我们需要按照功能模块拆分成多个独立的服务,如:用户服务、产品服务、订单服务、后台管理服务、数据分析服务等等。这一个个服务都是一个个独立的项目,可以独立运行。如果服务之间有依赖关系,那么通过RPC方式调用。
优点:
- 系统之间的耦合度大大降低,可以独立开发、独立部署、独立测试,系统与系统之间的边界非常明确,排错也变得相当容易,开发效率大大提升
- 系统之间的耦合度降低,从而系统更易于扩展。我们可以针对性地扩展某些服务。假设这个商城要搞一次大促,下单量可能会大大提升,因此我们可以针对性地提升订单系统、产品系统的节点数量,而对于后台管理系统、数据分析系统而言,节点数量维持原有水平即可
- 服务的复用性更高。比如,当我们将用户系统作为单独的服务后,该公司所有的产品都可以使用该系统作为用户系统,无需重复开发
Redis分布式算法原理
Redis分布式环境配置
修改两个Redis的配置文件redis.conf,将其中一个端口修改为6380。
启动Redis服务端
通过配置文件启动redis-server
。/redis.sercer ../redis.conf
启动Redis客户端
启动客户端需要指定端口
./redis.cli -p 6379|6380
Jedis下分布式Redis
public class RedisShardedPool {
private static ShardedJedisPool pool;//sharded jedis连接池
private static Integer maxTotal = Integer.parseInt(PropertiesUtil.getProperty("redis.max.total","20")); //最大连接数
private static Integer maxIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.max.idle","20"));//在jedispool中最大的idle状态(空闲的)的jedis实例的个数
private static Integer minIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.min.idle","20"));//在jedispool中最小的idle状态(空闲的)的jedis实例的个数
private static Boolean testOnBorrow = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.borrow","true"));//在borrow一个jedis实例的时候,是否要进行验证操作,如果赋值true。则得到的jedis实例肯定是可以用的。
private static Boolean testOnReturn = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.return","true"));//在return一个jedis实例的时候,是否要进行验证操作,如果赋值true。则放回jedispool的jedis实例肯定是可以用的。
// private static String redisIp = PropertiesUtil.getProperty("redis.ip");
// private static Integer redisPort = Integer.parseInt(PropertiesUtil.getProperty("redis.port"));
private static String redis2Ip = PropertiesUtil.getProperty("redis2.ip");
private static Integer redis2Port = Integer.parseInt(PropertiesUtil.getProperty("redis2.port"));
private static String redis1Ip = PropertiesUtil.getProperty("redis1.ip");
private static Integer redis1Port = Integer.parseInt(PropertiesUtil.getProperty("redis1.port"));
private static void initPool(){
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);
config.setTestOnBorrow(testOnBorrow);
config.setTestOnReturn(testOnReturn);
config.setBlockWhenExhausted(true);//连接耗尽的时候,是否阻塞,false会抛出异常,true阻塞直到超时。默认为true。
// JedisShardInfo info = new JedisShardInfo(redisIp,redisPort,1000*2);
JedisShardInfo info2 = new JedisShardInfo(redis2Ip,redis2Port,1000*2);
JedisShardInfo info1 = new JedisShardInfo(redis1Ip,redis1Port,1000*2);
List<JedisShardInfo> jedisShardInfoList = new ArrayList<JedisShardInfo>(2);
// jedisShardInfoList.add(info);
jedisShardInfoList.add(info2);
jedisShardInfoList.add(info1);
pool = new ShardedJedisPool(config,jedisShardInfoList, Hashing.MURMUR_HASH, Sharded.DEFAULT_KEY_TAG_PATTERN);
}
static{
initPool();
}
public static ShardedJedis getJedis(){
return pool.getResource();
}
public static void returnBrokenResource(ShardedJedis jedis){
pool.returnBrokenResource(jedis);
}
public static void returnResource(ShardedJedis jedis){
pool.returnResource(jedis);
}
public static void main(String[] args) {
ShardedJedis jedis = pool.getResource();
//添加key,Redis根据一致性哈希算法存入对应的Cache
//获取Key时,Redis通过同样的哈希算法得出对应的Key先前存在哪个Cache,去那个Cache下找key
for(int i =0;i<10;i++){
jedis.set("key"+i,"value"+i);
}
returnResource(jedis);
// pool.destroy();//临时调用,销毁连接池中的所有连接
System.out.println("program is end");
}
}
@Slf4j
public class RedisShardedPoolUtil {
/**
* 设置key的有效期,单位是秒
* @param key
* @param exTime
* @return
*/
public static Long expire(String key,int exTime){
ShardedJedis jedis = null;
Long result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.expire(key,exTime);
} catch (Exception e) {
log.error("expire key:{} error",key,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
//exTime的单位是秒
public static String setEx(String key,String value,int exTime){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.setex(key,exTime,value);
} catch (Exception e) {
log.error("setex key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static String set(String key,String value){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.set(key,value);
} catch (Exception e) {
log.error("set key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static String getSet(String key,String value){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.getSet(key,value);
} catch (Exception e) {
log.error("getset key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static String get(String key){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.get(key);
} catch (Exception e) {
log.error("get key:{} error",key,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static Long del(String key){
ShardedJedis jedis = null;
Long result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.del(key);
} catch (Exception e) {
log.error("del key:{} error",key,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static Long setnx(String key,String value){
ShardedJedis jedis = null;
Long result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.setnx(key,value);
} catch (Exception e) {
log.error("setnx key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
}