谷粒商城学习笔记

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

一、项目简介

1、项目背景

1、电商模式

在这里插入图片描述

2、谷粒商城

谷粒商城是一个 B2C 模式的电商平台销售自营商品给客户。

2、项目架构图

1、项目微服务架构图

在这里插入图片描述

2、微服务划分图

在这里插入图片描述

3、项目技术&特色

在这里插入图片描述

4、项目前置要求

在这里插入图片描述

二、分布式基础概念

2、集群&分布式&节点

分布式是指将不同的业务分布在不同的地方。
集群指的是将几台服务器集中在一起实现同一业务。
例如京东是一个分布式系统众多业务运行在不同的机器所有业务构成一个大型的业务集群。每一个小的业务比如用户系统访问压力大的时候一台服务器是不够的。我们就 应该将用户系统部署到多个服务器也就是每一个业务系统也可以做集群化 分布式中的每一个节点都可以做集群。 而集群并不一定就是分布式的。 节点集群中的一个服务器

4、负载均衡

在这里插入图片描述

7、服务熔断&服务降级

1、服务熔断 a. 设置服务的超时当被调用的服务经常失败到达某个阈值我们可以开 启断路保护机制后来的请求不再去调用这个服务。本地直接返回默认 的数据
2、服务降级 a. 在运维期间当系统处于高峰期系统资源紧张我们可以让非核心业 务降级运行。降级某些服务不处理或者简单处理【抛异常、返回 NULL、 调用 Mock 数据、调用 Fallback 处理逻辑】。

三、项目架构

架构图

在这里插入图片描述

微服务划分图

在这里插入图片描述

四、环境搭建

docker

centos安装docker

https://docs.docker.com/engine/install/centos/

设置开机自启

systemctl enable docker

设置开机自启docker容器mysql服务

docker update mysql --restart=always

