springcloud微服务基础--黑马笔记

1.微服务  分布式架构
    特点:单一职责、面向服务、自治、隔离性强
        SpringCloud Dubbo  springCloudAlibaba
    服务拆分:
        ·不要重复开发相同业务
        ·数据库独立
        ·暴露业务接口供其他服务调用
            调用方式:基于RestTemplate发起的http请求实现调用(只知道对方的ip、端口、url、请求参数)

    负载均衡是指将传入的网络流量高效分发到一组后端服务器

    服务调用关系
        服务提供者:暴露接口
        服务消费者:调用接口

    组件
        注册:Eureka、nacos
        负载均衡:Ribbon
        远程调用:feign
        网关:Gateway

2.Eureka  注册
    角色:
        EurekaServer:服务端,注册中心
                      记录服务信息  心跳监控
        EurekaClient:客户端
                      Provider:服务提供者
                                注册自己信息到EurekaServer; 每隔30秒向EurekaServer发送心跳
                      consumer:服务消费者
                                根据服务名称从EurekaServer拉取服务列表; 基于服务列表做负载均衡,选中一个微服务后发起远程调用
    步骤:
        1)搭建EurekaServer
          引入依赖  启动类中加@EnableEurekaServer  配置eureka地址
                spring:
                  application:
                    name: eurekaserver
                eureka:
                  client:
                    service-url:
                      defaultZone: http://127.0.0.1:10086/eureka/
        2)服务注册  服务提供者
          引入依赖  配置地址
        3)服务发现  服务消费者
          引入依赖  配置地址  给RestTemplate添加@LoadBalance  用服务提供者的服务名称远程调用

3. Ribbon
   LoadBalancerInterceptor负载均衡拦截器     RibbonLoadBalancerClient
   ·负载均衡规则:规则接口IRule  默认实现ZoneAvoidanceRule  根据Zone选择服务列表  轮询
   ·负载均衡策略:通过定义IRule实现可以修改负载均衡规则
        1)代码:在服务消费者中定义一个新的IRule
        2)配置文件:ribbon.NFLoadBalancerRuleClassName  无法全局
   ·饥饿加载  项目启动时创建
        ribbon默认是懒加载(第一次方法调用的时候才去初始化LoadBalancer)
        通过配置文件可开启饥饿加载,指定饥饿加载的微服务名称

4.nacos
    ·nacos服务注册或发现
        依赖配置    spring.nacos.server-addr: localhost:8848
    ·服务分级存储模型
        一级:服务  如userservice
        二级:集群  如成都或重庆
            ·服务集群属性    spring.nacos.discovery.cluster-name: CQ # 配置集群名称
            ·根据集群负载均衡  优先寻找与自己同集群的服务,再随机负载均衡
                    userservice: # 配置的服务名
                      ribbon:
                        NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule  # 负载均衡规则
            ·根据权重负载均衡  0-1   权重越高被访问频率越高,为0不会被访问   适合做版本更新
            ·环境隔离--namespace    每个namespace都有唯一id,不同namaspace下的服务不可见
        三级:实例  如重庆机房某台部署了userservice的服务器

    ·Nacos与eureka
        都支持服务注册和拉取,支持提供者心跳方式做健康检测
        Nacos有临时实例(心跳,不正常会被剔除,AP)和非临时实例(主动监测,CP)之分,支持服务列表变更的消息推送模式,更新更及时;eureka采用AP

    ·Nacos配置管理:
        ·统一配置管理
            引入配置客户端依赖   添加bootstrap.yam文件,优先级高于application.yml
        ·自动刷新(热更新)   配置文件变更后,无需重启就可以感知
            1) 在Value注入的变量所在类上添加@RefreshScope
            2) 使用@ConfigurationProperties
        ·多环境配置共享
            从nacos读取的配置文件
                1) [服务名]-[spring.profile.active].yaml  环境配置
                2) [服务名].yaml  默认配置,多环境共享
            优先级:[服务名]-[环境].yaml > [服务名].yaml > 本地配置
        ·集群搭建
            nginx反向代理(用户所有的请求都必须先发送到nginx网关上,再进行请求转发,用户端并不知道真正提供服务的服务器是谁)

