分布式问题

redis setnx lua脚本(抢购限流)|Redis 服务器会单线程原子性执行 lua 脚本,保证 lua 脚本在处理的过程中不会被任意其它请求打断  用户商品id数据作为key
乐观锁 version   sql set a= x where x=a+1
zk wather

先更新数据库,再删除缓存 可能删除失败就导致缓存旧值
单删可能中间来了新查询,旧数据

延时双删  sleep一段时间,已更新到数据库了 要估计好读数据+写缓存的时间

redis 时单线程 多路复用
watch指令类似于乐观锁,在事务提交时,如果watch监控的多个KEY中任何KEY的值已经被其他客户端更改
watch key1 key2 ... : 监视一或多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断 ( 类似乐观锁 )
multi : 标记一个事务块的开始( queued )
set a b
exec : 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 )   
    !!!类似于java编译性错误执行EXEC命令时,所有命令都不会执行   类似于java的1/0的运行时异常,则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常
discard : 取消事务,放弃事务块中的所有命令
unwatch : 取消watch对所有key的监控

zookeeper=文件系统+监听通知机制
 znode(目录节点) PERSISTENT-持久化目录节点 EPHEMERAL-临时目录节点  可存储数据
 监听通知机制 当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端
 
 实现Watcher 实现process方法
 
 
 
https://www.cnblogs.com/mengchunchen/p/9647756.html  分布式锁

redis分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能  可以支撑高并发的获取、释放锁操作。!!
zk分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小
另外一点就是,如果是redis获取锁的那个客户端bug了或者挂了,那么只能等待超时时间之后才能释放锁;而zk的话,因为创建的是临时znode,只要客户端挂了,znode就没了,此时就自动释放锁!!

zk分布式锁,就是某个节点尝试创建临时znode,此时创建成功了就获取了这个锁;这个时候别的客户端来创建锁会失败,只能注册个监听器监听这个锁。
释放锁就是删除这个znode,一旦释放掉就会通知客户端,然后有一个等待着的客户端就可以再次重新加锁。

分布式事务seata 分库分表/读写分离(强制走主库) 集群docker k8s netty 
设计模式 公共组件  泛型方法 入参检验 异常抛出!!!

rpc更快,基于tcp,udp,保持对象状态   http上层协议!!
多表调用join   三表以上造成笛卡尔积过大,性能差不走全表的话