配置阿里云镜像加速

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-‘EOF’
{
“registry-mirrors”: [“https://76ra8yjq.mirror.aliyuncs.com”]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

docker安装mysql

启动docker镜像

docker run -p 3306:3306
–name mysql
-v /mydata/mysql/log:/var/log/mysql
-v /mydata/mysql/data:/var/lib/mysql
-v /mydata/mysql/conf:/etc/mysql
-e MYSQL_ROOT_PASSWORD=root
-d mysql:5.7
参数说明-p 3306:3306将容器的 3306 端口映射到主机的 3306 端口 -v /mydata/mysql/conf:/etc/mysql将配置文件夹挂载到主机 -v /mydata/mysql/log:/var/log/mysql将日志文件夹挂载到主机 -v /mydata/mysql/data:/var/lib/mysql/将配置文件夹挂载到主机 -e MYSQL_ROOT_PASSWORD=root初始化 root 用户的密码

进入docker容器

docker exec -it f1178d5b0bd8 /bin/bash

修改mysql配置文件

vi /mydata/mysql/conf/my.cnf

[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect=‘SET collation_connection = utf8_unicode_ci’
init_connect=‘SET NAMES utf8’
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve

使配置文件生效

docker ps
docker restart mysql

docker安装redis

挂载可能会把文件当成目录所以预先创建好文件

mkdir -p /mydata/redis/conf
touch /mydata/redis/conf/redis.conf
docker run -p 6379:6379 --name redis -v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf

连接容器内redis客户端

docker exec -it redis redis-cli

当前数据保存在内存中需要配置持久化规则

vim /mydata/redis/conf/redis.conf
appendonly yes
docker restart redis

maven

在这里插入图片描述

git使用ssh连接

在这里插入图片描述

git管理仓库
在这里插入图片描述

开发生产者模型开发在dev分支开发完成合并到master分支

idea新建项目
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建微服务项目

在这里插入图片描述
在这里插入图片描述
从模块中复制一个pom文件放在根目录下进行修改

可以取消这两个勾选它会检查分析代码包括TODO
在这里插入图片描述
在这里插入图片描述

数据库设计

在这里插入图片描述

整合人人开源-后台管理系统

下载

https://gitee.com/renrenio 下载renren-fast和renren-fast-vue
快速搭建后台管理系统:renren-fast整合到gulimall项目中vscode打开renren-fast-vue配置开发环境
npm install npm run dev

配置前端运行环境

node.js

在这里插入图片描述

代码生成器逆向工程

下载https://gitee.com/renrenio/renren-generator.git

整合进gulimall项目修改配置文件先生成product模块基本文件在这里插入图片描述

在这里插入图片描述
运行服务访问localhost,点击生成下载.zip压缩文件解压放进gulimall-product
在这里插入图片描述
缺失很多依赖创建common模块,引入依赖和renren-fast中的部分依赖文件
shift+f6修改模块名称
修改逆向工程不使用shiro依赖重新生成代码
在这里插入图片描述

分布式组件

服务注册

1、引入依赖
在这里插入图片描述
2、开启服务注册
在这里插入图片描述
3、编写配置文件
在这里插入图片描述

feign

1、导入依赖
在这里插入图片描述
2、开启支持feign远程调用
在这里插入图片描述

3、编写声明式接口
在这里插入图片描述

配置中心

如何使用nacos作为配置中心统一管理配置

1、引入依赖

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>

2、创建一个bootstrap.properties文件
spring.application.name=guli-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

3、需要给配置中心默认添加一个叫 数据集Data Idguli-coupon.properties。默认规则应用名.properties

4、给 应用名.properties添加任何配置

5、动态获取配置
@RefreshScope动态获取并刷新配置
@Value(“${配置项的名称}”):获取配置
配置中心优先级>本地配置优先级

gateway

前端内容

ES6

ECMAScript 6.0以下简称 ES6ECMAScript 是一种由 Ecma 国际(前身为欧洲计算机制造商 协会,英文名称是 European Computer Manufacturers Association)通过 ECMA-262标准化的脚本 程序设计语言是 JavaScript 语言的下一代标准

模块化

vue

1、文件夹内终端敲入命令npm init -y
2、npm install vue
3、引入vuescript中src=“./node_modules/vue/dist/vue.js”
在这里插入图片描述
vue生命周期

vue模块化开发

在这里插入图片描述
在这里插入图片描述

目录结构

在这里插入图片描述

项目开发

商品服务

1、数据库导入数据
2、运行renren-vue和后台

配置网关

请求转发Service Unavailable问题

https://blog.csdn.net/kitahiragawa/article/details/124229580

原因这是由于版本不兼容引发的问题我当前使用的springcloud alibaba版本为2021.0.1.0而springcloud alibaba在2020版之后不支持ribbon,而springcloud gateway使用ribbon就导致了gateway无法路由到目标服务

跨域问题

不是简单请求就需要发送一个Options方式的预检请求

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

在这里插入图片描述

解决跨域

在这里插入图片描述
在这里插入图片描述

product模块逻辑删除

1、配置全局的逻辑删除规则省略
2、配置逻辑删除的组件Bean省略
3、给Bean加上逻辑删除注解@TableLogic

商品服务-三级分类

商品服务-品牌管理

oss上传

根据github上springCloudAlibaba演示demo引入
https://github.com/alibaba/spring-cloud-alibaba

在这里插入图片描述


nacos config配置
yml文件配置
在这里插入图片描述

注意点需要加如下依赖

<!–cloud新版本默认将bootstrap移除了所以需要添加如下依赖–>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bootstrap</artifactId>
    </dependency>

在这里插入图片描述
在这里插入图片描述

table显示图片

table->自定义模板->在里面配置template,scope内容自定义显示
在这里插入图片描述
异常排查
在这里插入图片描述

1、main.js是否引入elementui
2、main.js引入的是src下的elementui
3、elemnetui/index.js中没有引入image
4、去element官网快速上手配置引入image

jsr303数据校验

JSR303
1、给Bean添加校验注解:javax.validation.constraints并定义自己的message提示
2)、开启校验功能@Valid
效果校验错误以后会有默认的响应
3、给校验的bean后紧跟一个BindingResult就可以获取到校验的结果
4、分组校验多场景的复杂校验
1)、 @NotBlank(message = “品牌名必须提交”,groups = {AddGroup.class,UpdateGroup.class})
给校验注解标注什么情况需要进行校验
2、@Validated({AddGroup.class})
3)、默认没有指定分组的校验注解@NotBlank在分组校验情况@Validated({AddGroup.class})下不生效只会在@Validated生效
5、自定义校验
1、编写一个自定义的校验注解
2、编写一个自定义的校验器 ConstraintValidator
3、关联自定义的校验器和自定义的校验注解

统一异常处理

统一的异常处理
@ControllerAdvice
1、编写异常处理类使用@ControllerAdvice。
2、使用@ExceptionHandler标注方法可以处理的异常。

spu、sku

SPUStandard Product Unit标准化产品单元
SKUStock Keeping Unit库存量单位

iphoneX 是 SPU、MI 8 是 SPU
iphoneX 64G 黑曜石 是 SKU
MI8 8+64G+黑色 是 SKU

Object划分

