谷粒商城项目问题、难点与重点总结

相关介绍

基础知识

电商模式

1、B2B 模式
B2B(Business to Business),商家与商家建立的商业联系

2、B2C 模式
B2C(Business to Consumer),商对客模式,也即是商业零售,商家直接面向消费者销售商品和服务

3、C2B 模式
C2B(Customer to Business),消费者对企业,先有消费者需求产生而后有企业生产

4、C2C 模式
C2C(Customer to Customer),客户之间自己把东西放到网上去买

5、O2O 模式
O2O(Online to Offline),将线下商务和互联网结合在一起,让互联网成为线下交易的前台;线上交易、线下服务

项目描述

谷粒商城是一个 B2C 模式的电商平台。项目前后端分离开发,并且分为内网部署和外网部署,外网就是面向公众访问,部署前端项目;内网部署整个后端的服务集群。用户通过客户端完成相应的功能,比如登录、注册等,向后端服务发送请求。

完整的请求流程可以概括如下:

  1. 通过任意客户端请求来到 Nginx 集群,Nginx 把请求转交给后端服务,先将请求服务交给 API 网关,API 网关为 SpringCloud GateWay,网关可以根据当前请求,动态路由到指定的服务,例如要调用商品服务、购物车服务、或者检索服务。
  2. 如果路由过来后,某一个服务有众多服务器实现,网关会负载均衡地调用服务;当服务出现问题,会在网关级别对服务进行统一地熔断或者降级,使用 SpringCloud alibaba 提供的 Sentinel。当然网关还有其他功能,比如认证授权、限制瞬时流量等。
  3. 当请求通过网关到达服务后,进行处理的都是 Spring Boot 的一个个微服务,服务与服务之间会互相调用,如下订单时调用商品服务。有些请求需要登录以后才能处理,所以会有一个基于 OAuth2 的认证中心。

这些服务需要保存一些数据或者使用缓存,缓存是使用 Redis 集群实现的,分片集群加哨兵集群;持久化使用的是 MySQL 集群。服务与服务之间利用消息队列 RabbitMQ 进行异步解耦,完成分布式事务的最终一致性。检索使用 ElasticSearch,服务运行期间存取图片视频等都是利用阿里云对象存储服务。

项目上线后,为了快速定位项目中可能出现的一些问题,使用 ELK 对日志进行处理,用 LogStash 收集业务里面的各种日志,存储到 ES 中,使用 Kibana 从 ES 中检索到日志信息,快速定位线上问题所在。

在分布式系统中,每一个服务都可能部署在一台机器,而且服务与服务之间要相互调用,需要直到彼此在哪里,因此将所有服务注册到服务中心,其他服务可以通过注册中心发现其他服务的注册所在位置,使用 SpringCloud Alibaba Nacos 完成。每一个服务配置众多,后来要集中管理这些配置,实现修改一处配置,其他服务全部修改的效果,使用 SpringCloud Alibaba Nacos 来作为服务的配置中心,所有服务都可以动态地从 Nacos 中获取配置。

服务在调用期间可能出现的问题,比如下订单服务调用商品服务,商品服务调用库存服务,可能某一个链路出现问题,我们要追踪某一个调用链哪里出现问题,该怎么解决等等,使用 SpringCloud Sleuth+Zipkin 把每一个服务的信息交给交给开源的 Prometheus 进行聚合分析,再由 Grafana 进行可视化展示,Altermananger 实时得到服务的报警信息,以邮件和手机短信方式通知。

提供持续继承和持续部署,修改后的代码提交在 GitHub,可以通过通过自动化工具 Jenkins Pipeline,从 GitHub 获取代码,将它打包成 Docker 镜像,最后通过 Kuberneters 集成整个 Docker 服务,将服务以 Docker 容器的方式运行。

分布式基础

分布式

分布式的特点:

  • 分布性:地域分散,系统的功能分散在不同的节点上,具有数据处理的分布性
  • 自治性:节点各自既能自治地进行工作,又能协调任务处理
  • 并行性:一个大的任务可以划分为若干个子任务,分别在不同的主机上执行
  • 全局性:全局的通信机制,能互相通信,不区分本地和远程;还应当有全局的保护机制
微服务

单体式架构
项目源码归于一处,项目迭代不灵活、项目组职责和权限不清、项目并发配置不灵活、项目部署扩展困难

单体式架构

微服务架构
将项目拆分为几个独立的功能单元的架构,项目复杂度降低、团队界限明确、部署灵活
微服务架构

如何选择:

架构选型

微服务架构风格,像是把一个单独的应用程序开发为一套小服务,每个小服务运行在自己的进程中,并使用轻量级机制通信,通常是 HTTP API。这些服务围绕业务能力来构建,并通过完全自动化部署机制来独立部署;这些服务使用不同的编程语言书写,以及不同数据存储技术,并保持最低限度的集中式管理。