5.Feign
  ·步骤:引入依赖 --> 加@EnableFeignClients --> 编写FeignClient接口 --> 远程调用,代替RestTemplate
  ·日志配置:
        级别:NONE BASIC HEADERS FULL
        1)配置文件 feign.client.config.xxx.loggerLevel
                xxx是default代表全局
                xxx是服务名称代表某服务
        2)代码:配置Logger.Level这个bean
                @EnableFeignClients声明代表全局
                @FeignClient代表某服务
  ·优化:
        ·日志级别尽量用basic
        ·使用HttpClient或OKHttp代替URLConnection
                引入feign-httpClient依赖 -->  配置文件开启httpClient功能,设置连接池参数
  ·最佳实践:
        1)让controller和feignClient继承同一接口    缺点:紧耦合
        2)将feignClient、POJO、feign的默认配置都定义到一个项目中,供所有消费者使用   缺点:需要导入全部依赖
                不同包的FeignClient的导入有两种方式
                    ·在@EnableFeignClients注解中添加basePackage,指定FeignClient所在的包
                    ·在@EnableFeignClients注解中添加clients,指定FeignClient的字节码

6.网关--gateway
    ·网关功能:身份认证和权限校验、服务路由、负载均衡、请求限流
    ·gateway搭建:
        1)引入nacos服务发现和gateway依赖
        2)配置application.yml,包括服务基本信息、nacos地址、路由
    ·路由断言工厂  predicates
    ·过滤器 对路由的请求或响应做加工处理
        ·一定要定义顺序:order值越小,优先级越高
        ·执行顺序:defaultFilter(配置,GatewayFilter,所有路由都生效)  >  局部的路由过滤器(配置,GatewayFilter)  >  GlobalFilter全局过滤器(代码,GlobalFilter)
    ·跨域问题:
        跨域:域名不一致就是跨域,包括域名不同或端口不同
        跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
        解决方案:CORS(配置文件)

7.Docker  快速交付应用、运行应用的技术
    ·将程序及其依赖、运行环境一起打包为一个镜像,可以迁移到任意Linux系统;利用沙箱机制形成隔离容器,互不干扰
    ·容器:镜像运行起来就是容器,一个镜像可以运行多个容器
    ·结构:
        服务端:接收命令或远程请求,操作镜像或容器
        客户端:发送命令或请求到Docker服务端
    ·DockerHub:一个镜像托管的服务器,统称DockerRegistry
    ·数据卷: 解决容器与数据耦合的问题(不便于修改、数据不可复用、升级维护困难)
            ·是一个虚拟目录,指向宿主机文件系统中的某个目录
            ·挂载方式: -v 数据卷名 : 目标容器目录
                耦合度低,docker管理,但目录不好找
            ·如果容器运行时数据卷不存在,会自动被创建
    ·目录直接挂载:-v 宿主机文件/目录:容器内文件/目录
                目录容易查看,但耦合度高,需要自己管理

    ·镜像:分层结构
            ·BaseImage层:包含基本的系统函数库、环境变量、文件系统
            ·Entrypoint:入口,镜像中应用启动的命令
            ·其它:在BaseImage基础上添加依赖、安装程序、完成整个应用的安装和配置
    ·自定义镜像  dockerfile
            dockerfile本质是一个文件,通过指令描述镜像的构建过程
    ·dockerCompose  快速部署分布式应用,无需一个个微服务构建镜像和部署
            部署:docker-compose up -d
    ·docker镜像仓库  公有、私有


