分布式电商系统核心模块实现说明

2023-11-25 08:40

本文主要是介绍分布式电商系统核心模块实现说明,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

分布式电商系统核心模块

  • es全文检索
  • redis商品详情页
  • cookie购物车
  • 基于jwt的SSO单点登录
  • 社交登录【微博】
  • 支付-订单-库存

es全文检索

  1. 定义es的索引结构

就是将数据库里的 skuId,skuName,skuDesc,catalog3Id,price,skuDefaultImg,productId,skuAttrValueList【颜色,尺寸】数据查出来之后封装成一张表/对象PmsSearchSkuInfo,放到es的索引/库里面存着

PUT gmall0105
{"mappings": {"PmsSkuInfo":{"properties": {"id":{"type": "keyword","index": true},"skuName":{"type": "text","analyzer": "ik_max_word"},"skuDesc":{"type": "text", "analyzer": "ik_smart"},"catalog3Id":{"type": "keyword"},"price":{"type": "double"},"skuDefaultImg":{"type": "keyword","index": false},"hotScore":{"type": "double"},"productId":{"type": "keyword"},"skuAttrValueList":{"properties": {"attrId":{"type":"keyword"},"valueId":{"type":"keyword"}}}} }} 
}
  1. 使用es的java客户端代码批量导入数据到es中
for (PmsSearchSkuInfo pmsSearchSkuInfo : pmsSearchSkuInfos) {Index put = new Index.Builder(pmsSearchSkuInfo).index("gmall0105").type("PmsSkuInfo").id(pmsSearchSkuInfo.getId()+"").build();jestClient.execute(put);
}获取页面传来的查询参数,并构造所需的dsl语句字符串
boolQueryBuilder.filter(termQueryBuilder);  //精准匹配后过滤
boolQueryBuilder.must(matchQueryBuilder);  //模糊匹配
searchSourceBuilder.sort("id", SortOrder.DESC);//排序  searchSourceBuilder.aggregation();  //聚集
searchSourceBuilder.query(boolQueryBuilder); //查询结构,构造完成
Search search = new Search.Builder(searchSourceBuilder).addIndex("gmall0105").addType("PmsSkuInfo").build();
execute = jestClient.execute(search);   发起查询
List<SearchResult.Hit> hits=execute.getHits()得到查询结果
for(){pmsSearchSkuInfos.add(hit.source);}   转成java对象for(pmsSearchSkuInfos.skuAttrValueList){ 得到对应的 attrList  }  根据商品的sku销售属性,得到商品所对应的平台属性,因为需要实现面包屑的效果【需要在整个的平台属性中减去查询出来的商品的平台属性】
将从es中查询到skuInfoList返回给页面

最后测试网址:
http://localhost/listes?catalog3Id=61&valueId=39&valueId=43&valueId=48&keyword=硅谷

  • 各查询参数说明【平台属性,关键字,三级分类ID】
    catalog3Id=61------手机/手机通讯/手机
    valueId=(39,43,48)----屏幕尺寸:4寸以下,内存容量:16G,尺寸:z1
    keyword=硅谷 -----搜索框里输入硅谷进行全文检索

redis商品详情页

在高并发下缓存击穿,穿透,雪崩问题的解决

cookie购物车

在这里插入图片描述

 //存---使用redis的hash数据结构存储购物车数据jedis.hmset("user:"+memberId+":cart",map);map.put(OmsCartItem.getProductSkuId(), JSON.toJSONString(OmsCartItem));
//取---List< String> hvals = jedis.hvals("user:" + userId + ":cart");OmsCartItem omsCartItem = JSON.parseObject(hval, OmsCartItem.class);

注意点:
1、redis中取出来要进行反序列化
2、redis的hash结构是无序的,要进行排序(可以用时间戳或者主键id,倒序排序)
3、如果redis中没有要从数据库中查询,要连带把最新的价格也取出来,默认要显示最新价格而不是当时放入购物车的价格,如果考虑用户体验可以把两者的差价提示给用户。
4、加载入缓存时一定要设定失效时间,保证和用户信息的失效时间一致即可。
5、由于加入购物车时,用户可能存在登录和未登录两种情况,登录前在cookie中保存了一部分购物车信息,如果用户登录了,那么对应的要把cookie中的购物车合并到数据库中,并且刷新缓存。【登陆时:合并购物车,刷新缓存】
6、从对应域名下找cookie
在这里插入图片描述
测试网址: http://localhost:9999/addToCart?skuId=25&quantity=2 添加购物车
http://localhost:9999/cartList 查询购物车