微服务架构图

谷粒商城微服务架构图

分布式与微服务

分布式——是系统部署方式

  • 服务是分散部署在不同的机器上的
  • 且各自分开部署的部分彼此通过各种通信协议交互信息
  • 分开部署的应用不一定是微服务架构,例如,“集群”

微服务——是架构设计方式

  • 微小的服务,只应对一个单一的功能,只做一件事
  • 这个服务可以单独部署运行
  • 服务之间互相交互
集群、分布式、节点

集群是物理形态,指的是将多台服务器集中在一起,实现同一业务;分布式是工作方式,指的是将不同的业务分布在不同的地方。分布式中的每一个节点都可以做集群;而集群中的节点指的是一台服务器。

在分布式系统中,各个服务器可能处于不同主机,但是服务之间不可避免地需要互相调用,称为远程调用。

在 SpringCloud 中使用 HTTP+JSON 的方式完成远程调用

远程调用

分布式系统中,A 服务需要调用 B 服务,B 服务在多台机器中都存在,A 调用任意一个服务器中均可完成功能;为了避免每一个服务器都不要太忙或者太闲,可以负载均衡地调用每一个服务器,提升网站的健壮性。

常见的负载均衡算法:

  • 轮询: 为第一个请求选择健康池中的第一个后端服务器,然后按照顺序往后依次选择,直到最后一个,然后循环
  • 最小链接: 优先选择链接数最少,压力最小的后端服务器,在会话较长的情况下可以考虑这种模式
  • 散列: 根据请求源的 IP 的散列(hash)来选择要转发的服务器;可以在一定程度上保证特定用户能连接到相同的服务器;如果应用需要处理状态而要求用户能够连接到和之前相同的服务器,可以考虑

负载均衡

当服务 A 调用服务 B 时,并不知道 B 服务处于那几台服务器上以及那些服务器上面是正常运行的,那些服务是已经下线的。为了实现在某些服务下线时,其他服务可以实时感知到服务的下线,避免调用不可用的服务,可以使用注册中心。

服务注册、发现中心

每一个服务最终都有大量的配置, 并且每个服务都可能部署在多台机器上。 我们经常需要变更配置, 我们可以让每个服务在配置中心获取自己的配置;通过配置中心来集中管理微服务的配置信息

配置中心

服务熔断与服务降级

在微服务框架中,微服务之间通过网络进行通信,存在互相依赖,当其中一个服务不可用时,有可能会造成雪崩效应,必须要有容错机制来防止这种情况,保护服务

  • 服务熔断:
    设置服务的超时,当被调用的服务经常失败到达某个阈值,可以开启断路保护机制,后来的请求不再去调用这个服务,本地直接返回默认的数据

  • 服务降级:
    在运维期间,当系统处于高峰期,系统资源紧张,我们可以让非核心业务降级运行。降级:某些服务不处理,或者简单处理(抛出异常、返回 NULL、调用 Mock 数据、调用 Fallback 处理逻辑)

API 网关

在微服务架构中,API GateWay 作为整体架构的重要组件,它抽象了微服务中都需要的公共功能,同时提供了客户端负载均衡、服务自动熔断、灰度发布、统一认证、限流流控、日志统计等丰富的功能。

项目设计问题

为什么需要云存储

单体应用部署在一台服务器上,想要做文件上传,浏览器会给项目发送请求,将上传的文件交给他,项目收到某个请求后,将某个文件保存在一个特定的位置下,如果下次还想使用某个文件,还会发请求,将这个文件返回给我们显示。
分布式情况下,一个服务可能回部署多台服务器,第一次负载均衡,文件上传,保存到服务器中;下次请求,可能负载均衡到了其他服务器,而其他服务器是没有这个文件的,可能会出现一些问题。
解决方案是:不论文件发送到哪个服务器,文件上传时都是统一存储在一个文件系统中,不同服务器在同一个地方写,也在同一个地方读,就不会出现自己持有文件,其他服务器读不到的情况。

缓存问题

