电商项目构建

1.概念

1.1.集群与分布式

集群是物理形态,即一堆机器就可以叫做集群,不管是不是一起协作干活
分布式是工作方式,是若干独立计算机的集合,这些计算机对用户来说就像单个相关系统
分布式中每一个节点(集群中的一台服务器)都可以做集群,而集群不一定是分布式的(比如共同提供一个业务的系统中的集群不是,而整个分布式系统则是分布式的)

1.2.服务熔断

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

1.3.服务降级

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

1.4.API网关

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

2.Docker使用

安装:菜鸟教程-Docker安装
启动Docker:sudo systemctl start docker
Docker开机自启动:sudo systemctl enable docker
查看所有镜像:sudo docker images
配置阿里云镜像加速:阿里云镜像加速器地址
下载MySql:sudo docker pull mysql:版本
启动实例:docker run -p 主机端口:容器端口 --name 容器名 -v 主机配置文件夹:/etc/mysql/conf.d -v 主机日志文件夹:/var/log/mysql -v 主机配置文件夹:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d 镜像名,MYSQL_ROOT_PASSWORD代表初始化root用户的密码,其中-d代表后台运行,如: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.d:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root -d mysql
查看启动中的容器:docker ps
进入docker容器:docker exec -it 容器名 /bin/bash

2.1.redis安装

下载Redis:docker pull redis
启动Redis实例:docker run --name redis -v 主机目录:/data -v 主机目录:/etc/redis/redis.conf -d redis redis-server /etc/redus/redis.conf,其中redis-server /etc/redus/redis.conf表示依照此文件配置启动,注意容器内默认是没有redis.conf的,因此需要先在主机目录中创建好redis.conf,再去映射
如:docker run -p 6379:6379 --name redis -v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf -v /mydata/redis/data:/data -d redis redis-server /etc/redis/redis.conf
进入redis使用redis-cli:docker exec -it 容器名 redis-cli
最新redis默认已经是持久化的
也可以在配置文件中进行配置:appendonly yes //启用AOF持久化方式
之后重启redis:docker rerstart redis
容器开机启动:sudo docker update 容器名 --restart=always

2.2.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

使用15672端口即可访问rabbitmq管理界面,默认账户密码:guest

3.Git使用

在git bash中操作:

  • 配置作者信息:
    • git config --global user.name 名称
    • git config --global user.email 邮箱
  • ssh免密连接:ssh-keygen -t rsa -C "xxx@xxx.com"
  • 查看公钥内容:cat ~/.ssh/id_rsa.pub
    并将打印出的内容放在码云上,使用ssh -T git@gitee.com测试是否成功

4.创建项目微服务

创建项目模块时都引入Web与OpenFeign


在父工程下新建多个SpringBoot模块,并配置父工程pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.kanariya</groupId>
    <artifactId>mail</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mail</name>
    <description>聚合服务</description>
    <packaging>pom</packaging>
    <modules>
        <module>mail-coupon</module>
        <module>mail-ware</module>
        <module>mail-member</module>
        <module>mail-product</module>
        <module>mail-order</module>
    </modules>
</project>


为方便提交到码云,idea可以安装插件gitee

可以创建一个common模块,让所有子模块继承该模块,可以在该模块中编写通用类并导入相关依赖,相当于对子模块的依赖进行导入
导入依赖:

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>

配置数据源:(application.yml)

spring:
  datasource:
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.88.132:3306/mail_pms?characterEncoding=UTF8&serverTimezone=UTC

配置MyBatis-Plus:
(1)使用@MapperScan
(2)告诉MyBatis-Plus,sql映射文件位置(application.yml)并设置主键自增

mybatis-plus:
  mapper-locations: "classpath*:/mapper/**/*.xml"
  global-config:
    db-config:
      # 设置主键自增
      id-type: auto

利用renren-fast修改generator.properties即可修改生成配置,同时需要在application.yml中修改数据库配置信息