1 购物车在不登陆的情况下,也可以使用
需要引入对浏览器cookie的操作2 购物车在登录的情况下,需要使用mysql和redis来存储数据
Redis作为购物车的缓存3 在缓存情况下,或者用户已经添加购物车后,允许购物车中的数据和原始商品数据的不一致性4 购物车同步问题
什么时候同步(结算、登录)
同步购物车后,是否需要删除cookie数据5 用户在不同的客户端同时登录
如何处理购物车数据

在这里插入图片描述

基于jwt的SSO单点登录

服务应该是并行的,而非串行的【购物车挂了,后续流程都挂】

  • 为何要使用sso单点登录
    因为分布式下session无法跨顶级域名共享,且安全性不高,保存在cookie里面的session的唯一标识jsseionId容易被截取。
//京东的首页,商品页,商品详情页,全文检索页,购物车等每个模块都是一个独立的系统,有自己的域名
https://www.jd.com/  			京东首页https://list.jd.com/list.html?cat=9987,653,655    	三级分类下的商品页【9987一级分类,653二级分类,655三级分类】https://item.jd.com/49405721859.html     		商品详情页【sku=49405721859】https://search.jd.com/search?keyword=电脑&cid3=672	全文检索页【关键词电脑,平台属性cid3为672------》电脑/笔记本】https://cart.jd.com/cart.action?r=0.35325141737280386    	购物车【当前是未登录状态,使用cookie保存了购物车的信息】所以我在实现的时候,这几个模块的controller不应该放在同一个web模块下。

社交登录【微博】

(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。

1、【微博开放平台创建应用(填写用户授权后的网页授权回调地址)】点击微博登录—》跳转到
https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI
在这里插入图片描述
2、用户同意授权【输入用户的微博号和密码,对接微博登录成功】,页面跳转至 xxx/?code=CODE

http://www.gulishop.com/success?code=fef987b3f9ad1169955840b467bfc661

3、使用返回的code,换取access token
5、使用返回的code,换取access token
4、使用access token调用开发API获取用户信息(去访问任何微博开放平台的API)
1)、code用后即毁
2)、access_token在几天内是一样的
社交登录开发完毕
在这里插入图片描述

String show_user_url = "https://api.weibo.com/2/users/show.json?access_token="+access_token+"&uid="+uid;String user_json = HttpclientUtil.doGet(show_user_url);  //对接微博,获取用户信息Map<String,Object> user_map = JSON.parseObject(user_json,Map.class);// 将用户信息保存数据库,用户类型设置为微博用户UmsMember umsMember = new UmsMember();umsMember.setSourceType("2");umsMember.setAccessCode(code);umsMember.setAccessToken(access_token);umsMember.setNickname((String)user_map.get("screen_name"));

支付-订单-库存

从购物车用户点击结算,生成订单,订单状态是未付款,用户确认订单后点击付款,此时锁定库存,再发消息给订单,更新订单状态为库存已锁定,然后发消息给支付,开始支付,支付成功,就更新订单状态为已支付,假如在支付的时候,由于账户不足,导致支付失败,就进行消息回滚,其实更新订单,锁定库存事务也会进行回滚