如果使用本地缓存,缓存与微服务处于同一进程,但是每个微服务都有自己的缓存服务、数据更新时只更新自己的缓存,在分布式环境中可能造成缓存数据不一致;因此,在分布式情况下,微服务共同使用缓存中间件。

  • 缓存穿透:
    缓存穿透是指,用户不断发起请求,去请求缓存和数据库中都没有的数据。这时的用户可能是攻击者,大量请求没有的数据会导致数据库压力过大,压垮数据库。
    解决方案:
    缓存空对象、布隆过滤器、MVC 拦截器

  • 缓存雪崩:
    大量的缓存数据在同一时间集中过期失效,请求全部转发到数据库中,数据库瞬时压力过大雪崩。
    解决方案:

    • 规避雪崩:
      缓存数据的过期时间随机设置,防止同一时间大量数据过期现象发生;
      如果缓存数据库是分布式部署的,将热点数据均匀分布在不同缓存数据库中
    • 出现雪崩:熔断、降级
      事前:尽量保证整个 Redis 集群的高可用,发现机器宕机尽快补上,选择合适的内存淘汰策略
      事中:利用本地缓存+限流降级,避免 MySQL 崩掉
      事后:利用 Redis 持久化机制保存的数据尽快恢复缓存
  • 缓存击穿:
    缓存击穿指的是缓存中没有但是数据库中存在的数据,由于并发用户特别多,同时读缓存又没有读到数据,同时去数据库中取数据,引起数据库压力瞬间增大
    缓存击穿是指并发查同一条数据;缓存雪崩是指并发查多条数据
    解决方案:
    加互斥锁,在缓存失效时(没有从缓存中拿到数据),不是立即去数据库中加载数据,而是先用缓存工具中某些带有成功操作返回值的操作去 set 一个 mutex key,当操作成功返回时,再去数据库中加载并回设到缓存中;否则就去缓存中重试获取数据

接口幂等性问题

幂等性:
订单提交一次和提交多次,其结果是一样的

预防问题:

  • 用户多次点击按钮
  • 用户页面回退再次提交
  • 服务互相调用,由于网络问题,导致请求失败;feign 触发重试机制
  • 其他业务情况

解决方案:

  1. token 机制
    服务端提供了发送 token 的接口,分析那些业务是存在幂等问题的,在执行业务之前,必须先去获取 token ,服务器会把 token 保存到 Redis 中;
    服务器判断 token 是否在 Redis 中,存在表示第一次请求,然后删除 token,继续执行业务;
    需要保证只能有一个去 Redis 中查看,否则可能会导致删除两次

  2. 各种锁机制

  3. 各种唯一性约束
    数据库唯一性约束、Redis 防重

  4. 全局请求唯一 id
    调用接口时,生成一个唯一 id,Redis 将数据保存到集合中去重,存在即处理过,可以使用 nginx 设置每一个请求的唯一 id

问题

OpenFeign报错

问题:

使用 Spring Initializr 初始化项目引入了 openfeign,运行项目时出现了下面这个错误
SpringCloud OpenFeign 报错:No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?

分析:

原因一:

由于SpringCloud Feign 在 Hoxton.M2 RELEASED 版本之后不再使用 Ribbon 而是使用 spring-cloud-loadbalancer,所以不引入 spring-cloud-loadbalancer 会报错

解决问题需要加入 spring-cloud-loadbalancer 依赖,并且在 nacos 中排除 ribbon 依赖,不然 loadbalancer 无效

//我是在这引入了spring-cloud-starter-alibaba-nacos-discovery
<dependency>
    <groupId>com.oyz.gulimall</groupId>
    <artifactId>gulimall-common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>
//加入spring-cloud-loadbalancer依赖

<dependency>
  <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-loadbalancer</artifactId>
    <version>3.0.2</version>
</dependency>
原因二:

SpringCloud 和 SpringBoot 的版本太高,需要降低版本;实际中可以根据官方文档的版本搭配进行设置。

Nacos 配置中心不生效

问题:

启动报错:NacosConfigProperties : create config service error!properties=NacosConfigProperties{serverAddr='null', encode='null', group='DEFAULT_GROUP', prefix='null', fileExtension='properties', timeout=3000, endpoint='null', namespace='null', accessKey='null', secretKey='null', contextPath='null', clusterName='null', name='null', sharedDataids='null', refreshableDataids='null', extConfig=null},e=,

分析:

首先,访问官网确定 nacos 与各组件的版本关系 :https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html

原因一:

虽然已经在 application.properties 中做了如下配置

spring.cloud.nacos.config.server-addr=localhost:8848

但是,使用 Nacos Config 做统一配置管理时,启动 springboot 项目初始化都是使用 bootstrap.properties 配置文件去初始化上下文。将 application.properties 重命名为 bootstrap.properties 问题解决

原因二:

如果还没有解决,则可能是已经做了部分远程配置,但是没有启动 nacos,或者缺乏 bootstrap.yml 文件
编写配置文件 bootstrap.yml

server:
  port: 8008
spring:
  application:
    name: service-statistics
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        file-extension: properties

并设置远程配置参数

远程配置

gateway

启动报错

GateWay 启动报错:Parameter 0 of method loadBalancerWebClientBuilderBeanPostProcessor

解决方法:
添加对应的依赖

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

端口占用

运行 GateWay 模块显示:Web server failed to start. Port 8080 was already in use,一般是因为端口被占用

解决方法:

  1. 打开 CMD 界面运行以下两个命令
    netstat -ano|findstr 8080 // 用于查看端口占用情况
    taskkill /F /pid PID // 关闭进程
  • 15
    点赞
  • 96
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值