5.SpringCloud技术搭配方案

SpringCloudAlibaba - github
(1)Nacos(SpringCloud Alibaba):注册中心 + 配置中心
(2)Ribbon:负载均衡
(3)Feign:声明式HTTP客户端(调用远程服务)
(4)Sentinel(SpringCloud Alibaba):服务容错(限流、降级、熔断)
(5)Gateway:API网关(Webflux编程模式)
(6)Sleuth:调用链监控
(7)Seata(SpringCloud Alibaba):原Fescar,即分布式事务解决方案
设置SpringCloudAlibaba依赖管理:(pom.xml)

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2021.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

6.Nacos使用(服务发现)

引入依赖:

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

安装nacos-server
nacos默认账号密码:nacos/nacos
在application.yml中配置Nacos Server地址

spring:
  # 配置Nacos Server地址
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  # 配置服务名称
  application:
    name: coupon

使用@EnableDiscoveryClient开启服务注册与发现功能

@EnableDiscoveryClient
@MapperScan("com.kanariya.mailcoupon.coupon.dao")
@SpringBootApplication
public class MailCouponApplication {
    public static void main(String[] args) {
        SpringApplication.run(MailCouponApplication.class, args);
    }
}

7.Nacos使用(配置中心)

nacos配置中心官方说明
导入依赖:

 <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
 </dependency>
  <!--注意2.4版本SpringBoot必须加载bootstrap,否则无法读取nacos配置文件-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-bootstrap</artifactId>
     <version>3.0.3</version>
 </dependency>

创建bootstrap.properties文件进行配置(该文件优先于application.properties加载)

# 服务名
spring.application.name=coupon      
#可以在此处修改nacos上的配置命名空间,默认就为public命名空间ID
spring.cloud.nacos.config.namespace=public命名空间ID
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

可以使用@Value注解获取配置信息,优先使用nacos上的配置信息

同时要在nacos上创建配置文件:(文件名为${prefix}-${spring.profile.active}.${file-extension},prefix 默认为 spring.application.name 的值,spring.profile.active 即为当前环境对应的 profile,当 spring.profile.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension},file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置)

如果希望在项目运行时修改配置文件并使修改内容能够立即生效,需要在注入值的类(比如在Controller类内使用@Value引入nacos上配置的值,则此注解直接加在Controller类上)上加上@RefreshScope注解

8.Feign远程调用

Feign是一个声明式的HTTP客户端,它的目的就是让远程调用更加简单,Feign提供HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息
Feign整合了Ribbon(负载均衡)和Hystrix(服务熔断),可以不再显示调用两个组件
SpringCloudFeign在NetflixFeign的基础上扩展对SpringMVC注解的支持,在其实现下,只需要创建一个接口并用注解的方式进行配置,即可完成对服务提供方的接口绑定,简化SpringCloudRibbon自行封装服务调用客户端的开发量
想要远程调用其他服务的步骤:
(1)引入openFeign

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

(2)编写一个接口,告诉SpringCloud这个接口需要调用远程服务,可以将远程服务放在feign包下,便于区分

声明接口的每一个方法都是调用哪个远程服务的哪个请求

// 填写的是注册的服务名(即要调用的服务中application.yml内application.name的值)
@FeignClient("coupon")
public interface CouponFeignService {
    /*要调用服务的方法签名*/
    @RequestMapping("/coupon/coupon/member/list")
    public R memberConpons();
}

(3)开启远程调用功能

// 开启远程调用功能,basePackages指明要进行远程调用的包,此注解放在主动调用接口的服务的启动类上,比如member服务调用coupon服务,则@EnableFeignClient放在member的启动类上
@EnableFeignClients(basePackages = "com.kanariya.mailmember.member.feign")
@EnableDiscoveryClient
@MapperScan("com.kanariya.mailmember.member.dao")
@SpringBootApplication
public class MailMemberApplication {
    public static void main(String[] args) {
        SpringApplication.run(MailMemberApplication.class, args);
    }
}

