1 初识项目

介绍

项目亮点

综合了多种项目的亮点

  • 电商:对接支付平台、优惠券设计、库存超卖问题、秒杀抢购问题、超时订单处理问题
  • 在线学习:视频点播、学习辅助系统、考试评测系统
  • 社交互动:互动问答系统、课程点评系统、通用点赞系统、积分系统、排行榜系统

系统架构

  • 用户端:学习、个人、搜索、交易中心

  • 管理端:课程、用户、学习、交易、营销活动管理

  • 支撑平台

    • 基础服务:数据字典、角色管理、权限管理
    • 第三方平台:视频点播、文件存储、内容审核、短信发送、三方支付服务

技术架构

  • 展现层 Vue

  • 接入层

    • CDN
    • 反向代理 NGINX
    • 身份认证、请求路由、负载均衡
  • 服务层

    • 微服务组件:Nacos、Seata、Openfeign、sentinel、LoadBalancer、Springcloud
    • 分布式组件:XXL-JOB、redisson、rabbitMq
  • 数据层:es、Redis、MongoDB、MySQL

  • 第三方:阿里云、腾讯云

  • DevOps:文档管理 YAPI、GOGS、持续集成 Jenkins、容器管理 Docker、日志管理 GrayLog、链路追踪 SW

补充:NGINX 与 Gateway 模块

功能区分

在 Spring Cloud 微服务项目中,负载均衡、请求路由和身份认证的功能通常可以由 Spring Cloud GatewayNGINX 共同承担,但它们各自的侧重点不同:

都可以转发请求、引入负载均衡策略
  1. Gateway 请求路由:根据路径、请求头等条件,将请求路由到不同的微服务实例。
  2. NGINX 反向代理和静态资源处理:一方面处理前端页面和静态资源的请求,一方面将请求转发到后端的 Spring Cloud Gateway 或直接转发到微服务实例。

a. NGINX 进行简单的负载均衡:对多个 Gateway 实例或微服务实例进行简单的轮询或 IP Hash 负载均衡。

b. Gateway 配合 Spring Cloud LoadBalancer 或其他组件,实现对不同实例的流量分发。

# 示例(NGINX负载均衡到多个Gateway实例):

upstream gateway {
    server gateway1:8080;
    server gateway2:8080;
}
Spring Cloud Gateway
  • 身份认证和授权:可以集成 OAuth2、JWT 等方式,在请求到达微服务前进行安全校验。
  • 动态路由:可以通过配置中心动态修改路由规则,适应不同的需求。
  • 限流:直接使用 Gateway 自带的 RequestRateLimiter​在配置文件中进行流量数量的限制配置即可,无需引入 Sentinel。
NGINX
  • 请求过滤:可以做简单的黑白名单过滤或 IP 限制。
链路关系梳理

下边以 api.tianji.com/ts/orders/xxxxx​ 请求为例

image

由于在本地 hosts 文件已经配置了域名 api.tianji.com​,所以会转发到对应的 ip 地址 192.168.150.101​,即虚拟机的地址

又因为端口是缺省的 80,所以到了虚拟机里面就是访问 NGINX,NGINX 进行了如下的配置

  1. image
  2. image

所以请求会被代理到 Gateway 微服务模块