在这里插入图片描述
在这里插入图片描述

项目运行内存配置

1、新建、配置compound
在这里插入图片描述
2、配置最大占用内存
在这里插入图片描述
在这里插入图片描述

@Transactional分析

断点执行看不到之前代码的入库数据

1、因为事务没有提交之前数据是读不出来的
2、mysql默认的隔离级别是可重复读就是最起码读到已经提交了的数据为了测试方便将当前会话的隔离级别等级设置为读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
3、然后就可以很方便得查看数据库变化

让@Transactional事务遇到异常不回滚

1、可以使用try catch捕获异常
2、
在这里插入图片描述

库存&采购流程

采购需求->合并整单->采购单->库存

在这里插入图片描述

基础篇总结

#在这里插入图片描述

分布式高级篇

ElasticSearch

官方文档https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
官方中文https://www.elastic.co/guide/cn/elasticsearch/guide/current/foreword_id.html 社区中文 https://es.xiaoleilu.com/index.html http://doc.codingdict.com/elasticsearch/0/

在这里插入图片描述
在这里插入图片描述

1、下载镜像文件

docker pull elasticsearch:7.4.2 存储和检索数据
docker pull kibana:7.4.2 可视化检索数据

2、创建实例

1、ElasticSearch

mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data
echo “http.host: 0.0.0.0” >> /mydata/elasticsearch/config/elasticsearch.yml
chmod -R 777 /mydata/elasticsearch/ 保证权限
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e “discovery.type=single-node”
-e ES_JAVA_OPTS=“-Xms64m -Xmx512m” \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2

http.host: 0.0.0.0 es可以被远程任何机器访问
-e:配置参数
-p:暴露端口-9200是我们给es的restAPI发请求的端口-9300是es在分布式集群状态下的节点通信端口
discovery.type单节点模式
ES_JAVA_OPTS不指定的话es一启动会将内存全部占用虚拟机就卡死了
-d:后台启动

以后再外面装好插件重启即可
特别注意 -e ES_JAVA_OPTS=“-Xms64m -Xmx256m” \ 测试环境下设置 ES 的初始内存和最大内存否则导 致过大启动不了 ES

查看日志docker logs elasticsearch

访问http://192.168.233.141:9200/

2、Kibana

docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.233.141:9200 -p 5601:5601 \ -d kibana:7.4.2

访问http://192.168.233.141:5601/app/kibana#/dev_tools/console?_g=()

初步检索

在这里插入图片描述
在这里插入图片描述
_seq_no可以作乐观锁
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

样本数据 acounts.json

https://github.com/elastic/elasticsearch/blob/7.5/docs/src/test/resources/accounts.json

进阶检索

https://www.elastic.co/guide/en/elasticsearch/reference/7.4/getting-started-search.html

启动docker容器

docker ps -a
docker start containerId
开机自启
docker update containerId --restart=always

mapping

type是keyword类型不会进行全文检索只会精确匹配
type是text类型的全文检索保存数据的时候进行分词检索的时候按照分词进行匹配

ES5.0及以后的版本取消了string类型将原先的string类型拆分为text和keyword两种类型。它们的区别在于text会对字段进行分词处理而keyword则不会进行分词。
也就是说如果字段是text类型存入的数据会先进行分词然后将分完词的词组存入索引而keyword则不会进行分词直接存储。
text类型的数据被用来索引长文本例如电子邮件主体部分或者一款产品的介绍这些文本会被分析在建立索引文档之前会被分词器进行分词转化为词组。经过分词机制之后es允许检索到该文本切分而成的词语但是text类型的数据不能用来过滤、排序和聚合等操作。
keyword类型的数据可以满足电子邮箱地址、主机名、状态码、邮政编码和标签等数据的要求不进行分词常常被用来过滤、排序和聚合

安装ik分词器

1、下载https://github.com/medcl/elasticsearch-analysis-ik/releases?after=v6.4.2
2、解压到plugin文件夹装在ik目录中
在这里插入图片描述
3、进入es容器:docker exec -it 容器id /bin/bashelasticsearch-plugin list
在这里插入图片描述
4、重启容器
docker restart elasticsearch

docker安装nginx

在这里插入图片描述

es自定义词库

在这里插入图片描述
在这里插入图片描述

springboot整合es

为什么不用js直接操作es
1、安全性
2、js对es支持度低