8.消息队列 MQ
    ·同步通信:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式
             如,你直接问我什么是同步,我马上告诉你这就是同步。
             ·优:时效性强,立即得到结果
             ·缺:耦合度高,性能和吞吐量下降,资源消耗,级联失败问题
    ·异步通信:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。
             如,你用知乎提个问题,什么是异步,然后你就干别的去了;等我看到这条消息,告诉你,这就是异步,之后你又会收到一条消息,知道了这就是异步。
             ·优(broker):耦合度低,吞吐量提升,故障隔离,流量削峰
             ·缺:依赖于broker的可靠性、安全性、吞吐能力;架构复杂,不好追踪管理
    ·MQ 消息队列,存放消息的队列,事件驱动架构中的broker
        RabbitMQ 消息通信中间件
                    channel -- 操作MQ的工具;exchange -- 路由消息倒队列中; queue -- 缓存消息;
                    virtual host-- 虚拟主机,对queue、exchange等资源的逻辑分组
            ·基本消息队列的消息发送:
                    建立connection
                    创建channel
                    利用channel声明队列
                    利用channel向队列发送消息
            ·基本消息队列的消息接收:
                    建立connection
                    创建channel
                    利用channel声明队列
                    定义consumer的消费行为handleDelivery()
                    利用channel将消费者与队列绑定

        SpringAMQP  应用间消息通信的一种协议,便于消息发送和接收
            1.基本消息的发送与接收
                ·发送消息:
                    引入ampq的依赖
                    配置RabbitMQ的地址
                    利用RabbitTemplate的convertAndSend方法
                ·接收消息
                    引入ampq的依赖
                    配置RabbitMQ的地址
                    定义类,加@Component,类中声明方法,加@RabbitListener,方法参数就是消息
                    PS:消息一旦消费就会从队列删除,RabbitMQ没有消息回溯功能

            2.work queue 工作队列
                ·提高消息处理速度,避免队列消息堆积
                ·多个消费者绑定到一个队列,同一条消息只会被一个消费者处理(平均)
                ·通过设置prefetch来控制消费者预取的消息数量,如1,表示每次只能获取一条消息,处理完成才能获取下一条消息

            3.发布订阅模式  允许将同一消息发送给多个消费者。实现方式是加入了exchange(交换机)。
                  常见exchange类型包括:(exchange负责消息路由,而不是存储,路由失败则消息丢失)
                        ·Fanout:广播
                            将接收到的消息广播到每一个跟其绑定的queue

                        ·Direct:路由
                            将接收到的消息根据规则路由到指定的Queue,路由模式
                                ·每一个Queue都与Exchange设置一个BindingKey
                                ·发布者发送消息时,指定消息的RoutingKey
                                ·Exchange将消息路由到BindingKey与消息RoutingKey一致的队列

                        ·Topic:话题
                            与DirectExchange类似,区别在于routingKey必须是多个单词的列表
                            可以使用通配符:
                                #:代指0个或多个单词
                                *:代指一个单词

                        ·交换机的作用是什么?
                            接收publisher发送的消息
                            将消息按照规则路由到与之绑定的队列
                            不能缓存消息,路由失败,消息丢失
                        ·Direct交换机与Fanout交换机的差异?
                             Fanout交换机将消息路由给每一个与之绑定的队列
                             Direct交换机根据RoutingKey判断路由给哪个队列
                             如果多个队列具有相同的RoutingKey,则与Fanout功能类似
                        ·消息转换器
                            SpringAMQP中消息的序列化和反序列化是怎么实现的?
                                  利用MessageConverter实现的,默认是JDK的序列化
                                  注意发送方与接收方必须使用相同的MessageConverter