之后通过注入Feign类直接调用即可

9.核心概念

(1)命名空间:进行配置隔离,不同的命名空间下,可以存在相同的Group或者Data ID的配置。Namespace的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。nacos中默认新增的所有配置都在public(保留空间)
在nacos中可以通过此项配置修改命名空间:spring.cloud.nacos.config.namespace=public命名空间ID
(2)配置集:一组相关或者不相关的配置项的集合称为配置集,在系统中,一个配置文件通常就是一个配置集,包含系统各个方面的配置。例如,一个配置集可能包含数据源、线程池、日志级别等配置项
(3)配置ID:类似文件名。如Nacos中DATA ID
(4)配置分组:默认所有的配置集都属于DEFAULT_GROUP
推荐为每个微服务创建一个命名空间,使用配置分组区分运行环境
可以使用下面的方式配置分组:spring.cloud.nacos.config.group=prop
注:可以通过以下方式引用多配置集:

# 服务名
spring.application.name=coupon      
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=coupon
# 默认读取prod分组
spring.cloud.nacos.config.group=prop
spring.cloud.nacos.config.extension-configs[0].data-id=mybatis.yml
spring.cloud.nacos.config.extension-configs[0].group=dev
# 动态刷新(默认false)
spring.cloud.nacos.config.extension-configs[0].refresh=true
spring.cloud.nacos.config.extension-configs[1].data-id=other.yml
spring.cloud.nacos.config.extension-configs[1].group=dev
# 动态刷新(默认false)
spring.cloud.nacos.config.extension-configs[1].refresh=true

微服务任何配置信息,任何配置文件均可以放在配置中心,只需要在bootstrap.properties中说明加载配置中心中哪些配置文件即可
以前SpringBoot任何方法从配置文件中获取值的方法,都能使用,如@Value、@ConfigurationProperties
配置中心所有的配置优先使用

10.Gateway网关

网关作为流量的入口,常用功能包括路由转发、权限校验、限流控制等,而SpringCloud Gateway作为SpringCloud官方推出的第二代网关框架,取代Zuul网关
网关拥有断言(Predicate,用于判定路由进入到哪里,只有断言为true才能够进入相关的服务)、过滤器(Filter,用于对请求、响应进行处理)
步骤:
(1)创建gateway模块,并引入gateway依赖
(2)将网关服务注册到Nacos上
(3)配置网关(通过路由进行配置)
路由配置官方文档

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
        - id: baidu_route
          uri: https://www.baidu.com
          predicates:
            - Query=url,baidu
        - id: qq_route
          uri: https://www.qq.com
          predicates:
            - Query=url,qq

直接访问http://localhost:12000/?url=qq会跳转到www.qq.com网站(12000为修改后的网关服务端口号),如果是http://localhost:12000/hello?url=qq会将/hello也传过去,即实际跳转路径为www.qq.com/hello
注:由于通用模块的存在,gateway会引入mybatis相关组件,可以在此处进行排除:

@EnableDiscoveryClient
// 排除mybatis相关的数据源的类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

11.缓存使用

为提升系统性能,可将部分数据放入缓存中,而数据库承担数据落盘工作
哪些数据适合放入缓存:
(1)即时性、数据一致性要求不高的
(2)访问量大且更新频率不高的数据(读多、写少)
添加redis依赖:

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

配置redis的host等信息:

spring:
  redis:
    host: 192.168.88.132
    port: 6379

使用Spring自动配置好的StringRedisTemplate来操作redis

        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        // 保存
        ops.set("hello", "world" + UUID.randomUUID().toString());
        // 查询
        String hello = ops.get("hello");
        System.out.println("hello");
posted @ 2021-07-24 11:44  kanaliya  阅读(70)  评论(0)    收藏  举报