分析
1、方便检索
{
skuId:1
spuId:11
skuTitle:华为xx
price:998
saleCount:99
attrs:[{尺寸:4寸},{CPU高通945},{分辨率全高清}]
}
冗余:100w商品 每个商品20个属性假设合起来2kb数据 100w2kb=2000MB=2G 商城系统多了2G
2、
sku索引{
skuId:1
spuId:11
xxxxxx
}
attr索引{
spuId11
attrs:[{尺寸:4寸},{CPU高通945},{分辨率全高清}]
}
问题: 搜索’小米’ 粮食、手机、电器
1w个 4k个spu
分步4k个spu对应的所有可能属性
esClient请求搜索4k个spuId,每个都是long型数据 4k
8=32000byte=32kb
1w人在商城检索商品1w*32kb=320MB 一次光数据传输320mb,高并发情况下会网络阻塞
总结空间和时间不能二者兼得所以我们这里选择第一种设计模型

PUT product
{
“mappings”: {
“properties”: {
“skuId”: {
“type”: “long”
},
“spuId”: {
“type”: “keyword”
},
“skuTitle”: {
“type”: “text”,
“analyzer”: “ik_smart”
},
“skuPrice”: {
“type”: “keyword”
},
“skuImg”: {
“type”: “keyword”,
“index”: false,
“doc_values”: false
},
“saleCount”: {
“type”: “long”
},
“hasStock”: {
“type”: “boolean”
},
“hotScore”: {
“type”: “long”
},
“brandId”: {
“type”: “long”
},
“catalogId”: {
“type”: “long”
},
“brandName”: {
“type”: “keyword”,
“index”: false,
“doc_values”: false
},
“brandImg”: {
“type”: “keyword”,
“index”: false,
“doc_values”: false
},
“catalogName”: {
“type”: “keyword”,
“index”: false,
“doc_values”: false
},
“attrs”: {
“type”: “nested”,
“properties”: {
“attrId”: {
“type”: “long”
},
“attrName”: {
“type”: “keyword”,
“index”: false,
“doc_values”: false
},
“attrValue”: {
“type”: “keyword”
}
}
}
}
}
}
index:false 表示该属性不可用来被检索
doc_values: true 表示可以用来作聚合、排序、脚本等操作进行空间节省
“type”: “nested” 表示属性子对象中的某些值进行检索

nginx+windows搭建域名访问环境

在这里插入图片描述

域名解析我们在浏览器上敲gulimall.comwindows如何知道哪个域名对应哪个ip地址
1、查看系统内部系统映射规则网卡带我们转过去
2、如果系统没告诉gulimall.com在哪个地址那就去网络上的dns(比如114.114.114.114,8.8.8.8)解析出域名(dns中保存了每个域名对应每个ip地址在公网保存)查看ip映射规则

在这里插入图片描述

1、配置hosts
192.168.233.141 gulimall.comhttp://gulimall.com:9200/测试配置是否成功
2、配置nginx配置文件请求发到网关
在这里插入图片描述
3、在网关配置转发策略
在这里插入图片描述
4、域名请求依然是404
在这里插入图片描述
因为nginx代理给网关的时候会丢失请求的host信息
配置proxy_set_header Host $host
在这里插入图片描述

压力测试

在这里插入图片描述
在这里插入图片描述

java内存模型

压测数据

压测内容路径压测线程数吞吐量/s90%响应时间99%响应时间
Nginxhttp://192.168.233.141:80/50233511944
Gatewayhttp://localhost:88/5010367831
简单服务localhost:10000/hello5011341817
首页一级菜单渲染localhost:1000050270(db,thymeleaf)267365
首页渲染thymeleaf开缓存localhost:1000050290251365
首页渲染thymeleaf开缓存、 优化数据库、降低日志级别日 志(关日志)localhost:1000050700105183
三级分类数据获取localhost:10000/index/catalog.json502(db)/8(加索引)
三级分类优化业 务,减少与数据库的交互localhost:10000/index/catalog.json50111571896
三 级 分 类 使 用 redis 作为缓存localhost:10000/index/catalog.json50411153217
首页全量数据获取localhost:10000507(静态资源)
Nginx+Gateway50
Gateway+简单服务localhost:88/hello50312630125
全链路gulimall.com/hello5080088310

监控内存使用率等数据:docker stats

测nginx
在这里插入图片描述
在这里插入图片描述
简单服务
在这里插入图片描述

首页全量数据获取
在这里插入图片描述
在这里插入图片描述
开thymeleaf缓存、优化数据库、关日志、nginx动静分离
效果还是不明显吞吐量从7-11
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述开thymeleaf缓存、优化数据库、关日志、nginx动静分离、调节内存
在这里插入图片描述

