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

网站建设公司的成本有哪些内容在网站中设置网站地图

网站建设公司的成本有哪些内容,在网站中设置网站地图,河南建设厅八大员查询网站,义乌十大进出口贸易公司全局ID生成器 每个店铺都可以发布优惠卷 当用户抢购时#xff0c;就会生成订单并保存到tb_voucher_order这张表中#xff0c;而订单表如果使用数据库自增id就存在一些问题#xff1a; 1.id的规律性太明显 2.受单表数据量的限制 全局ID生成器#xff0c;是一种在分布式系…全局ID生成器 每个店铺都可以发布优惠卷 当用户抢购时就会生成订单并保存到tb_voucher_order这张表中而订单表如果使用数据库自增id就存在一些问题 1.id的规律性太明显 2.受单表数据量的限制 全局ID生成器是一种在分布式系统下用来生成全局唯一ID的工具一般要满足下列特性 为了增加ID的安全性我们可以不直接使用Redis自增的数值而是拼接一些其他信息 ID的组成部分 1.符号位1bit,永远为0 2.时间戳31bit,以秒为单位可以使用69年 3.序列号32bit,秒内的计数器支持每秒产生2⋀32个不同的ID RedisIdWorker Component public class RedisIdWorker {/*** 开始时间戳*/private static final long Begin_TIMESTAMP 1640995200L;/*** 序列号的位数*/private static final int COUNT_BITS 32;private StringRedisTemplate stringRedisTemplate;public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate stringRedisTemplate;}public long nextId(String keyPrefix) {//1.生成时间戳LocalDateTime now LocalDateTime.now();long nowSecond now.toEpochSecond(ZoneOffset.UTC);long timestamp nowSecond - Begin_TIMESTAMP;//2.生成序列号//2.1获取当前日期。精确到天String date now.format(DateTimeFormatter.ofPattern(yyyy:MM:dd));//2.2自增长long count stringRedisTemplate.opsForValue().increment(icr: keyPrefix : date);//3.拼接并返回return timestamp COUNT_BITS | count;} } private ExecutorService es Executors.newFixedThreadPool(500);Resourceprivate RedisIdWorker redisIdWorker;Testvoid testIdWorker() throws InterruptedException {CountDownLatch latch new CountDownLatch(300);Runnable task () - {for (int i 0; i 100; i) {long id redisIdWorker.nextId(order);System.out.println(id id);}latch.countDown();};long begin System.currentTimeMillis();for (int i 0; i 300; i) {es.submit(task);}latch.await();long end System.currentTimeMillis();System.out.println(time (end - begin));}全局唯一ID生成策略 1.UUID 2.Redis自增 3.snowflake算法 4.数据库自增 Redis自增ID策略 1.每天一个key,方便统计订单量 2.ID构造是时间戳计数器 实现优惠券秒杀下单 每个店铺都可以发布优惠券分为平价劵。平价券可以任意购买而特价券需要秒杀抢购 表关系如下 tb_voucher:优惠券的基本信息优惠金额使用规则等 tb_seckill_vouvher:优惠券的库存、开始抢购时间结束抢购时间。特价优惠券才需要填写这些信息 实现优惠券秒杀下单 在VoucherController实现了一个接口可以实现添加秒杀优惠券、 RestController RequestMapping(/voucher) public class VoucherController {Resourceprivate IVoucherService voucherService;/*** 新增普通券* param voucher 优惠券信息* return 优惠券id*/PostMappingpublic Result addVoucher(RequestBody Voucher voucher) {voucherService.save(voucher);return Result.ok(voucher.getId());}/*** 新增秒杀券* param voucher 优惠券信息包含秒杀信息* return 优惠券id*/PostMapping(seckill)public Result addSeckillVoucher(RequestBody Voucher voucher) {voucherService.addSeckillVoucher(voucher);return Result.ok(voucher.getId());} }用户可以在这些店铺页面中抢购这些优惠券 下单时需要判断两点 1.秒杀是否开始或结束如果尚未开始或已经结束则无法下单 2.库存是否充足不足则无法下单 超卖问题 超卖问题是典型的多线程安全问题针对这一问题的常见解决方案就是加锁 乐观锁 乐观锁的关键是判断之前查询得到的数据是否被修改过常见的方式有两种 超卖总结 超卖这样的线程安全问题解决方案有哪些 1.悲观锁添加同步锁让线程串行执行 优点简单粗暴 缺点性能一般 2.乐观锁不加锁在更新时判断是否有其他线程在修改 优点性能好 存在成功率低的问题 一人一单 需求修改秒杀业务要求同一个优惠券一个用户只能下一单 VoucherOrderServiceImpl Service public class VoucherOrderServiceImpl extends ServiceImplVoucherOrderMapper, VoucherOrder implements IVoucherOrderService {Resourceprivate ISeckillVoucherService seckillVoucherService;Resourceprivate RedisIdWorker redisIdWorker;Overridepublic Result seckillVoucher(Long voucherId) {//1.查询优惠券SeckillVoucher voucher seckillVoucherService.getById(voucherId);//2.判断秒杀是否开始if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {//尚未开始return Result.fail(秒杀尚未开始);}//3.判断秒杀是否结束if (voucher.getEndTime().isBefore(LocalDateTime.now())) {//秒杀已经结束return Result.fail(秒杀已经结束);}//4.判断库存是否充足if (voucher.getStock() 1) {//库存不足return Result.fail(库存不足);}Long userId UserHolder.getUser().getId();synchronized (userId.toString().intern()) {//获取代理对象IVoucherOrderService proxy (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);}}Transactionalpublic Result createVoucherOrder(Long voucherId) {//5.一人一单Long userId UserHolder.getUser().getId();//5.1查询订单Integer count query().eq(user_id, userId).eq(voucher_id, voucherId).count();//5.2判断是否存在if (count0) {//用户已经购买过了return Result.fail(用户已经购买过一次);}//6.扣减库存boolean success seckillVoucherService.update().setSql(stockstock-1).eq(voucher_id, voucherId).gt(stock,0).update();if (!success) {//扣减失败return Result.fail(库存不足);}//7.创建订单VoucherOrder voucherOrder new VoucherOrder();//7.1订单idlong orderId redisIdWorker.nextId(order);voucherOrder.setId(orderId);//7.2用户idLong userid UserHolder.getUser().getId();voucherOrder.setUserId(userid);//7.3代金券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);//7.返回订单idreturn Result.ok(orderId);} }一人一单的并发安全问题 通过加锁可以解决在单机情况下的一人一单安全问题但是在集群模式下就不行了 1.我们将服务启动两份端口分别是8081和8082 2.然后修改nginx的conf目录下的nginx.cong文件配置反向代理和负载均衡 现在用户节点会在这两个节点上负载均衡再次测试下是否存在线程安全问题 分布式锁 什么是分布式锁 分布式锁满足分布式系统或集群模式下多进程可见并且互斥的锁 分布式锁的实现 分布式锁的核心是实现多进程之间互斥而满足这一节点的方式有很多种常见的有三种 基于Redis的分布式锁 实现分布式锁需要实现的两个基本方法 1.获取锁 互斥确保只能有一个线程获取锁 非阻塞尝试一次成功返回true,失败返回false 2.释放锁 手动释放 基于Redis实现分布式锁的初级版本 ILock SimpleRedisLock public class SimpleRedisLock implements ILock {private String name;private StringRedisTemplate stringRedisTemplate;private static final String KEY_PREFIX lock:;public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name name;this.stringRedisTemplate stringRedisTemplate;}Overridepublic boolean tryLock(long timeoutSec) {long threadId Thread.currentThread().getId();//获取锁Boolean success stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX name, threadId , timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);}Overridepublic void unlock() {//释放锁stringRedisTemplate.delete(KEY_PREFIX name);} }基于Redis实现分布式锁的初级版本存在问题分析 1业务阻塞超时或业务未执行完释放其他线程的锁 2.释放锁之前判断是否是该线程的锁 改进Redis的分布式锁 需求修改之前的分布式锁实现满足 1.在获取锁时存入线程标识可以用UUID表示 2.在释放锁时先获取锁中的线程标识判断是否与当前线程标识一致 如果一致则释放锁 如果不一致不释放锁 SimpleRedisLock public class SimpleRedisLock implements ILock {private String name;private StringRedisTemplate stringRedisTemplate;public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name name;this.stringRedisTemplate stringRedisTemplate;}private static final String KEY_PREFIX lock:;private static final String ID_PREFIX UUID.randomUUID().toString(true) -;Overridepublic boolean tryLock(long timeoutSec) {//获取线程标识String threadId ID_PREFIX Thread.currentThread().getId();//获取锁Boolean success stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX name, threadId , timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);}Overridepublic void unlock() {//获取线程标识String threadId ID_PREFIX Thread.currentThread().getId();//获取锁中的标识String id stringRedisTemplate.opsForValue().get(KEY_PREFIX name);//判断标识是否一致if (threadId.equals(id)) {//释放锁stringRedisTemplate.delete(KEY_PREFIX name);}} }改进Redis的分布式锁后存在问题分析 锁判断和锁释放不是原子性 Redis的Lua脚本 Redist提供了Lua脚本功能在一个脚本中编写多条Redis命令确保多条命令执行时的原子性。Lua是一种编程语言它的基本语法大家可以参考网站 https://www.runoob.com/lua/lua-tutorial.html 这里重点介绍Redis提供的调用函数语法如下 例如我们要执行set name jack,则脚本是这样 例如我们要先执行set name Rose,再执行get name,则脚本如下 写好脚本以后需要用Redis命令来调用脚本调用脚本的常见命令如下 例如我们要执行redis.call(‘set’,‘name’,‘jack’)这个脚本语法如下 如果脚本中的key、value不想写死可以作为参数传递。key类型参数会放入KEYS数组其他参数会放入ARGV数组在脚本中可以从KEYS和ARGV数组获取这些参数 释放锁的业务流程是这样的 1.获取锁中的线程标示 2.判断是否与指定的标示当前线标示一致 3.如果一致则释放锁删除 4.如果不一致则什么都不做 利用Lua脚本来表示则是这样的 再次改进Redis的分布式锁 需求基于Lua脚本实现分布式锁的释放逻辑 提示RedisTemplate调用Lua脚本的API如下 unlock.lua -- 比较线程标示与锁中的标示是否一致 if (redis.call(get, KEYS[1]) ARGV[1]) then-- 释放锁 del keyreturn redis.call(del, KEYS[1]) end return 0SimpleRedisLock public class SimpleRedisLock implements ILock {private String name;private StringRedisTemplate stringRedisTemplate;public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name name;this.stringRedisTemplate stringRedisTemplate;}private static final String KEY_PREFIX lock:;private static final String ID_PREFIX UUID.randomUUID().toString(true) -;private static final DefaultRedisScriptLong UNLOCK_SCRIPT;static {UNLOCK_SCRIPT new DefaultRedisScript();UNLOCK_SCRIPT.setLocation(new ClassPathResource(unlock.lua));UNLOCK_SCRIPT.setResultType(Long.class);}Overridepublic boolean tryLock(long timeoutSec) {//获取线程标识String threadId ID_PREFIX Thread.currentThread().getId();//获取锁Boolean success stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX name, threadId , timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);}Overridepublic void unlock() {//调用lua脚本stringRedisTemplate.execute(UNLOCK_SCRIPT,Collections.singletonList(KEY_PREFIX name),ID_PREFIX Thread.currentThread().getId());} }基于Redis实现的分布式锁总结 1.基于Redis的分布式锁实现思路 利用set nx ex获取锁并设置过期时间保存线程标示 释放锁时先判断线程标示是否与自己一致一致则删除锁 2.特性 利用set nx满足互斥性 利用set ex保证故障时锁依然能释放避免死锁提高安全性 利用Redis集群保证高可用和高并发性 基于Redis的分布式锁优化 基于setnx实现的分布式锁存在下面问题 Redisson Redisson是一个在Redis的基础上实现java驻内存数据网格In-Memory Data Grid。它不仅提供了一系列的分布式java常用对象还提供了许多分布式服务其中就包含了各种分布式锁的实现 官网地址https://redisson.org GitHub地址https://github.com/redisson/redisson Redisson入门 1.引入依赖 2.配置Redisson客户端 3.使用Redisson的分布式锁 Redisson可重入锁原理 获取锁的Lua脚本 释放锁的Lua脚本 Redisson分布式锁原理 1.可重入利用hash结构记录线程id和重入次数 2.可重试利用信号量和PubSub和功能实现等待、唤醒、获取锁失败的重试机制 3.超时续约利用watchDog,每隔一段时间重置超时时间 Redisson分布式锁主从一致性问题 分布式锁总结 1.不可重入Redis分布式锁 原理利用setnx的互斥性利用ex避免死锁释放锁时判断线程标示 缺陷不可重入、无法重试锁超时失效 2.可重入的Redis分布式锁 原理利用hash结构记录线程和重入次数利用watchDog延续时间利用信号量控制锁重试等待 缺陷redis宕机引起锁失效问题 3.Redisson的multiLock 原理多个独立的Redis节点必须在所有节点都获取重入锁才算获取锁成功 缺陷运维成本高失效复杂 视频地址
http://www.hkea.cn/news/14569145/

