当前位置: 首页 > news >正文

优惠券个人网站怎么做中华建设网算什么级别网站

优惠券个人网站怎么做,中华建设网算什么级别网站,简历模板简单免费,电商平台网站技术开发在多线程环境下#xff0c;为了保证数据的线程安全#xff0c;锁保证同一时刻#xff0c;只有一个可以访问和更新共享数据。在单机系统我们可以使用synchronized锁或者Lock锁保证线程安全。synchronized锁是Java提供的一种内置锁#xff0c;在单个JVM进程中提供线程之间的锁…在多线程环境下为了保证数据的线程安全锁保证同一时刻只有一个可以访问和更新共享数据。在单机系统我们可以使用synchronized锁或者Lock锁保证线程安全。synchronized锁是Java提供的一种内置锁在单个JVM进程中提供线程之间的锁定机制控制多线程并发。只适用于单机环境下的并发控制 但是如果想要锁定多个节点服务synchronized就不适用于了 想要在多个节点中提供锁定在分布式系统并发控制共享资源确保同一时刻只有一个访问可以调用避免多个调用者竞争调用和数据不一致问题保证数据的一致性。 分布式锁就是控制分布式系统不同进程访问共享资源的一种锁的机制。不同进程之间调用需要保持互斥性任意时刻只有一个客户端能持有锁。 从单体锁到分布式锁只不过是将锁的对象从一个进程的多个线程转成多个进程。 共享资源包含 数据库文件硬盘共享内存 实现思路 分布式锁的加锁和解锁是使用不同的数值来表示不同的状态比如0表示空闲状态。 加锁 加锁时判断锁是否空闲如果空闲修改状态为1表示已加锁返回成功。如果不为空闲状态0则返回失败表示没有获取到锁。 解锁 将锁状态修改为空闲状态0。 以上的加锁和解锁操作都要保证是一个原子操作。 分布式锁特性 1. 互斥性 分布式锁最基本的特性同一时刻只能一个节点服务拥有该锁当有节点获取锁之后其他节点无法获取锁不同节点之间具有互斥性。 2. 超时机制 不考虑异常正常情况下请求获取锁之后处理任务处理完成之后释放锁。但是如果在处理任务发生服务异常或者网络异常时导致锁无法释放。其他请求都无法获取锁变成死锁。 为了防止锁变成死锁需要设置锁的超时时间。过了超时时间后锁自动释放其他请求能正常获取锁。 3. 自动续期 锁设置了超时机制后如果持有锁的节点处理任务的时候过长超过了超时时间就会发生线程未处理完任务锁就被释放了其他线程就能获取到该锁导致多个节点同时访问共享资源。对此就需要延长超时时间。 开启一个监听线程定时监听任务监听任务线程还存活就延长超时时间。当任务完成、或者任务发生异常就不继续延长超时时间。 分布式实现 分布式主要有三种实现 数据库ZookeeperRedis 通过模拟客户下单操作。 先判断库存是否充足 如果充足先扣库存再新增订单。如果不足就提示库存不够。 先创建订单表和商品库存表: --库存表-- create table t_product(id bigint(20) not null auto_increment,name varchar(64) not null comment 商品名,store int default 0 comment 库存,primary key(id) )insert into t_product values (1, 红米手机, 100);-- 订单表 -- create table t_order(id bigint(20) not null auto_increment,sn varchar(64) not null comment 订单号,num int default null comment 数量,price int default null comment 单价,product_id bigint default null comment 商品id,create_time timestamp not null default CURRENT_TIMESTAMP comment 创建时间,primary key(id) )为了查询时防止幻读我们还需要保证查询和插入是在同一个事务中。下单先判断是否有库存有库存就减库存1再新增订单。主要代码如下 Transactional public void addOrder(Order order) throws Exception {Product product productDao.selectById(order.getProductId());int store product.getStore() - 1;if (store 0) {// 扣库存 product.setStore(store);productDao.updateByPrimaryKey(product);// 添加订单orderDao.insert(order);} else {throw new Exception(哎呦喂库存不足);} }其中查询库存方法productDao.selectById的SQL语句是: select id,name,store from t_product where id xxx使用压测工具apache ab开启多个线程请求50次 ab -n 10 -c 2 http://127.0.0.1:8080/xxxx压测结果: 库存剩余72订单数量50**新增了 50 条订单库存只扣了 28 **。 这是因为在并发环境下多个线程下单操作前面的线程还未更新库存后面的线程已经请求进来并获取到了未更新的库存后续扣减库存都不是扣减最近的库存。线程越多扣减的库存越少。这就是在高并发场景下发生的超卖问题。 1. 数据库实现分布式锁 Mysql数据库可以使用select xxx for update来实现分布式锁。 for update是一种行级锁也叫排它锁。如果一条select语句后面加上for update,其他事务可以读取但不能进进行更新操作。 将上面查询库存productDao.selectById方法的SQL语句后面加上for update: select id,name,store from t_product where id xxx for update再使用apache ab开启多个线程请求50次 ab -n 10 -c 2 http://127.0.0.1:8080/xxxx压测结果: 库存剩余50订单数量50数据库成功实现分布式锁 使用for update行级锁可以实现分布式锁通过行级锁锁住库存where后条件一定要走索引不然会触发表锁会降低MySQL的性能。 不过基于MySQL实现的分布式锁存在性能瓶颈在Repeatable read隔离级别下select for update操作是基于间隙锁锁实现这是一种悲观锁会存在线程阻塞问题。 当有大量的线程请求的情况下大部分请求会被阻塞等待后续的请求只能等前面的请求结束后才能排队进来处理。 Zookeeper 实现分布式锁 数据库实现分布式锁存在性能瓶颈无法支撑高并发的请求。可以使用Zookeeper实现分布式锁Zookeeper提供一种分布式服务协调的中心化服务而分布式锁的实现是基于Zookeeper的两个特性。 顺序临时节点: Zookeeper 数据模型znode是以多层节点命名的空间每个节点都用斜杠/分开的路径来表示类似文件系统的目录。 节点类型分成持久节点和临时节点每个节点还可以标记有序性。一旦节点被标记为有序性那整个节点就有自动递增的特点。利用以上的特性创建一个持久节点作为父节点在父节点下面创建一个临时节点并标记该临时节点为有序性。 Watch 机制: Zookeeper 还提供了另一个重要的特性Watch(事件监听器)在指定节点的上注册监听事件。当事件触发时会将事件通知给对应的客户。 了解了Zookeeper的两个特性之后那如何使用这两种特性来实现分布式锁呢 首先创建一个持久类型的父节点当用户请求时就在父节点创建临时类型的子节点并标记临时节点为有序性。 建立子节点之后对父节点下面所有临时节点进行排序判断刚创建的临时节点是否是最小的节点如果是最小的节点就获取锁。如果不最小的节点则等待锁并且获取该节点上一个顺序节点并为其注册监听事件等待触发事件并获得锁。 当请求完毕后删除该节点并触发监听事件下一个顺序节点获得锁流程如下所示 curator将上面实现分布式锁的思路封装好了直接调用即可。 引入curator依赖 dependencygroupIdorg.apache.curator/groupIdartifactIdcurator-recipes/artifactIdversion4.3.0/version /dependency使用InterProcessMutex分布式可重入排它锁,一般流程如下 InterProcessMutex lock new InterProcessMutex(client, lockPath); // 加锁 interProcessMutex.acquire(); // 执行代码xxxxxxx // 解锁 interProcessMutex.release();为了避免每次请求都要创建InterProcessMutex实例创建InterProcessMutex的bean: private String address xxxxx;Bean public InterProcessMutex interProcessMutex() {CuratorFramework zkClient getZkClient();String lockPath /lock;InterProcessMutex lock new InterProcessMutex(zkClient,lockPath);return lock; }private CuratorFramework getZkClient() {ExponentialBackoffRetry retry new ExponentialBackoffRetry(1000,3,5000);CuratorFramework zkClient CuratorFrameworkFactory.builder().connectString(address).sessionTimeoutMs(5000).connectionTimeoutMs(5000).retryPolicy(retry).build();zkClient.start();return zkClient; }在高并发场景下多个用户请求系统并获取临时节点顺序 使用interProcessMutex获取锁和释放锁: 获取锁 interProcessMutex.acquire()释放锁 interProcessMutex.release() 请求接口如下 RestController public class Controller {Autowiredprivate InterProcessMutex interProcessMutex;GetMapping(/sec-kill)public String secKill() throws Exception {// 获取锁interProcessMutex.acquire();// 扣减库存创建订单等操作....interProcessMutex.release();return ok;} }如果获取锁之后系统发生异常系统就一直持有锁后续请求也无法获取锁导致死锁。需要设置锁超时机制interProcessMutex.acquire添加超时时间 interProcessMutex.acquire(watiTime,TimeUnit);超时时间设置要根据业务执行时间来设定不能太长也不能太短。 Zookeeper一些特点 Zookeeper实现的分布式锁相对数据库性能有很大的提高。Zookeeper配置集群发生单点故障时、或者系统挂掉时临时节点会因为 session 连接断开而自动删除。频繁的创建和删除节点并且每个节点都有watch事件对Zookeeper服务来说压力大。相对Redis的性能还存在差距。 3. Redis 实现分布式锁 Redis 实现分布式锁是最复杂的但是也是性能最高的。 加锁 SETNX key value 如果键不存在时对键设值返回1。如果键存在不做任何操作,返回0。setnx全称是set if not exist。解锁 DEL key通过删除key释放锁删除键之后其他线程可以争夺锁。 Redis也需要考虑超时问题一般都是用SETNX EXPIRE组合来实现超时设置伪代码如下 pubic boolean lock(Jedis jedis,String key,String value,long expireTime) {long flag jedis.setnx(key,value);// 成功获取锁if(flag) {// 如果这里突然崩溃无法设置过期时间将发生死锁 jedis.expirt(key,expireTime);return true;}return false; } 通过setnx方法获取锁如果key存在就返回失败。如果不存在就设值成功设值成功之后再通过expirt设置超时时间。 如果在设置超时时间和设置锁之间出现系统崩溃此时没有给锁设置过期时间将会出现死锁问题。 在Redis 2.6.12版本后SETNX增加了过期时间参数 pubic boolean lock(Jedis jedis,String key,String value,long expireTime) {long flag jedis.setnx(key,value,expireTime);// 成功获取锁if(flag) {return true;}return false; } 解锁需要删除键值即可其他线程就能竞争锁了 pubic void lock(Jedis jedis,String key) {jedis.del(key); }一般请求controlle如下 RestController public class Controller {Autowiredprivate InterProcessMutex interProcessMutex;GetMapping(/sec-kill)public String secKill() throws Exception {// 获取锁lock();// 扣减库存创建订单等操作....unLock();return ok;} }Redis设置了超时时间后就解决死锁的问题但也会引发其他问题。 如果设置的超时时间比较短而业务执行的时间比较长。比如超时时间设置5s而业务执行需要10s此时业务还未执行完其他请求就会获取到锁两个请求同时请求业务数据不满足分布式锁的互斥性无法保证线程的安全如下流程所示 超时解锁导致并发 用户A先获取锁还未执行完业务代码此时已经过了超时时间锁被释放。用户B获取到锁此时用户A和用户B并发执行业务数据 锁误删除: 用户A执行完业务代码后执行释放锁操作而此时用户A已经被超时释放锁被用户B持有此时释放锁就把用户B的锁误删了。 解决方案 首先要将超时时间设置的长一些满足业务执行的时间。如果系统对吞吐量要求比较严格根据具体的业务的执行时间来设置超时时间超时时间比业务执行时间长一些超时时间不能设置太长也不能设置太短。 针对锁误删除的问题。每个线程在获取锁时设置一个的线程标识比如UUID作为唯一的标识设置value值在解锁时先判断是是否是自己线程的标识如果不是就不做删除 pubic void lock(Jedis jedis,String key,String value) { if (jedis.get(key).equals(value)) {jedis.del(key);} }除了设置合理超时时间外可能还有偶尔几个线程执行业务代码因为网络环境执行时间变长。这时候就需要再加一个线程定时执行自动续期锁。 4.Redission 分布式锁 Redis虽然作为分布式锁来说性能是最好的。但是也是最复杂的,上面总结Redis主要有下面几个问题 死锁设置超时后 锁误删业务还继续执行导致多个线程并发执行 线上都是用Redission实现分布式锁Redisson是一个在Redis的基础上实现的Java驻内存数据网格In-Memory Data Grid。它不仅提供了一系列的分布式的Java常用对象还提供了许多分布式服务。Redisson是基于netty通信框架实现的所以支持非阻塞通信性能优于Jedis。 Redisson分布式锁四层保护 防死锁防误删可重入自动续期 Redisson实现Redis分布式锁支持单机和集群模式 引入maven依赖 dependencygroupIdorg.redisson/groupIdartifactIdredisson/artifactIdversion3.8.2/version /dependency添加Redission配置 Configuration public class RedissonConfig {Beanpublic RedissonClient redissonClient() {Config config new Config();// 单机模式config.useSingleServer().setAddress(redis://127.0.0.1:6379).setPassword(xxxx);// 集群模式/*config.useClusterServers().setScanInterval(2000) // 集群状态扫描间隔时间单位是毫秒//可以用rediss://来启用SSL连接.addNodeAddress(redis://127.0.0.1:7000, redis://127.0.0.1:7001).addNodeAddress(redis://127.0.0.1:7002);*/ return Redisson.create(config);}}使用Redission分布式锁分成三个步骤 获取锁 redissonClient.getLock(lock)加锁 rLock.lock()解锁 rLock.unlock() 请求controlle示例如下 RestController public class Controller {Autowiredprivate RedissonClient redissonClient;GetMapping(/sec-kill)public String secKill() throws Exception {// 获取锁RLock rLock redissonClient.getLock(lock);// 加锁rLock.lock();// 执行业务数据// 解锁rLock.unlock();return ok;} }Redission实现的分布式锁直接调用不需要锁异常、超时并发、锁删除等问题它把处理上面的问题的代码都封装好了直接调用即可。 Redlock 算法 在单机模式下Redis发生单机故障Redis master宕机了该怎么办是否将锁转移到slave呢答案是不行的因为Redis复制是异步的无法满足锁互斥性。 Redlock算法可以解决上面的问题在集群模式下Redission 使用Redlock算法使用单机实例的方式顺序获取集群下的锁。如果请求超时则认定该节点不可用。当获取锁的实例数超过半数时则获取锁成功。如果获取锁失败即没有获取超过半数的实例那么久释放所有节点的锁。 Watch dog 看门狗机制 Redission通过看门狗的实现自动续期的功能当分布式锁获取到锁后对应的Redis宕机了会出现死锁的状态为避免出现这种状态锁一般会设置一个过期时间。默认是30s超过30s后会自动释放锁。 Redission实例被关闭之前不断的延长锁的有效期拿到线程的锁如果没有完成业务操作那么看门狗会一直延长锁的超时时间。默认情况下每10s延长一次超时时间续期时间是30s可以通过Config.lockWatchdogTimeout来设定。 Redisson还提供了可以指定leaseTime参数的加锁方法来指定加锁的时间。超过这个时间后锁便自动解开了不会延长锁的有效期。 总结 分布式锁是由于单机锁无法满足分布式系统锁在分布式环境下需要分布式锁来控制共享内容保证线程的安全。分布式满足几个特性 互斥性超时释放锁自动续期分布式锁实现方式 Mysql使用排它锁select xxxx for update。实现比较简单但是数据库无法支撑大量请求访问性能较差。Zookeeper先创建一个持久类型的节点当多个线程请求时在持久类型节点创建顺序临时节点先判断自己是否是最小节点如果是持有锁执行后续逻辑如果不是就找到上一个顺序节点并添加watch监听事件。线程处理结束后。触发监听事件通知下一个节点获取锁。Zookeeper性能优于数据库但是频繁的创建、删除节点并且创建watch监听对服务器的压力也大。使用Redis实现分布式锁性能是最优也是最复杂的。SETNX key value 获取锁如果key存在则成功获取锁否则获取锁失败。使用del删除节点释放锁。复杂在于需要平衡超时时间和锁续期。不设置超时时间会发生死锁。设置了超时时间就可能出现业务处理时间大于超时时间出现多个锁同时访问共享数据以及锁误删的情况。解决方案是根据具体的业务时间设置合理的超时时间锁误删的话要给每个线程设置一个唯一的id。此外如果业务时间大于超时时间开启线程定时续约时间。针对Redis实现分布式锁存在的问题Redisson提供了解决方案Redisson是一个在Redis的基础上实现的Java驻内存数据网格In-Memory Data Grid,Redisson是基于netty通信框架实现的所以支持非阻塞通信性能也比较高。Redisson有四种特性防死锁、防误删、可重入、自动续期。支持单机和集群模式。自动续期是使用watch dog看门狗机制在实例关闭前不断地延长锁的有效期。默认10s延迟一次延长时间为30s。
http://www.pierceye.com/news/769303/