-Xms 堆内存的初始大小默认为物理内存的1/64
-Xmx 堆内存的最大大小默认为物理内存的1/4
-Xmn 堆内新生代的大小。通过这个值也可以得到老生代的大小-Xmx减去-Xmn
-Xss 设置每个线程可使用的内存大小即栈的大小

在这里插入图片描述
在这里插入图片描述

测试服务崩溃
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
三 级 分 类 使 用 redis 作为缓存
在这里插入图片描述

在这里插入图片描述
问题压测报错
在这里插入图片描述

在这里插入图片描述

解决
TODO:压测产生堆歪内存溢出OutOfDirectMemoryError
1springboot2.0以后默认使用lettuce作为操作redis的客户端它使用netty来进行网络通信
2lettuce的bug导致netty堆外内存溢出 -Xmx300m netty如果没有指定堆外内存默认使用-Xmx300m
可以通过-Dio.netty.maxDirectMemory进行设置
解决方案不能使用-Dio.netty.maxDirectMemory只去调大堆外内存调大内存只能延缓报错的时间
1、升级lettuce客户端
2、切换使用jedis客户端
在这里插入图片描述

总结
1、中间件越多性能损失越大大多都损失在网络交互了
2、业务
 DbMySQL 优化  模板的渲染速度缓存  静态资源

优化数据库
新建索引
在这里插入图片描述

动静分离

1、在nginx的html文件夹中新建static文件夹
2、将guli-product中的index下静态资源复制到static文件夹下
3、将href和<script src =""等各路径指向的静态资源加/static路径
在这里插入图片描述
在这里插入图片描述

4、修改nginx配置文件(这里的share文件夹是因为拷贝的es分词器的应该是docker默认路径)
在这里插入图片描述

缓存与分布式锁

ttl命令查看key剩余的过期时间

会产生数据一致性问题

在这里插入图片描述

redisTemplate和Lettuce、Jedis关系
Lettuce、Jedis都是操作redis的底层客户端spring再次封装成redisTemplate
在这里插入图片描述
在这里插入图片描述

所以不管是Lettuce还是Jedis连接redis都是兼容的

高并发下缓存失效问题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本地锁

本地锁在分布式场景下锁不住所有的服务

本地锁synchronized、JUC(Lock),在分布式场景下想要锁住所有的服务必须使用分布式锁
这里this锁对象指向当前的serviceImpl对象分布式场景下每个this都不一样
在这里插入图片描述

问题本地锁压力测试测试结果依然多次查询了数据库锁的时序问题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解决当前锁时序
在这里插入图片描述
当前是在释放锁后存进redis
在这里插入图片描述
真正完整合理的逻辑查数据库和存入缓存应该是一个原子操作也就是在同一把锁内完成否则就会有释放锁的时序问题导致多次查询数据库
在这里插入图片描述
在这里插入图片描述

分布式锁_redis

本地锁在分布式场景下的问题

1、在这里插入图片描述

2、启动多个服务压力测试
gulimall.com->nginx->gateway负载均衡
在这里插入图片描述

在这里插入图片描述

3、现象
在这里插入图片描述
在这里插入图片描述

redis分布式锁

setnx是原子性的

xshell发送命令到全部客户端docker exec -it redis redis-cli进入redis容器的客户端命令行,发送setnx命令
在这里插入图片描述
版本一
在这里插入图片描述
在这里插入图片描述
版本二

如果getDataFromDb出现异常又或者服务掉线导致锁未释放发生死锁
在这里插入图片描述
设置过期时间
又为了防止在获取到锁和设置过期时间之间发生宕机使用setnx ex原子性操作
在这里插入图片描述
在这里插入图片描述

版本三
在这里插入图片描述

在这里插入图片描述
版本四

如果由于业务时间很长锁自己过期了我们直接删除有可能把别人正在持有的锁删除了
解决 占锁的时候值指定为uuid每个人匹配是自己 的锁才删除。
在这里插入图片描述

在这里插入图片描述

版本五

1、如果正好判断是当前值正要删除锁的时候锁已经过期(网络延时) 别人已经设置到了新的值。那么我们删除的是别人的锁
解决 删除锁必须保证原子性。使用redis+Lua脚本完成

在这里插入图片描述
在这里插入图片描述

redis分布式锁两个核心
1、加锁保证原子性
2、解锁保证原子性
3、key过期时间放长一点

分布式锁_redisson

在这里插入图片描述

文档https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95

可重入锁:a、b方法都加锁加的是一样的锁a获取到的锁b可以用也就等于b方法直接执行
不可重入锁a、b方法都加锁加的一样的锁b需要等a释放锁才可以执行导致死锁