9.elasticsearch  分布式搜索引擎,可以用来实现搜索、日志统计、分析、系统监控等功能
    ·采用倒排索引:(正向索引文档中找词条,倒排是根据词条找文档)
         索引(index):相同类型的文档的集合
         文档(document):每条数据就是一个文档
         映射(mapping):索引中文档的字段约束信息,类似表的结构约束
         词条(term):文档按照语义分成的词语
    ·区别:
        Mysql:擅长事务类型操作,可以确保数据的安全和一致性
        Elasticsearch:擅长海量数据的搜索、分析、计算

    ·mapping是对索引库中文档的约束,常见的mapping属性包括:
        type:字段数据类型,常见的简单类型有:
            字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
            数值:long、integer、short、byte、double、float、
            布尔:boolean
            日期:date
            对象:object
        index:是否创建索引,默认为true
        analyzer:使用哪种分词器
        properties:该字段的子字段

    ·索引库操作
        1) 创建索引库
            PUT /索引库名称
            {
                "mappings":{
                    "properties":{
                        "字段名":{
                            "type":"text",
                            "analyzer":"ik_smart"
                        },
                    }
                }
            }
        2)查看索引库
            GET /索引库名
        3)删除索引库
            DELETE /索引库名
        4)修改索引库   索引库和mapping一旦创建无法修改,但是可以添加新的字段
            PUT /索引库名/_mapping
            {
                "properties":{
                    "新字段名":{
                        "type":"integer"
                    }
                }
            }
        5)RestClient
            - 初始化   RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(HttpHost.create("url")));
            - 创建  CreateIndexRequest
                // 创建Request对象
                CreateIndexRequest request = new CreateIndexRequest("hotel");
                // 准备请求的参数:DSL语句
                request.source(MAPPING_TEMPLATE, XContentType.JSON);
                // 发送请求
                client.indices().create(request, RequestOptions.DEFAULT);
            - 删除  DeleteIndexRequest
                // 创建Request对象
                DeleteIndexRequest request = new DeleteIndexRequest("hotel");
                // 发送请求
                client.indices().delete(request, RequestOptions.DEFAULT);
            - 是否存在  GetIndexRequest
                // 创建Request对象
                GetIndexRequest request = new GetIndexRequest("hotel");
                // 发送请求
                boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
                // 输出
                System.err.println(exists ? "索引库已经存在!" : "索引库不存在!");
            -索引库操作的基本步骤:
                ·初始化RestHighLevelClient
                ·创建XxxIndexRequest。XXX是Create、Get、Delete
                ·准备DSL( Create时需要,其它是无参)
                ·发送请求。调用RestHighLevelClient#indices().xxx()方法,xxx是create、exists、delete

    ·文档操作
        1)添加文档
            ·POST /索引库名/_doc/文档id
              {
                  "字段1":"值1",
                  "字段2":{
                      "子属性1":"值3",
                      "子属性2":"值4"
                  },
              }
            ·RestClient
                 - 1)创建Request对象
                 - 2)准备请求参数,也就是DSL中的JSON文档
                 - 3)发送请求
            ·RestClient批量导入
                - 1)创建Request对象。这里是BulkRequest
                - 2)准备参数。批处理的参数,就是其它Request对象,这里就是多个IndexRequest
                - 3)发起请求。这里是批处理,调用的方法为client.bulk()方法
        2)查看文档
            ·GET /索引库名/_doc/文档id
            ·RestClient
                 - 1)准备Request对象。这次是查询,所以是GetRequest
                 - 2)发送请求,得到结果。因为是查询,这里调用client.get()方法
                 - 3)解析结果,就是对JSON做反序列化
        3)删除文档
            ·DELETE /索引库名/_doc/文档id
            ·RestClient
                - 1)准备DeleteRequest对象。要指定索引库名和id
                - 2)准备参数,无参
                - 3)发送请求。因为是删除,所以是client.delete()方法
        4)修改文档
            一、全量修改,会删除旧文档,添加新文档
                PUT/索引库名/_doc/文档id
                {
                    "字段1":"值1",
                    "字段2":"值2",
                }
            二、增量修改,修改指定字段值  局部
                POST/索引库名/_update/文档id
                {
                    "doc": {
                        "字段名":"新的值",
                    }
                }
            三、RestClient
                - 1)准备UpdateRequest对象
                - 2)准备参数。也就是JSON文档,里面包含要修改的字段
                - 3)更新文档。这里调用client.update()方法
        5)RestClient文档操作的基本步骤:
              - 初始化RestHighLevelClient
              - 创建XxxRequest。XXX是Index、Get、Update、Delete、Bulk
              - 准备参数(Index、Update、Bulk时需要)
              - 发送请求。调用RestHighLevelClient#.xxx()方法,xxx是index、get、update、delete、bulk
              - 解析结果(Get时需要)

    ·DSL查询文档
        GET /indexName/_search
        {
            "query": {
                "查询类型": {
                    "查询条件": "条件值"
                }
            }
        }
        1)查询所有:查询出所有数据,一般测试用。例如:match_all
        2)全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:
          match_query(推荐)
          multi_match_query
        3)精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。例如:
          range  范围
          term   不分词的词条
        4)地理(geo)查询:根据经纬度查询。例如:
          geo_distance    距离(推荐)
          geo_bounding_box  矩形范围
        5)复合(compound)查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。例如:
          ·bool query    布尔查询,利用逻辑关系组合多个其它的查询
                - must:必须匹配每个子查询,类似“与”
                - should:选择性匹配子查询,类似“或”
                - must_not:必须不匹配,不参与算分,类似“非”
                - filter:必须匹配,不参与算分

          ·fuction score  算分函数查询,可以控制文档相关性算分,控制文档排名
                关键点:
                - 过滤条件:决定哪些文档的算分被修改
                - 算分函数:决定函数算分的算法 weight
                - 运算模式:决定最终算分结果   multiply


    ·搜索结果处理
        1)排序   keyword类型、数值类型、地理坐标类型、日期类型
            排序方式ASC、DESC
        2)分页
            - from:从第几个文档开始
            - size:总共查询几个文档
            - 深度分页(查询分页深度较大时,汇总数据过多,对内存和CPU会产生非常大的压力  >10000)
                    search after
                    scroll
        3)高亮  highlight
            对非搜索字段高亮,需要添加一个属性:required_field_match=false
        4)RestClient操作
            查询的基本步骤是:
            - 创建SearchRequest对象
            - 准备Request.source(),也就是DSL。
               ① QueryBuilders来构建查询条件
               ② 传入Request.source() 的 query() 方法
            - 发送请求,得到结果
            - 解析结果(参考JSON结果,从外到内,逐层解析)

    ·数据聚合
        聚合常见的有三类:
        1)桶(Bucket)聚合:用来对文档做分组  相当于mysql中的group by
          - TermAggregation:按照文档字段值分组,例如按照品牌值分组、按照国家分组
          - Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组
        2)度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等  相当于mysql的聚合函数
          - Avg:求平均值
          - Max:求最大值
          - Min:求最小值
          - Stats:同时求max、min、avg、sum等
        3)管道(pipeline)聚合:其它聚合的结果为基础做聚合
        4)语法如下:
            GET /hotel/_search
            {
              "size": 0,  //  设置size为0,结果中不包含文档,只包含聚合结果
              "aggs": {   //  定义聚合
                  "brandAgg": {   //给聚合起个名字
                      "terms":    {   //  聚合的类型,按照品牌值聚合,所以选择term
                          "field":    "brand",    //  参与聚合的字段
                          "size": 20  //  希望获取的聚合结果数量
                      }
                  }
              }
            }
            ~~聚合必须的三要素:
            - 聚合名称
            - 聚合类型
            - 聚合字段
            ~~聚合可配置属性有:
            - size:指定聚合结果数量
            - order:指定聚合结果排序方式
            - field:指定聚合字段

    ·自动补全
        ·拼音分词器
        ·自定义分词器:
            ①创建索引库时,在settings中配置,可以包含三部分
            ②character filter
            ③tokenizer
            ④filter
        ·为了避免搜索到同音字,搜索时不要使用拼音分词器
        ·参与补全查询的字段必须是completion类型

    ·数据同步
        1)同步调用
            - 优点:实现简单,粗暴
            - 缺点:业务耦合度高
        2)异步通知
            - 优点:低耦合,实现难度一般
            - 缺点:依赖mq的可靠性
        3)监听binlog
            - 优点:完全解除服务间耦合
            - 缺点:开启binlog增加数据库负担、实现复杂度高

    ·集群
        1)单机面临的问题:
            - 海量数据存储问题:将索引库从逻辑上拆分为N个分片(shard),存储到多个节点
            - 单点故障问题:将分片数据在不同节点备份(replica )
        2)脑裂问题:
            - 集群中的节点失联导致的
            - 解决脑裂的方案是,要求选票超过 ( eligible节点数量 + 1 )/ 2 才能当选为主,因此eligible节点数量最好是奇数
        3)集群职责划分
            ·master eligible节点
                - 参与集群选主
                - 主节点可以管理集群状态、管理分片信息、处理创建和删除索引库的请求
            ·data节点
                - 数据的CRUD
            ·coordinator节点
                - 路由请求到其它节点
                - 合并查询到的结果,返回给用户
        4)集群分布式存储
            当新增文档时,应该保存到不同分片,保证数据均衡
        5)集群分布式查询
            elasticsearch的查询分成两个阶段:
                - scatter phase:分散阶段,coordinating node会把请求分发到每一个分片
                - gather phase:聚集阶段,coordinating node汇总data node的搜索结果,并处理为最终结果集返回给用户
        6)集群故障转移
            集群的master节点会监控集群中的节点状态,如果发现有节点宕机,会立即将宕机节点的分片数据迁移到其它节点,确保数据安全
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值