相关文章:

  • 我们网站在那里登陆后台系统管理网站建设服务咨询
  • 免费上传图片的网址网站seo工作内容
  • chatgpt 网站一对一直播软件开发
  • 网站做排行多少费用个人电脑做网站打不开数据库
  • 做网站是比特币的滁州做网站电话号码
  • php网站开发说明怎么样建网站卖东西
  • 网站图片做多大浙江建设人才网
  • 网站关键词宝塔wordpress腾讯云
  • 优化排名推广教程网站免费房地产网站模板
  • 商城网站建设都需要多少钱电子商务网站建设预算
  • 万荣做网站怎么优化一个网站关键词
  • 潍坊市建设局网站网络工程师 网站建设
  • 做网站要求什么条件计算机网络技术学什么
  • 建设网站呼叫中心有什么好处中国能源建设集团有限公司级别
  • 免费论坛建站二 网站建设的重要性
  • wordpress站点迁移怎样做带音乐的表白网站
  • 海淀网站制作网站建设基本技术
  • 做一个平面网站的成本如何搭建一个app平台
  • 建设工程学部研究生培养网站义乌网站建设和制作
  • 简单的模板网站吉安网站建设jxthw
  • js做的网站佛山本地的网站设计公司
  • 企业网站页面网站建设朝阳
  • ui设计工具有哪些百度seo排名优化系统
  • 网站建设案例简介怎么写淘宝官方网站主页
  • 国外网站 dns南京模板做网站
  • 河北企业网站建设技术江西省外省建设入库网站
  • 网站建设的概念如何将自己做的网站放到网上去
  • 网站维护明细报价表最新的网站建设架构
  • 百度大全seo推广话术
  • 做网站赚钱流程英文网站建设注意什么