而 Gateway 里面又配置了下列路由规则,说明 URL /ts/**​ 会被负载均衡地路由到名称为 trade-service 的模块

image

而 tj-trade 项目配置文件里的项目名称就是 trade-service

image

由 URL 看得出来这种请求是 restful 风格的,看得出来订单资源后面的一串数字是订单 id,所以接下来去找 orders 相关的控制器

最终就找到了请求入口

  • image

综上所述,请求经过了 本地 DNS 文件、虚拟机 NGINX、Springcloud-Gateway 模块,最终抵达 tj-trade 模块的 OrderController 的 deleteOrder() 接口

NGINX 将请求转发给网关微服务模块网关微服务将请求转发到具体的微服务

项目环境搭建

企业开发模式

本地部署、编码方面

  • 本地只运行正在开发的微服务

  • 对于 clone 下来的项目

    • Master 分支是完整的项目代码,==lesson-init 是上课要渐渐开发的分支==

    • ==开发时需要使用 dev 分支==

      • 后续在开发功能的时候,还会在 dev 基础上==创建其他分支==,一个功能就创建一个新的分支,然后合并到 dev,最后进行部署
  • 对于 bootstrap 的多环境配置文件启动模块的 Application 的时候,不要直接右键 run,因为每个模块的 resource 下面都有不同环境的 yaml 配置文件

    • 原因:由于 bootstrap.yaml 文件的配置,在默认情况下,微服务启用的是 bootstrap-dev.yaml 配置

      image

    • 说明:本项目 -dev 和-local 文件的唯一区别是 ip 地址,-dev 是虚拟机的地址,-local 是本机的地址

    • 如果要在本地运行,需要在 idea 的服务的配置里设置 profile 为 local:【在这里配的会比配置文件的优先级要高,所以就不用修改配置文件了】

  • 当本地项目和远程容器里的项目同时运行时,因为两个都是注册到虚拟机上的 Nacos,所以 Nacos 里同一个服务有两个实例

    • 如果想要本地正在开发的项目不被别人访问到,但是又可以调用其他的服务,可以在配置成为 Nacos 的服务调用者的同时让自己不要注册要 Nacos 上,即将 register-enabled​ 配置为 false

      image

调试方面

远程调试:用户在页面发起的请求还是到虚拟机的容器里,但虚拟机和本机都配置好了,请求会跳转到本机的 idea 的源码上

本地调试:通过在 Nacos 里将虚拟机的服务下线或者权重设置为 0,让用户页面发起请求后,到 Nacos 里只能获取并访问本地的服务实例

远程调试

==由于交易服务属于开发环境已经部署的服务,我们无法在本地调试(也不建议在本地调试,因为环境不一样),这在今后的开发中会经常碰到。遇到这样的情况我们就需要利用 IDEA 提供的远程调试功能。==

其实很简单,idea 已经给我们准备好了这样的功能,我们只要做一些简单的配置、再把在 idea 里配置的一串参数放到远程服务启动的参数里,然后就可以进行远程联调了

ps:要求本地和远程的代码一致

服务器端(远程机器)

本项目是基于 Jenkins 来部署的,因此是需要修改 Jenkins 部署脚本。

具体细节如下。

在 Jenkins 部署 tj-trade-debug​ 的任务里配置 构建步骤 —— 执行shell​:

image

java ....xx.jar​ 的一串参数被配置在了 启动脚本 startup.sh​ 里,启动脚本如下:

image

image

本地端(IDEA 或 Eclipse 配置)
  1. 打开 IDEA,点击 Run -> Edit Configurations​。

  2. 点击 +​,添加一个新的启动项,选择 Remote JVM Debug​。

  3. 配置远程调试参数:

    • image

    • Host:远程服务器的 IP 地址。

    • Port:5005(远程 Java 进程监听的调试端口)。

    • Command Line Arguments for remote JVM:显示的命令和上面在服务器端执行的启动命令一致,即远程微服务启动命令为:java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 xx.jar

      这个命令用于远程调试 Java 应用程序,启动一个 Java 应用并开启 Java Debug Wire Protocol (JDWP) 调试接口。

      • java -jar​:以 jar 包形式运行 Java 程序。
      • xx.jar​:目标 Java 应用的 jar 文件名。
      • -agentlib:jdwp​:启用 JDWP,允许远程调试。
      • transport=dt_socket​:使用 socket 通信方式进行调试。
      • server=y​:将 JVM 作为调试服务器(监听调试请求)。
      • suspend=n​:JVM 启动时不挂起,直接运行,调试器可以随时连接。
      • address=*:5005​:监听在 5005 端口,*​表示监听所有 IP 地址,可以远程连接。
  4. 点击 Apply​,然后点击 Debug​,IDEA 会尝试连接远程服务器进行调试。

    此时启动的不是本机的 tj-trade,而是远程的 代理

  5. 在代码中打断点,访问页面发起请求,触发远程代码执行后,调试器会自动停在断点处。

本地调试

测试方面

(本地)接口 / 单元 测试

因为项目中全部都配置了 swagger 的注解,所以可以通过 swagger 来测试所有的接口。

下面以测试 “删除订单” 接口为例。

  1. 在本地启动 tj-trade 项目,访问 swagger 页面 http://192.168.150.101:8088/doc.html

    其中 8088​ 是 tj-trade 的端口

  2. 文档管理 - 全局参数设置​ 里添加一个 请求头类型的参数 user-info

    因为 删除订单时需要对登录用户做校验,因此需要先设置用户 id 的全局参数【具体细节看源码的登录用户的信息是如何传递的

  3. 删除订单接口 - 调试 - 请求参数 - id​ 里添加 订单 id

用户 id 和 订单 id 得是 订单数据库里面的一条记录里配对的两个值!所以得通过数据库找到一对匹配的值进行测试才可以。

组件测试

将本地的微服务注册到 nacos 上去,把虚拟机里的服务停掉,从而让本地服务和其他服务进行联调

把虚拟机里的服务停掉的办法:

  • 关停虚拟机中启动的交易服务:虚拟机里 docker stop tj-trade
  • 在 Nacos 中将虚拟机中启动的交易服务权重设置为 0
  • 在 Nacos 中将虚拟机中的服务下线

可以通过网页前端发起请求,也可以用公司提供的公共服务器上的 Mock 服务

部署联调
  1. 将本地代码 push 到 gogs 的==对应分支==上,让 gogs 上的钩子触发 Jenkins 对执行 tjxt-dev-build 任务:将 tjxt 项目从 gogs 上==**对应分支**==上拉取最新代码,进行编译、构建

    编译、构建:具体脚本执行时是将项目从 gogs 上拉取下来,进行编译、打包

  2. 在 Jenkins 里手动点击部署修改了需要重新部署的微服务模块

    部署:具体脚本执行时是 “构建 docker 镜像” + “ docker run 部署” ==【部署完之后 Nacos 会有对应服务】==

虽然在 Jenkins 的每个任务条目点击后方的 执行按钮都显示的是 “立即构建”,但其实对不同的任务又可以细分为 编译、构建、部署

补充:对 Jenkins 钩子 ==对应分支== 的配置

默认情况下,不加这个过滤器就意味着任何人只要推送代码到私服,都会触发这个构建,但事实上我们只要对 dev 分支的变化做构建,所以添加过滤器

image

此外,构建得基于特定的分支做构建,所以指定分支

远程部署方面【持续集成】

微服务手动部署比较麻烦而且容易出错,所以企业中都会采用持续集成的方式,==快捷实现开发、部署一条龙服务。==

==为了模拟真实环境,在虚拟机中已经提供了一套持续集成的开发环境,==代码一旦自测完成,push 到 Git 私服后即可自动编译、构建。

这个环境核心的角色有三个:Jenkins、gogs、docker

  • gogs:存代码的私服,在 GUI 界面配置了钩子,当代码被 push 上来的时候会通知 Jenkins 进行部署
  • Jenkins:从私服上拉取代码、进行部署【代码的编译、构建、打包,打包成 docker 的镜像】,是整个一条龙服务的核心
  • docker:构建镜像,让部署很简单

熟悉项目

项目结构

  • 本项目是:项目创建一个 Project,项目下的每一个微服务都是一个 Module,方便管理

  • 绝大多数服务都是 常规的 结构:src、pom.xml

  • tj-auth 模块比较特殊,它要提供一些工具包 SDK 给其他模块用于身份校验

    • image
  • 微服务 module​ 中如果有对外暴露的 Feign 接口,需要定义到 tj-api​ 模块中

实体类规范

  • DTO:数据传输对象,在客户端与服务端间、服务端与服务端间传递数据,例如微服务之间的请求参数和返回值、前端提交的表单
  • PO:持久层对象,与数据库表一一对应,作为查询数据库时的返回值
  • VO:视图对象,返回给前端用于封装页面展示的数据
  • QUERY:查询对象,一般是用于封装复杂查询条件

本项目里面都定义在 domain 包下【只是本项目的规范】

依赖注入

  • 对于 final 类型的字段和 标注了 @NonNull​ 注解的字段,用 lombok 提供的 @RequiredArgsConstructor​ 来自动生成构造函数,用于构造器注入
  • 对于其他的,仍然用 @Autowired 等方式注入

异常处理

  • 全局异常处理器的使用,主要涉及到两个注解:

    • @RestControllerAdvice // 表示当前类为全局异常处理器,专门捕获@RestController层抛出的异常。
    • @ExceptionHandler // 指定可以捕获哪种类型的异常进行处理
  • 本项目的全局异常处理器位于 tj-common 的 autoconfigure.mvc.advice​ 包下

  • 标注了 @RestControllerAdvice​ 的类 CommonExceptionAdvice​ 下有很多标注了 @ExceptionHandler​ 的异常处理方法、和一个响应处理的 processResponse​方法

    • image
    • image

其他

  • Linux 操作别名

  • ps -ef | grep nginx 命令【可以看到 nginx 装到哪】

    • image
  • docker ps -a 输出详解

    • 多端口映射
  • Nacos 配置管理:共享的配置、动态的配置

  • 项目是分模块开发的,除了公共模块,其余都是可以运行的

  • 进入 docker 容器的命令参数详解

  • 删除容器 docker rm​ 不等于 删除镜像 docker rmi​,不可以删除正在运行的容器,除非先停掉容器或者用 -f 强制删除

  • maven 的聚合和集成

  • maven 的三套生命周期

  • 每个模块都配置了 swagger,要访问某个模块的 swagger 页面,访问 192.168.150.101:xxxx/doc.html​​​ 即可,xxxx 是该模块对应的端口

    • 除此之外,网关还做了微服务的聚合,即我们既可以通过上面每个端口去查看微服务的文档,也可以在网关查看所有微服务的文档。

    • Gateway 模块的端口是 10010:

      image

    同样一个接口,在网关 swagger 进行测试和在 单独模块 swagger 进行测试的返回不一样

    • 网关 swagger 的返回面向前端
    • 单独模块 swagger 返回的是服务间进行交互的数据
    • image
  • 删除订单得用逻辑删除【可以用 @TableLogic 自动完成】

  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    143 引用 • 442 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...