jwt  第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
RS256 (采用SHA-256 的 RSA 签名) 是一种非对称算法
HS256 (带有 SHA-256 的 HMAC 是一种对称算法, 双方之间仅共享一个 密钥
保护安全,防止被盗用 使用https  或者ip和token绑定!!!
jwt不过期,可以加如黑名单等待过期后删除


登录流程 sso->role->权限验证、模块权限、jedis分布式锁
ZuulFilter 接口权限放行/验证登录/服务转发到相应服务
WebMvcConfigurer 替代xml配置  接口权限放行和拦截器注册并验证逻辑(登录/权限)
Filter函数回调   interceptor则是基于Java反射的(AOP思想)
Filter Servlet 容器支持  interceptor Spring容器
Filter先执行  interceptor后执行


注册多个服务实例 
idea 点击Edit Configurations  其次勾选允许启动,新版本的是勾选Allow parallel run   xshell服务器启动一个注册到本地

负载均衡  ribbon+RestTemplate 多个地方地用多个地方配置(但是可以调用集群外的服务 指定ip)    FeignClient 动态代理注册到ioc 封装http请求 调用方法invoke
客户端从Eureka中拿到对应的服务列表,默认进行轮询RoundRobinRule  随机

https://www.cnblogs.com/jing99/p/11696192.html
zuul网关(统一入口,安全),进行路径的路由,定位到具体的服务节点上 
底层使用ribbon来实现请求的路由,并内置Hystrix      zuul.routes  service-ids:  /service-ids/**  
ZuulFilter filterType前置|后置  run做权限验证!!!是否登录和接口权限

分布式锁  redis zk
登录需要限定次数 多个服务的多个syn 同步锁也就失效了。

redis分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能
zk分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小

如果是redis获取锁的那个客户端bug了或者挂了,那么只能等待超时时间之后才能释放锁;
而zk的话,因为创建的是临时znode,只要客户端挂了,znode就没了,此时就自动释放锁

Jedis jedis = new Jedis("192.168.31.251",6379);
jedis.auth("nssa_redis_1qazZAQ!");
String result = "NO";
try{
    while (true) {
        //获取分布式锁成功退出循环  但是不能无限等待  可以用次数或者时间限制
        result = jedis.set("testkey", "testvalue", "NX", "PX", 100000);
        if ("OK".equals(result)) {
            //操作公共的参数  业务
            break;
        }
    }
}finally {
    //业务结果等操作
    if("OK".equals(result)){
        //释放锁 应判断是否获取到锁 成功返回1
        Long RELEASE_SUCCESS = 1L;
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object resultTest = jedis.eval(script, Collections.singletonList("testkey"), Collections.singletonList("testvalue"));
    }
}

登录成功 需要清0
if ("OK".equals(result)) {
    //操作公共的参数  业务
    String numkey ="login-userLoginNum"+user.getUsername();
    jedis.set(numkey,"0");
    break;
}


Jedis jedis = new Jedis("192.168.31.251",6379);
jedis.auth("nssa_redis_1qazZAQ!");
while (true){
    //获取分布式锁成功退出循环  但是不能无限等待
    String result = jedis.set("testkey", "testvalue", "NX", "PX", 100000);
    if ("OK".equals(result)) {
        //操作公共的参数  业务
        String numkey ="login-userLoginNum"+user.getUsername();
        String num = jedis.get(numkey);
        if(num == null || num.equals("0")){
            jedis.set(numkey,"1");
        }else{
            int nowNum = Integer.parseInt(num)+1;
            jedis.set(numkey,String.valueOf(nowNum));

            if(nowNum > 5){
                System.out.println("账号或者密码错误,登录5次失败,用户锁定5分钟");

                resultObject.setMsg("账号或者密码错误,登录5次失败,用户锁定5分钟");
                redisUtil.set("login-"+user.getUsername(),nowNum,5*60);   需要锁住  和记录次数key不一样
            }
        }
        break;
    }
}finally 释放锁

集群连接 
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(100);
config.setMaxIdle(50);
config.setMaxWaitMillis(3000);
config.setTestOnBorrow(true);
config.setTestOnReturn(true);
//集群池子
JedisShardInfo jedisShardInfo1 = new JedisShardInfo("120.26.1.1", 6379);
jedisShardInfo1.setPassword("123456888888");
List<JedisShardInfo> list = new LinkedList<JedisShardInfo>();
list.add(jedisShardInfo1);   
ShardedJedisPool pool = new ShardedJedisPool(config, list);
//获取连接
ShardedJedis jedis = pool.getResource();


jedis.del()直接删除锁可能出现误删除 

分布式锁解决  一个集群中多台机器操作一个变量  成员变量 A 存在 JVM1、JVM2、JVM3 三个 JVM 内存中!!!
分布式锁具备的条件:高可用高性能获取锁与释放锁/锁失效机制,防止死锁/非阻塞锁特性,即没有获取到锁将直接返回获取锁失败
Memcached:add
jedis:Redis:setnx,原子性操作,只有在 key 不存在的情况下,才能 set 成功  但是容易产生死锁,并且 setnx和expire(设置超时时间)不是原子操作,redis宕机,就无法释放锁
2.6.12版本:set(String key, String value, String nxxx, String expx, long time); ex/px 秒/毫秒   NX/XX 键不存在/键存在在操作
Zookeeper:顺序临时节点 
Chubby:Google 公司实现的粗粒度分布式锁服务,底层利用了 Paxos 一致性算法
数据库:乐观锁(通过版本号)或者悲观锁(通过for update)
redission:为了不断提高的吞吐量,异步非阻塞线程模型大行其道    RLock lock = redisson.getLock("myLock") lock.lock();


分布式事务:操作位于不同的节点上,需要保证事务的 AICD 特性。
两阶段提交(2PC) Oracle 非常明显的性能问题
补偿事务(TCC)
MQ 事务消息
LCN  seata

https://blog.csdn.net/burpee/article/details/52812837

zookeeper=文件系统!!!!+监听通知机制,分布式应用配置管理、统一命名服务、状态同步服务、集群管理等功能

znode(目录节点): 可以存储数据  peristent ephemeral  持久化和临时,客户端与zookeeper断开连接后,该节点被删除  seqential节点顺序,自动增加
将数据保存在内存中,这也就保证了 高吞吐量和低延迟!!!大小限制为1M

Session:一个客户端连接是指客户端和服务器之间的一个 TCP 长连接。无论是哪台服务器为客户端分配的 sessionID,都务必保证全局唯一
只要在 sessionTimeout 规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。

一个Watch事件是一个一次性的触发器!!!!!
监听通知机制:当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。
在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候
if (KeeperState.SyncConnected == event.getState()) {  //zk连接成功通知事件
    if (EventType.None == event.getType() && null == event.getPath()) {
        connectedSemaphore.countDown();
    } else if (event.getType() == EventType.NodeDataChanged) {  //zk目录节点数据变化通知事件
        try {
            System.out.println("配置已修改,新值为:" + new String(zk.getData(event.getPath(), true, stat)));
        } catch (Exception e) {
        }
    }
}

ACL:权限,create read write delete admin create/delete针对字节点

zkServer.sh start conf/zoo-1.cfg 集群     zkCli.sh 启动服务端和客户端
ls create set get delete
tickTime: 服务器之间或客户端与服务器之间维持心跳的时间间隔  initLimit  syncLimit  
myid中添加服务号(id唯一标识) zxid事务的操作顺序    dataDir 数据路径    
sercer.a=b:c:d a是几号服务器,那个配置文件 b服务器ip c交换端口 d服务器挂了,从哪个端口重新选举  2888:3888

选举初leader 3.4.0只有fast算法
leader提供读服务,Follower 和 Observer(观察状态) 唯一的区别在于 Observer 机器不参与 Leader 的选举过程   LOOKING:竞选状态
半数机制:ZooKeeper集群中,半数以上节点存活,集群可用,所以ZooKeeper适合安装奇数服务器
FastLeaderElection(最新默认)  启动给自己投票,5台一般是第三台是leader

监听过程 main->connnet->watcher注册->事件变化->线程的process方法处理事件变化!!!!
写过程:向server1发送请求,不是就找到真正的leader,然后广播给其他server,超过半数写成功就说明写成功了!!!,然后通知server1写成功了

崩溃恢复和消息广播
ZAB(ZooKeeper Atomic Broadcast 原子广播)协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。
为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid
ZooKeeper每个对节点的改变都将产生一个唯一的Zxid,并且这个时间戳全局有序。。如果Zxid1的值小于Zxid2的值,那么Zxid1所对应的事件发生在Zxid2所对应的事件之前!!!
Zxid实现中Zxid是一个64为的数字,它高32位是epoch用来标识Leader关系是否改变,每次一个Leader被选出来,它都会有一个新的epoch。低32位是个递增计数。

public class ParkInfoEntity implements Serializable  序列化和反序列化
public static void main(String[] args) throws IOException, ClassNotFoundException {
    byte[] bytes = output();
    input(bytes);
}
public static byte[] output() throws IOException {
    ParkInfoEntity parkInfoEntity = new ParkInfoEntity();
    parkInfoEntity.setAreaName("中国");

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(outputStream);
    oos.writeObject(parkInfoEntity);
    oos.flush();
    return outputStream.toByteArray();
}

public static void input(byte[] bytes) throws IOException, ClassNotFoundException {
    ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
    ObjectInputStream ois = new ObjectInputStream(inputStream);
    ParkInfoEntity parkInfoEntity = (ParkInfoEntity) ois.readObject();
    System.out.println(parkInfoEntity.getAreaName());
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值