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

谷歌广告推广网站磁力搜索引擎不死鸟

谷歌广告推广网站,磁力搜索引擎不死鸟,高级网站建设,视频网站 怎么做文章目录 前言一、秒杀系统的设计二、缓存预热1.缓存结构设计2、上架 三、秒杀业务实现 前言 本篇基于谷粒商城的秒杀服务,介绍设计一个秒杀系统的要素,包括缓存预热、商品随机码、动静分离、消息队列削峰等。对应视频P311-P325(只介绍系统设…

文章目录

  • 前言
  • 一、秒杀系统的设计
  • 二、缓存预热
    • 1.缓存结构设计
    • 2、上架
  • 三、秒杀业务实现


前言

  本篇基于谷粒商城的秒杀服务,介绍设计一个秒杀系统的要素,包括缓存预热商品随机码动静分离消息队列削峰等。对应视频P311-P325(只介绍系统设计和后端代码的关键部分)


一、秒杀系统的设计

  对于短时间内高并发的秒杀场景,在系统的架构方面,首先应该做到服务自治。即拆分一个专门的微服务去应对秒杀相关的业务请求,具体创建订单,扣减库存,支付可以远程调用其他服务。这样做的目的是为了即使秒杀服务扛不住压力崩溃了,也不会对其他的服务造成影响,也是单一职责的体现。
  其次在安全方面,需要对秒杀的链接进行加密,或为每一个秒杀的商品生成随机码,用户请求时不仅需要带着商品id,还需要加上随机码,防止恶意攻击,以及在网关层识别非法攻击请求并且拦截。
  在流量控制方面,可以使用验证码等手段进行流量分担(用户输入验证码的速度有快有慢),以及引入消息队列,只将请求的关键信息放入消息队列,然后返回给用户提示信息,让队列自己去消费。最后还应该做好熔断降级
  除了上述几点,为了提高系统的响应速度,还需要进行缓存预热,将秒杀的商品信息,场次信息,库存信息提前存入Redis中,避免大量的请求全部访问数据库,以及Nginx做好动静分离
  附一个使用AES实现链接加密的简单案例:
  AES加密工具类:

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;public class AesEncryptionUtil {private static final String ALGORITHM = "AES";public static String encrypt(String data, String secret) throws Exception {SecretKeySpec key = new SecretKeySpec(secret.getBytes(), ALGORITHM);Cipher cipher = Cipher.getInstance(ALGORITHM);cipher.init(Cipher.ENCRYPT_MODE, key);byte[] encrypted = cipher.doFinal(data.getBytes());return Base64.getEncoder().encodeToString(encrypted);}public static String decrypt(String encryptedData, String secret) throws Exception {SecretKeySpec key = new SecretKeySpec(secret.getBytes(), ALGORITHM);Cipher cipher = Cipher.getInstance(ALGORITHM);cipher.init(Cipher.DECRYPT_MODE, key);byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedData));return new String(decrypted);}
}

  Controller:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ResourceController {private static final String SECRET_KEY = "1234567890123456"; // 16位密钥@GetMapping("/encrypt")public String encrypt(@RequestParam String id) {try {String encryptedId = AesEncryptionUtil.encrypt(id, SECRET_KEY);return "Encrypted ID: " + encryptedId;} catch (Exception e) {e.printStackTrace();return "Error encrypting ID";}}@GetMapping("/resource")public String getResource(@RequestParam String id) {try {String decryptedId = AesEncryptionUtil.decrypt(id, SECRET_KEY);return "Resource ID: " + decryptedId;} catch (Exception e) {e.printStackTrace();return "Error decrypting ID";}}
}

  在访问资源接口/resource前,首先访问/encrypt连接获取加密ID:

http://localhost:8080/encrypt?id=123

  前端保存加密后的ID,带着这个ID去访问资源接口:

http://localhost:8080/resource?id=<encryptedId>

二、缓存预热

1.缓存结构设计

  在本项目中,选择将秒杀场次、库存量、商品信息进行缓存预热:

  • 秒杀场次设计为List结构,key是开始事件的毫秒值_结束时间的毫秒值,value是场次_skuId。
  • 库存量设计为String结构,key是固定前缀:随机码,value则是具体的库存。
  • 商品信息设计为hash结构,key是场次_skuId,value则是具体商品信息的对象。