读写锁

读锁要等写锁释放才可以读取数据写锁要排队读锁不用排队

读 + 读 相当于无锁并发读只会在Redis中记录好所有当前的读锁。他们都会同时加锁成功
写 + 读 必须等待写锁释放
写 + 写 阻塞方式
读 + 写 有读锁。写也需要等待

闭锁

相当于juc中的CountDownLatch

缓存一致性

缓存保证的是最终一致性不是强一致实时一致

双写模式
在这里插入图片描述
失效模式
在这里插入图片描述
解决方案
在这里插入图片描述

springCache

@EnableConfigurationProperties

@EnableConfigurationProperties的作用是把springboot配置文件中的值与我们的xxxProperties.java的属性进行绑定需要配合@ConfigurationProperties使用 我们这里是获取properties的配置文件数据然后将数据和CacheProperties属性对应

检索服务

搭建页面环境

在这里插入图片描述

1、将html中搜索页index.html复制进gulimall-search的template目录,将./改成/static/search/
在这里插入图片描述
1、导入thymeleaf依赖否则路径访问请求不到index.html页面2、打包指定yml文件否则报错Param ‘serviceName’ is illegal
2、将其他静态资源放进nginx的/mydata/nginx/html/static/search目录
3、hosts文件配置search.gulimall.com映射nginx配置文件配置server_name
在这里插入图片描述
4、在gateway配置search.gulimall.com的host映射
在这里插入图片描述
5、访问http://search.gulimall.com/
在这里插入图片描述

检索服务

1、skuPrice的类型改成double否则range区间过滤有问题

# 创建索引
PUT gulimall_product
{
  "mappings": {
	"properties": {
		"attrs": {
			"properties": {
				"attrId": {
					"type": "long"
				},
				"attrName": {
					"type": "keyword"
				},
				"attrValue": {
					"type": "keyword"
				}
			},
			"type": "nested"
		},
		"brandId": {
			"type": "long"
		},
		"brandImg": {
			"type": "keyword"
		},
		"brandName": {
			"type": "keyword"
		},
		"catalogId": {
			"type": "long"
		},
		"catalogName": {
			"type": "keyword"
		},
		"catelogId": {
			"type": "long"
		},
		"catelogName": {
			"type": "keyword"
		},
		"hasStock": {
			"type": "boolean"
		},
		"hosStock": {
			"type": "boolean"
		},
		"hotScore": {
			"type": "long"
		},
		"saleCount": {
			"type": "long"
		},
		"skuId": {
			"type": "long"
		},
		"skuImg": {
			"type": "keyword"
		},
		"skuPrice": {
			"type": "keyword"
		},
		"skuTitle": {
			"type": "text"
		},
		"spuId": {
			"type": "long"
		}
	}
  }
}
#检索服务
#模糊匹配、复合类型字段查询
#过滤按照属性、分类、品牌、价格区间、库存
#排序、分页、高亮
#聚合分析
GET /gulimall_product/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "skuTitle": "华为"
          }
        }
      ],
      "filter": [
        {
          "term": {
            "catalogId": "225"
          }
        },
        {
          "terms": {
            "brandId": [
              "1",
              "2",
              "9"
            ]
          }
        },
        {
          "nested": {
          "path": "attrs",
          "query": {
            "bool": {
              "must": [
                {
                  "term": {
                    "attrs.attrId": {
                      "value": "15"
                    }
                  }
                },
                {
                  "terms": {
                    "attrs.attrValue": [
                      "海思Hisilicon",
                      "以官网信息为准"
                    ]
                  }
                }
              ]
            }
          }
        }
        },
        {
          "term":{
            "hasStock":{
              "value":"true"
            }
          }
        },
        {
          "range":{
            "skuPrice":{
              "gte":0,
              "lte":6000
            }
          }
        }
      ]
    }
  },
  "sort": [
    {
      "skuPrice": {
        "order": "desc"
      }
    }
  ],
  "from": 0,
  "size": 5,
  "highlight": {
    "fields": {
      "skuTitle":{}},
    "pre_tags":"<b style='color:red'>",
    "post_tags":"</b>"
  }
}

异步&线程池

面试 一个线程池 core 7 max 20 queue50100 并发进来怎么分配的
先有 7 个能直接得到执行接下来 50 个进入队列排队在多开 13 个继续执行。现在 70 个 被安排上了。剩下 30 个默认拒绝策略。

初始化线程的 4 种方式

1、初始化线程的 4 种方式
 1、继承 Thread
 2、实现 Runnable 接口
 3、实现 Callable 接口 + FutureTask 可以拿到返回结果可以处理异常
 4、线程池 给线程池直接提交任务