//提交订单
@RequestMapping("alipay/submit")@LoginRequired(loginSuccess = true)@ResponseBodypublic String alipay(String outTradeNo, BigDecimal totalAmount, 数量){alipayClient.pageExecute(alipayRequest【订单号,购买数量】).getBody(); //调用SDK生成表单// // 向消息中间件发送一个检查支付状态(支付服务消费)的延迟消息队列----起点paymentService.sendDelayPaymentResultCheckQueue(outTradeNo,5);//发消息到一个队列里面return form;  //跳转到阿里的扫码支付页面
}Queue payhment_success_queue = session.createQueue("PAYMENT_CHECK_QUEUE");MessageProducer producer = session.createProducer(payhment_success_queue);
// 为消息加入延迟时间mapMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY,1000*60); producer.send(mapMessage);@JmsListener(destination = "PAYMENT_CHECK_QUEUE",containerFactory = "jmsQueueListener")public void consumePaymentCheckResult(MapMessage mapMessage) throws JMSException {
// 调用paymentService的支付宝检查接口   
paymentService.updatePayment(paymentInfo);====Queue payhment_success_queue = session.createQueue("PAYHMENT_SUCCESS_QUEUE");MessageProducer producer = session.createProducer(payhment_success_queue);
producer.send(mapMessage);@JmsListener(destination = "PAYHMENT_SUCCESS_QUEUE",containerFactory = "jmsQueueListener")public void consumePaymentResult(MapMessage mapMessage) throws JMSException { orderService.updateOrder(omsOrder);【已支付】=====》Queue payhment_success_queue = session.createQueue("ORDER_PAY_QUEUE"); @JmsListener(destination = "ORDER_PAY_QUEUE", containerFactory = "jmsQueueListener")public void receiveOrder(TextMessage textMessage) throws JMSException { // 库存削减【锁库存】gwareService.lockStock(orderTask);//库存正常就锁库存,异常就 //库存超卖 记录日志,返回错误状态wareSkuMapper.incrStockLocked(wareSku);
}     
1. 假如库存中有10件商品,a提交完订单(数量9件),此时(锁定数量9),此时还没调用付款,b马上提交了订单数量为2件,此时锁定数量为11就超过了库存数量,b操作失败【页面提示库存不足】2. 库存中有10件商品,A,锁定的3件,隔段时间b锁定了4件,总的锁定就为7件,此时假设仓库管理员把a的商品3件出库了,此时出库数量为3,总锁定数量为4件,库存数量变为73. 库存中有10件商品,A,锁定了3件,但此时由于a的卡上余额不足,则进行回退撤销a锁定的3键,锁定数量变为零,支付失败。
1. 提交订单时,先校验数据库中的价格是否有变动?库存,比如你购买了十件,他会去查看仓库里是否有十件货,【验证库存数量--数量不足就return null】,而不是锁库存的数量,也不是库存减去所库存的数量2. 此时订单创建完毕,就跳转到支付3. 支付--》订单--》库存要保证分布式事务的一致性,如果抛异常就进行事务的回滚向支付成功队列里面发送支付成功的消息,然后提交事务订单业务收到消息更新订单状态为已付款..向库存发消息库存系统进行锁库存【更新库存锁定数量字段比如为2】,比如说库存数量更新为二,更新订单状态为商品准备出库,比如库存只有十件,但是我库存却出现了20件这时候数据库里所库存阶段维持,然后抛出错误,抄卖一场的日志到日志文件里面订单更新完状态之后又会通知物流系统,实时物流系统会发送物品及物品出库此时库存数量会减,然后以出库数量会增加然后订单状态更新为已出库

我们正常不可能在同一时间点击按钮多次,但是黑客通过程序可以实现在同一时间发送多个请求,并且用同一个交易码,这就可能导致高并发下(通过一个交易码多次提交订单,正常情况下是一个交易码,只能提交一次订单

购物车里有五件商品,也相当于有五个订单,你提交的时候,如果一个商品及其中的一个订单,他没有库存了,那你如果把所有的五个订单都回滚,用户体验不太好(京东是直接替用户做决定的,把你不合格的那个订单直接给他删了在购物车里给他删了这其实是不好的你应该直接让用户重新操作,重新去修改订单,直到他教研通过为止)

交易订单号是自己程序,可以选择生成的,可以用你的私钥加上当前时间出来申请订单号,然后再用支付宝借口的时候传入订单号

saveorder,在保存订单时删除购物车的数据

使用dubbo的时候可以指令协议,默认的是dubbo协议

服务器和服务器之间可以通过一步进行信息的交流,如支付宝直接对支付服务器发送银行转账已完成的这种消息

实际库存数量就是仓库里实际有的商品
锁定库存数量就是当前用户下单,付完钱之后买了两件商品

决定要不要拆单试看一个sku能不能在库存表里面一次完成?鸡你买了十个红色手机,那这十个红色手机能否在一个库存,里面取出来,因为我们的仓库可能有多个,比如北京有一个仓库,南京有一个仓库,可能北京的仓库里面有三个红色手机,南京的仓库里面有七个红色手机,那就需要进行三把十个手机分成3和7,然后从三号上号上面

该订单的商品都在一个库存里面,所以直接调用首库存就可以了,如果发生拆单,那就循环进行锁库存

这篇关于分布式电商系统核心模块实现说明的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/423471

相关文章

Zookeeper安装和配置说明

一、Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式。 ■ 单机模式:Zookeeper只运行在一台服务器上,适合测试环境; ■ 伪集群模式:就是在一台物理机上运行多个Zookeeper 实例; ■ 集群模式:Zookeeper运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble) Zookeeper通过复制来实现

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P