相关文章:

  • 外贸仿牌网站建设做鞋子有什么好网站好
  • 珠海市外贸网站建设公司高级网站开发工程师考试题
  • 网站开发技术语言大千科技网站建设
  • 做资格核查在哪个网站中国建设银行网站查询密码是什么意思
  • 工程业绩在建设厅网站都能查到微信微网站统计
  • 孝感做网站公司游戏优化大师官网
  • 安徽省公共资源交易中心网站电商一共有什么平台
  • 长春搜索引擎网站推广线下推广引流渠道
  • 中国未来巨型空间站网站建设与开发课程内容
  • 老外做牛排的视频网站网站建设公司推荐q479185700顶上
  • node做网站后台西安企业模板建站
  • 石家庄网推公司郑州seo顾问
  • 东莞网站建设求职简历网站设置右击不了如何查看源代码
  • 东莞建网站的公查公司的网站有哪些
  • 网站建设与管理知识点互联网保险公司有哪几家
  • 微网站建设正规公司宿州高端网站建设公司哪家好
  • 服装网站网络建设和硬件资源商贸公司起名大全最新
  • 怎么做网站的浏览量常德网站开发网站运营
  • 自己架设服务器做网站个人网站 备案
  • 怎么做公司宣传网站岳阳网站建设收费标准
  • 做电商网站的上海公司手机人才网
  • asp网站制作教程重庆个人网站建设
  • 关于 门户网站 建设 请示信誉好的低价网站建设
  • 东莞品牌型网站建设科技类公司网站设计
  • 珠宝公司网站模版亚马逊aws wordpress
  • 网站权重分析域名有了怎么建设网站
  • 简单的seo网站优化排名在线房产网
  • 生活服务网站开发与设计网络营销师培训费用是多少
  • 在萍乡谁可以做网站ip做网站
  • 东湖网站建设福州网站开发si7.cc