区别
 1、2不能得到返回值3可以获取返回值
 1、2、3都不可以控制资源
 4可以控制资源系统稳定无论面对多高的并发不会耗尽资源让系统崩溃

线程池七大参数

  1. corePoolSize:核心线程数【一直存在除非设置了allowCoreThreadTimeOut】线程池创建好以后就准备就绪的线程数量就等待来接受异步任务去执行
  2. maximumPoolSize最大线程数量控制资源
  3. keepAliveTime存活时间。如果当前正在运行的线程数量大于core数量释放空闲的线程。只要线程空闲大于指定的keepAliveTime
  4. unit:时间单位
  5. BlockingQueue<Runnable> workQueue:阻塞队列。如果任务有很多就会将目前多的任务放在队列里面。只要有线程空闲就会去队列里面去除新的任务继续执行
  6. threadFactory线程的创建工厂
  7. RejectedExecutionHandler handler如果队列满了按照我们指定的拒绝策略拒绝执行任务

工作顺序

1、线程池创建准备好 core 数量的核心线程准备接受任务
2、新的任务进来用 core 准备好的空闲线程执行。
  (1) 、core 满了就将再进来的任务放入阻塞队列中。空闲的 core 就会自己去阻塞队 列获取任务执行
  (2) 、阻塞队列满了就直接开新线程执行最大只能开到 max 指定的数量
  (3) 、max 都执行好了。Max-core 数量空闲的线程会在 keepAliveTime 指定的时间后自 动销毁。最终保持到 core 大小
  (4) 、如果线程数开到了 max 的数量还有新任务进来就会使用 reject 指定的拒绝策 略进行处理
3、所有的线程创建都是由指定的 factory 创建的。

拒绝策略

在这里插入图片描述
1、丢弃队列中最老的任务
2、直接拒绝新来的任务会抛异常
3、直接调用run方法异步变同步
4、直接拒绝不抛异常

常见的 4 种线程池

在这里插入图片描述
在这里插入图片描述
1、core是0所有都可回收
2、固定大小core=max,所有都不可回收
3、定时任务的线程池
4、单线程池后台从队列里面获取任务挨个执行

CompletableFuture 异步编排

1、2、3可以并发查4、5、6可以并发查4、5、6依赖1返回的spuId
在这里插入图片描述

商品详情

1、配置hosts的item.gulimall.comnginx的路由gateway网关nginx之前配置过*.gulimall.com所以不用再配置了
2、将详情的静态资源文件传到nginx的html/item目录下
3、修改html访问路径访问http://item.gulimall.com/

自定义配置线程池

异步查询商品详情

认证服务

配置auth.gulimall.com,nginx不用配置将登陆、注册页面的静态资源文件复制进reg、login文件夹下

在这里插入图片描述
jsr303校验

1、实体类加限制
2、加@Valid注解
3、BindingResult result接收错误
在这里插入图片描述
在这里插入图片描述

OAuth2.0协议

OAuth2.0对于用户相关的 OpenAPI例如获取用户信息动态同步照片日志分 享等为了保护用户数据的安全和隐私第三方网站访问用户数据前都需要显式的向 用户征求授权。

OAuth2.0对于用户相关的 OpenAPI例如获取用户信息动态同步照片日志分 享等为了保护用户数据的安全和隐私第三方网站访问用户数据前都需要显式的向 用户征求授权。

微博登录

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

分布式session

1、导入依赖
2、yml文件配置
3、@EnableRedisHttpSession
在这里插入图片描述
在这里插入图片描述
问题
1、不能跨不同域名共享
2、同一个服务复制多份session不同步问题
3、不同服务session不能共享问题

1、session存到redis
2、解决子域session共享问题
3、使用json序列化的方式来序列化对象到redis
在这里插入图片描述
需要在gulimall域名下也可以访问
在这里插入图片描述

jdk默认的序列化方式存储到redis
在这里插入图片描述
json序列化的方式
在这里插入图片描述

单点登录

不用使用springSession域名放大
在这里插入图片描述

购物车

在这里插入图片描述

ThreadLocal

每个线程互不干扰
在这里插入图片描述

消息队列

消息中间件应用场景
1、异步处理
2、应用解耦B服务修改接口A调用B也就需要修改接口
3、流量控制
在这里插入图片描述
在这里插入图片描述

RabbitMQ概念
在这里插入图片描述

Docker安装RabbitMQ

docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:management
docker update rabbitmq --restart=always