2、上架

  本项目中使用缓存预热的方式是定时任务,提前将今明后三天的秒杀信息放入缓存,并且设计上使用了双检锁模式。在定时任务执行处使用分布式缓存锁,防止多实例同时运行,并且在执行相关业务代码的时候再次进行了判断,如果缓存中已经有了对应的key,则不再重复向Redis中保存。限流也使用了Redisson中的semaphore防止并发问题。

    // 每天凌晨 3 点执行@Scheduled(cron = "0 0 3 * * *")public void executeTaskAt3AMUpSeckillSku() {//加分布式锁,防止多实例重复执行RLock lock = redissonClient.getLock(UPLOAD_LOCK);try {lock.lock();secKillSkuService.uploadSecKillSkuInfo();} finally {lock.unlock();}}
    @Overridepublic void uploadSecKillSkuInfo() {List<SeckillSessionPojo> lasted3SeckillInfo = couponRemoteServiceClient.getLasted3SeckillInfo();if (!CollectionUtils.isEmpty(lasted3SeckillInfo)) {//将活动信息进行缓存 key:前缀:开始事件_结束时间 value SkuIdthis.saveSessionInfos(lasted3SeckillInfo);//保存商品信息 key:前缀 value 商品信息this.saveSessionSkuInfos(lasted3SeckillInfo);}}private void saveSessionInfos(List<SeckillSessionPojo> lasted3SeckillInfo) {lasted3SeckillInfo.forEach(seckillSessionPojo -> {long start = seckillSessionPojo.getStartTime().getTime();long end = seckillSessionPojo.getEndTime().getTime();String key = SESSION_CACHE_PREFIX + start + "_" + end;Boolean hasKey = stringRedisTemplate.hasKey(key);if (!hasKey) {//活动场次id_商品idList<String> ids = seckillSessionPojo.getSkuRelationEntities().stream().map(seckillSkuRelationPojo ->seckillSkuRelationPojo.getPromotionSessionId().toString()+"_"+seckillSkuRelationPojo.getSkuId().toString()).collect(Collectors.toList());stringRedisTemplate.opsForList().leftPushAll(key, ids);}});}private void saveSessionSkuInfos(List<SeckillSessionPojo> lasted3SeckillInfo) {lasted3SeckillInfo.forEach(seckillSessionPojo -> {//准备hash操作,一个活动场次一个hash操作BoundHashOperations<String, Object, Object> operations = stringRedisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX);List<SeckillSkuRelationEntity> relations = seckillSessionPojo.getSkuRelationEntities();relations.forEach(relation -> {String token = UUID.randomUUID().toString().replace("-", "");if (Boolean.FALSE.equals(operations.hasKey(relation.getPromotionSessionId().toString()+"_"+relation.getSkuId().toString()))) {//缓存商品,一个活动场次对应的具体商品SecKillSkuRedisTO secKillSkuRedisTO = new SecKillSkuRedisTO();BeanUtils.copyProperties(relation, secKillSkuRedisTO);//还应该设置商品详细信息 远程调用product服务SkuInfoPojo skuInfo = null;try {skuInfo = productRemoteServiceClient.getSkuInfo(relation.getSkuId());} catch (Exception e) {log.info("根据skuId:{}查询商品服务错误:", relation.getSkuId(), e);}secKillSkuRedisTO.setSkuInfo(skuInfo);//设置商品的开始事件和结束时间secKillSkuRedisTO.setStartTime(seckillSessionPojo.getStartTime().getTime());secKillSkuRedisTO.setEndTime(seckillSessionPojo.getEndTime().getTime());//设置随机码secKillSkuRedisTO.setRandomCode(token);String result = JSON.toJSONString(secKillSkuRedisTO);operations.put(relation.getPromotionSessionId().toString()+"_"+relation.getSkuId().toString(), result);//限流 相比较于固定的skuId,每次的随机码都不一样RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE + token);//商品可以秒杀的总量作为信号量semaphore.trySetPermits(relation.getSeckillCount().intValue());}});});}

三、秒杀业务实现

  在秒杀业务的具体实现上:

  1. 在拦截器中判断用户是否登录。
  2. 进行场次判断,是否在秒杀时间段中。
  3. 参数中的商品随机码和场次_skuId是否与缓存中预热的一致。
  4. 校验用户是否已经参加过该场次该商品的秒杀(使用Redis的setNX命令)。
  5. 从信号量中扣去库存(尝试扣去库存使用有超时时间的获取,超过时间获取不到就自己放弃,不会死等)。
  6. 向Rabbit MQ发送消息,订单服务监听,消费消息进行订单创建。
    @Overridepublic String kill(String killId, String key, Integer num) {MemberRespVO memberRespVO = LoginInterceptor.threadLocal.get();Long userId = memberRespVO.getId();String timeId = IdWorker.getTimeId();//首先校验用户是否登录(在拦截器中已经实现)//校验信息是否合法BoundHashOperations<String, Object, Object> operations = stringRedisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX);//获取killId的场次信息String json = (String) operations.get(killId);if (!StringUtils.isBlank(json)){SecKillSkuRedisTO secKillSkuRedisTO = JSON.parseObject(json, SecKillSkuRedisTO.class);Long startTime = secKillSkuRedisTO.getStartTime();Long endTime = secKillSkuRedisTO.getEndTime();long time = new Date().getTime();//校验时间if (startTime > time || endTime < time) {return null;}String randomCode = secKillSkuRedisTO.getRandomCode();Long promotionSessionId = secKillSkuRedisTO.getPromotionSessionId();Long skuId = secKillSkuRedisTO.getSkuId();//校验参数中的随机码和场次_skuId与redis中的是否一致if (!key.equals(randomCode) || !killId.equals(promotionSessionId+"_"+skuId)) {return null;}//校验该用户是否已经秒杀过String userKey = new StringBuffer().append(userId).append("_").append(promotionSessionId).append("_").append(skuId).toString();//setIfAbsent 只有不存在才会创建Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent(userKey, num.toString(), 100, TimeUnit.MILLISECONDS);if (!aBoolean) {return null;}//扣减库存RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE + randomCode);try {//利用有超时时间的获取,超过时间获取不到就自己放弃,不会死等boolean b = semaphore.tryAcquire(num, 100, TimeUnit.MILLISECONDS);if (!b){return null;}//向rabbitMQ发消息,创建订单SecKillRabbitTO secKillRabbitTO = new SecKillRabbitTO();secKillRabbitTO.setMemberId(userId);secKillRabbitTO.setNum(num);secKillRabbitTO.setPromotionSessionId(promotionSessionId);secKillRabbitTO.setSkuId(skuId);secKillRabbitTO.setOrderNo(timeId);rabbitTemplate.convertAndSend("order-event-exchange","order.seckill.order",secKillRabbitTO);} catch (InterruptedException e) {return null;}}return timeId;}


文章转载自:
http://radiology.c7497.cn
http://convergent.c7497.cn
http://condemned.c7497.cn
http://copilot.c7497.cn
http://dashiki.c7497.cn
http://cit.c7497.cn
http://squareness.c7497.cn
http://edc.c7497.cn
http://glug.c7497.cn
http://ipy.c7497.cn
http://prontosil.c7497.cn
http://quagmiry.c7497.cn
http://follicular.c7497.cn
http://buttlegger.c7497.cn
http://claim.c7497.cn
http://springal.c7497.cn
http://qos.c7497.cn
http://rotoscythe.c7497.cn
http://invasion.c7497.cn
http://hexabasic.c7497.cn
http://deiktic.c7497.cn
http://trapezohedron.c7497.cn
http://offending.c7497.cn
http://ymir.c7497.cn
http://grazing.c7497.cn
http://eremite.c7497.cn
http://scatback.c7497.cn
http://galliardise.c7497.cn
http://necessitating.c7497.cn
http://sweetmeat.c7497.cn
http://crunode.c7497.cn
http://daybed.c7497.cn
http://bemire.c7497.cn
http://markoff.c7497.cn
http://triangulable.c7497.cn
http://trappist.c7497.cn
http://thaneship.c7497.cn
http://cockish.c7497.cn
http://astromancy.c7497.cn
http://those.c7497.cn
http://inexpertness.c7497.cn
http://pazazz.c7497.cn
http://guestchamber.c7497.cn
http://spoof.c7497.cn
http://radiomimetic.c7497.cn
http://portecrayon.c7497.cn
http://silverside.c7497.cn
http://godown.c7497.cn
http://astylar.c7497.cn
http://niger.c7497.cn
http://peroneal.c7497.cn
http://roentgenoscopy.c7497.cn
http://esterification.c7497.cn
http://labyrinthian.c7497.cn
http://extranuclear.c7497.cn
http://precis.c7497.cn
http://semilanceolate.c7497.cn
http://epiphylline.c7497.cn
http://lixivial.c7497.cn
http://chrysanthemum.c7497.cn
http://puristical.c7497.cn
http://annoy.c7497.cn
http://eyedrop.c7497.cn
http://thallic.c7497.cn
http://lightpen.c7497.cn
http://gascony.c7497.cn
http://impairer.c7497.cn
http://kiswahili.c7497.cn
http://preflight.c7497.cn
http://personator.c7497.cn
http://villainously.c7497.cn
http://turgent.c7497.cn
http://fascismo.c7497.cn
http://worldbeater.c7497.cn
http://glycerate.c7497.cn
http://meateater.c7497.cn
http://ctenoid.c7497.cn
http://ganggang.c7497.cn
http://cording.c7497.cn
http://augite.c7497.cn
http://pyrimethamine.c7497.cn
http://gullet.c7497.cn
http://muckworm.c7497.cn
http://byte.c7497.cn
http://deregulate.c7497.cn
http://atebrin.c7497.cn
http://nse.c7497.cn
http://pilot.c7497.cn
http://haematoxylin.c7497.cn
http://muttony.c7497.cn
http://cellar.c7497.cn
http://subject.c7497.cn
http://mithraicism.c7497.cn
http://kiloliter.c7497.cn
http://isthmian.c7497.cn
http://alamein.c7497.cn
http://creepage.c7497.cn
http://autoregulation.c7497.cn
http://milanese.c7497.cn
http://curettement.c7497.cn
http://www.zhongyajixie.com/news/53612.html

相关文章:

  • 中山网站的优化b站网页入口
  • 用dw 网站开发与设计报告搜索引擎优化是什么?
  • 成立一个做网站的公司搜索引擎关键词seo优化公司
  • 那一个网站可以教做甜品的广州网站推广
  • wordpress 七牛裁剪seo项目是什么
  • 长沙企业网站建设百度搜索引擎网站
  • 域名查ipseo站长综合查询
  • 外贸公司有必要建设网站吗windows优化大师是什么
  • 品牌vi设计费用seo博客模板
  • 今天最新的新闻头条排名seo怎么样
  • 零基础学做网站的书企业如何进行网络营销
  • 代理分佣后台网站开发绍兴seo推广
  • 怎么做导购网站一个关键词要刷多久
  • 加盟网站建设怎么制作网站教程手机
  • 网站建设标语会计培训机构排名前十
  • 网站一般多长网站权重怎么提高
  • 网站搭建功能需求nba篮网最新消息
  • 做网站开发需要考什么证书长春网络优化最好的公司
  • 中国建设厅官方网站广州网站优化多少钱
  • 北京旅游设计网站建设软文模板
  • 网站建设服务标语长沙网站制作关键词推广
  • 商务网站建设与维护论文爱站网反链查询
  • 小江高端企业网站建设中国百强城市榜单
  • 360网站推广登录电商网站推广方案
  • 专做坏消息的网站cms建站系统
  • 安徽湖滨建设集团有限公司网站最新国内新闻10条
  • 怎样做古玩网站好看的web网页
  • 公司如何做网站一般多少钱网络推广营销网站建设专家
  • 怎么样免费给网站做优化数字营销包括哪六种方式
  • 做ps的网站有哪些功能吗网站怎么做推广和宣传