在这里插入图片描述
Exchange 类型
在这里插入图片描述
在这里插入图片描述

修改rabbitmq消息序列化方式

发送消息,如果发送的消息是个对象会使用序列化机制将对象写出去对象必须实现Serializable接口
如果要修改为json分析RabbitAutoConfiguration的RabbitTemplate的bean对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

RabbitMQ测试

参数可以写以下类型
1、Message message原生消息详情信息。头+体
2、T<发送的消息的类型> OrderReturnReasonEntity content
3、Channel chanel:当前传输数据的通道
Queue:可以很多人都来监听。只要收到消息队列删除消息而且只能有一个收到此消息
场景
1):订单服务启动多个集群场景同一个消息只能有一个客户端收到
2):只有一个消息完全处理完方法运行结束我们就可以接收到下一个消息

监听消息使用@RabbitListener; 主启动类必须有@EnableRabbit
@RabbitListener 类+方法上监听哪些队列即可
@RabbitHandler: 标在方法上(重载区分不同的消息)

RabbitMQ消息确认机制-可靠抵达

在这里插入图片描述
消息确认机制_发送端确认
在这里插入图片描述

两个回调分别表示
confirm回调消息抵达Broker
return回调只要消息没有投递给指定的队列就触发这个失败回调比如把routingkey写错
在这里插入图片描述

消费端确认(保证每个消息都被正确消费此时才可以broker删除这个消息)

在这里插入图片描述

订单服务

整合环境
1、复制订单html进order模块拷贝静态资源进nginx
2、配置网关

feign远程调用丢失请求头问题

在这里插入图片描述

在这里插入图片描述

feign异步调用丢失请求头问题

在这里插入图片描述
在这里插入图片描述

提交订单的幂等性处理

在这里插入图片描述
幂等解决方案
1、token 机制
Token 获取、比较和删除必须是原子性
2、各种锁机制
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本地事务&分布式事务

在这里插入图片描述

本地事务

>数据库事务的几个特性原子性(Atomicity )、一致性( Consistency )、隔离性或独立性( Isolation) 和持久性(Durabilily)简称就是 ACID
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

springboot中的事务的坑
a方法中直接调用b、c方法使用的事务配置和a保持一致
如果要使用b、c方法自己的事务配置需要bService.b(),cService.c()
在这里插入图片描述
在这里插入图片描述
本地事务失效问题
同一个对象内事务方法互调默认失效原因是绕过了代理对象事务使用代理对象来控制的
解决使用代理对象来调用事务方法
1、引入aop-starter(因为此依赖引入了aspectj依赖

<dependency>
     <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2、@EnableAspectJAutoProxy(exposeProxy = true)
//开启aspectj动态代理功能。以后所有的动态代理都是aspectj创建的即使没有接口也可以创建动态代理对外暴露代理对象。注jdk动态代理必须有接口
3、AopContext.currentProxy()
在这里插入图片描述

分布式事务

在这里插入图片描述

七、RabbitMQ延时队列实现定时任务

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

RabbitMQ使用的是惰性检查机制所以一般是给队列设置过期时间不是给消息设置过期时间

在这里插入图片描述
代码实现
在这里插入图片描述
升级后
在这里插入图片描述
消息队列流程
在这里插入图片描述
在这里插入图片描述

解决在订单释放结束再给库存服务发送消息释放库存
最终一致性方案

在这里插入图片描述

保证消息可靠性

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

支付业务

加密
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

内网穿透

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

秒杀

定时任务

解决定时任务阻塞问题
在这里插入图片描述
使用redisson解决分布式系统的幂等性问题
在这里插入图片描述

在这里插入图片描述
使用redis的信号量模拟库存减少并发场景下与数据库的交互

在这里插入图片描述

高并发场景应对

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我们使用了
1、我们将秒杀单独抽取出来了秒杀服务
2、我们使用随机码只有秒杀时间到了才能收到随机码
3、我们使用定时任务将秒杀的商品存进了redis库存信息使用redisson分布式信号量控制只有抢到了信号量才会去数据库
4、nginx动静分离
后续再加后四个
5、登陆拦截器没有在网关层去做恶意请求拦截器
6、我们使用队列削峰机制

秒杀

在这里插入图片描述

使用rabbitmq实现流量的削峰而不是每个请求都去调用订单服务

SpringCloud Alibaba-Sentinel

功能熔断、降级、限流
在这里插入图片描述
熔断feign调用的远程服务出现问题直接返回fallback指定的方法
降级指定时间内指定请求数超过指定时长一段时间内再调用该接口就会触发熔断

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6