分布式基础

分布式基础,第1张

分布式基础

目录

SpringCloud和SpringCloud Alibaba引入微服务治理方案

概述

SpringCloud Alibaba-Nacos

Nacos注册中心

Nacos配置中心

SpringCloud-Feign

Springcloud -Getway:API网关 

跨域

elasticsearch

基本概念

初步检索

1._cat

3 .索引一个文档(保存)

4.查询请求文档

5.更新文档

6. 删除文档

7.bulk批量API


SpringCloud和SpringCloud Alibaba引入微服务治理方案 概述

SpringCloud的痛点

SpringCloud部分组件停止维护和更新,给开发带来不便

SpringCloud部分环境搭建复杂,没有完善的可视化界面,我们需要二次开发和定制。

SprigCloud配置复杂,部分配置差别难以区分和合理应用

SpringCloud Alibaba的优势

性能强悍,设计合理,开源,有可视化界面给运维开发带来极大的便利

结合SpringCloud Alibaba,我们最终的技术方案:

SpringCloud Alibaba-Nacos:注册中心(服务发现与注册)

SpringCloud Alibaba-Nacos:配置中心(动态配置管理)

SpringCloud-Ribbon:负载均衡

SpringCloud-Feign:调用远程服务

SpringCloud Alibaba -Sentinel:服务容错(限流,降级,熔断)

Springcloud -Getway:API网关(webflux编程模式)

SpringCloud-sleuth:调用链监控

SpringCloud-Alibaba-Seata:原fescar,分布式事务解决方案

SpringCloud与Springcloud alibaba与Springboot的对应关系

 首先引入SpringCloud,SpringCloudAlibaba和Springboot的相关依赖(注意版本对应),因为后面要用SpringCloud,SpringCloudAlibaba的相关组件所以要引入我们SpringCloud,SpringCloudAlibaba的相关依赖。

SpringCloud Alibaba-Nacos Nacos注册中心

首先下载nacos服务器

1.将Nacos Discovery的依赖引入,功能是将我们的微服务注册到我们的注册中心,包括发现其他微服务,对服务注册发现的功能,放在com文件下,那么其他的微服务也具有了服务发现注册的功能。

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        

2.将 Nacos 服务器地址配置添加到 /src/main/resources/application.yml 文件中。那个微服务需要配置到注册中心就要在该服务中配置nacos服务器地址,那么该服务一旦上线就可以在nacos服务器中找到。 localhost:8848是注册中心地址,并且要为每个服务取一个应用的名字,不然nacos的客户端找不到该服务 Application:name。

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  application:
    name: ncpmall-coupon

 3.使用@EnableDiscoveryClient注解开启服务注册与发现功能,运行该服务,nacos服务器就能发现该微服务。

@MapperScan("com.lizude.ncpmall.ncpmallcoupon.dao")
@SpringBootApplication
@EnableDiscoveryClient
public class NcpmallCouponApplication {
    public static void main(String[] args) {
        SpringApplication.run(NcpmallCouponApplication.class, args);
    }
}

4.启动该服务之前我们需要先打开Nacos服务器,然后启动该服务

Nacos配置中心

1.引入配置中心的依赖,该服务在配置一些配置文件之后就能连接配置中心


            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-config

2.将 Nacos config 元数据配置添加到文件 /src/main/resources/bootstrap.properties (这个文件会优先于application.properties加载)

spring.application.name=ncpmall-coupon
spring.cloud.nacos.config.server-addr=localhost:8848

没有使用nacos之前如果要修改配置十分麻烦,需要在application里面修改,然后重新发布到服务器上,但是如果服务器一多就会十分麻烦,现在我们只需要在nacos修改一处,处处生效 。

3.在nacos的配置页面点加号

然后在运行的服务的console中找那个微服务配置文件的名字填到上面的配置图片中,我们是ncpmall-coupon.properties .

4.最后如果项目已经上线不方便重启,就使用@refreshScope,当配置信息改变,就不需要重启微服务

@Value("$(配置项名字)");获取到配置

如果配置中心和当前应用的配置文件都配置了相同的项,优先使用配置中心的配置

@RefreshScope//刷新配置信息
@RestController
@RequestMapping("ncpmallcoupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;

    @Value("${coupon.user.name}")
    private  String name;
    @Value("${user.age}")
    private Integer age;
    @RequestMapping("/test")
    public R test(){
        return R.ok().put("name",name).put("age",age);
    }

    @RequestMapping("/menber/list")
    public R menbercoupons(){
        CouponEntity couponEntity = new CouponEntity();
        couponEntity.setCouponName("满一百减10");
        return R.ok().put("coupons",Arrays.asList(couponEntity));
    }

    *.xml
  global-config:
    db-config:
      id-type: auto
server:
  port: 8000

配置集ID:类似于配置文件名

  

配置分组:默认所有的配置集都属于:DEFAULT_GROUP

指定配置分组在bootstrap.properties文件中

spring.application.name=ncpmall-coupon
spring.cloud.nacos.config.server-addr=localhost:8848
#或者dev,prop,test的名称空间
spring.cloud.nacos.config.namespace=47c04e7e-4096-4f5c-8e83-c04a5d252902
spring.cloud.nacos.config.group=11

配置分组区分环境 :每个微服务创建自己的命名空间,使用配置分组区分环境,dev,test,prop

3.同时加载多个配置集

在boottrap.properties中配置 

spring.application.name=ncpmall-coupon
spring.cloud.nacos.config.server-addr=localhost:8848
#或者dev,prop,test的名称空间
spring.cloud.nacos.config.namespace=a062449f-f8a6-409f-8d1d-b21eb28c1d00
#spring.cloud.nacos.config.group=11
spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
spring.cloud.nacos.config.ext-config[0].group=dev
spring.cloud.nacos.config.ext-config[0].refresh=true
spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
spring.cloud.nacos.config.ext-config[1].group=dev
spring.cloud.nacos.config.ext-config[1].refresh=true
spring.cloud.nacos.config.ext-config[2].data-id=other.yml
spring.cloud.nacos.config.ext-config[2].group=dev
spring.cloud.nacos.config.ext-config[3].refresh=true
SpringCloud-Feign

Feign是一个声明式的http客户端,它的目的就是让远程调用更加简单。feign提供了http请求的模板。引入了feign就具备了调用其他微服务的能力。

1.想要远程调用别的服务

(1):引入openFeigh

(2):编写一个接口,告诉Springcloud,这个接口需要调用远程服务

              1.声明接口的每一个方法都是调用那个远程服务的那个请求(这个时候我们只需要把远程请求的方法黏贴到我们的openfeign中)

//告诉Springcloud这个接口是个远程客户端,注解要说明调用远程那个微服务
@FeignClient("ncpmall-coupon")
//如果我们以后要调用这个接口的menbercoupons方法那么就会去注册中心中找ncpmall-coupon,然后再去调用这个请求ncpmallcoupon/coupon/menber/list对应的controller方法
public interface CouponFeignService {
    @RequestMapping("ncpmallcoupon/coupon/menber/list")
    public R menbercoupons();
}

 (3)开启远程调用功能(用@EnableFeignClients注解开启),当服务启动就会自动扫描这个包下所有标了@Feignclinent注解的接口,每一个接口又说明了,他是调用那个接口的那个请求。

@MapperScan("com.lizude.ncpmall.ncpmallcoupon.dao")
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients("com.lizude.ncpmall.ncpmallcoupon.feign")
public class NcpmallCouponApplication {

    public static void main(String[] args) {
        SpringApplication.run(NcpmallCouponApplication.class, args);
    }

}
Springcloud -Getway:API网关 

简介:网关作为流量的入口,常用功能包括路由转发,权限校验,限流控制,Springcloud gateway作为SpringCloud官方推出的第二代网关框架,取代了zuul网关。

跨域

定义:前后端分离就产生了跨域,指浏览器不能执行其他服务器的资源,它是由浏览器的同源策略造成的,是浏览器对Javascript施加的安全限制。

同源策略:协议,域名,端口号都要相同,其中有一个不同就是跨域

 跨域流程:

 

 跨域官方文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORSHTTP | MDN

解决跨域(一):使用nginx部署为同一域

 解决跨域(二):发送预检请求,然后响应允许跨域,配置允许跨域的响应头

elasticsearch 基本概念

应用场景:全文检索,ELK(elasticsearch,kibanna,logstack(收集日志)):日志储存,日志检索

elasticsearch是一个分布式的开源搜索和分析的引擎,可以快速存储,分析,检索海量数据。

1.index(索引)

动词相当于mysql中的insert等

名词相当于mysql中的database

2.Type(类型)

在elasticsearch的index中,可以定义一个或者多个类型type,类似于mysql中的table,每种数据类型的数据都放在一起。

 数据就是json格式的文档,每一个文档都有它的属性,属性就相当于mysql中的列名。

在ealsearch6.6之后没有类型这个说法

3.Elasticsearch倒排索引机制

 elasticsearch:存储检索数据                        kibnana:可视化检索数据界面

初步检索 1._cat

在get方法下,访问192.168.56.10:9200/_cat/nodes:查看所有节点

在get方法下,访问192.168.56.10:9200/_cat/health:查看所有elasticsearch的健康状况

在get方法下,访问192.168.56.10:9200/_cat/master:查看主节点

在get方法下,访问192.168.56.10:9200/_cat/indices:查看所有索引   相当于MySQL的show databases

2.索引创建,查询,删除

创建:192.168.56.10:9200/shopping            put方法

查询:192.168.56.10:9200/shopping          get方法

删除:192.168.56.10:9200/showpping         delete方法

3 .索引一个文档(保存)

保存一个数据,保存在那个索引的那个类型下,指定用哪个唯一标识

在put请求下,向elasticssearch 发送localhost:9200/customer/externer/1,在customer索引下的externer类型下保存一号数据,数据为{"name" : "lizude"},json数据

PUT和post都行:

post新增。如果不指定id,会自动生成id。指定id就会修改这个数据,并新增版本号

PUT可以新增可以修改。put必须指定id;由于put需要指定id,我们一般用来做修改,不指定id会报错,。

 postman测试

 _index,_type,_id,_version等这些带“_”,属于元数据

 _index:索引

_type:类型

_id:刚刚的/1

_version:版本,如果postman再发送一个相同的请求,version就会是2

result:发送请求的结果,如果postman再发送一个相同的请求,result就会是update

_shards:分片(集群)

4.查询请求文档

在get请求下,localhost:9200/customer/external/1

 _seq_no,_primary_term是并发控制字段,用来做乐观锁(集群)

_found是否找到该数据

5.更新文档

192.168.56.10:9200/customer/external/1/_update                   POST                      
{
"doc":{
"name": "John Doew"
}
}

POST customer/external/1
{
"name": "John Doe2"
}

PUT customer/external/1
{
"name": "John Doe"
}

不同:POST *** 作会对比源文档数据,如果相同不会有什么 *** 作,文档 version 不增加
PUT *** 作总会将数据重新保存并增加 version 版本;在创建索引时候只能用put不能post
带_update 对比元数据如果一样就不进行任何 *** 作。
看场景;
对于大并发更新,不带 update;
对于大并发查询偶尔更新,带 update;对比更新,重新计算分配规则

6. 删除文档

customer/external/1                 DELETE方法                      elasticsearch没有提供类型的删除 *** 作

7.bulk批量API

localhost:192.168.56.10/customer/external/_bulk                            post方法

{"index":{"_id":"1"}}        保存一个一号数据,index是索引,而是是post请求所以是保存
{"name": "John Doe" }             数据内容是"name": "John Doe"

两行为一个整体
{"index":{"_id":"2"}}
{"name": "Jane Doe" }

批量 *** 作没有办法在postman中进行测试,到kibana测试:

POST customer/external/_bulk
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }
POST /_bulk
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title":"My first blog post" }
{ "index":{ "_index": "website", "_type": "blog" }}
{ "title":"My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123"} }
{ "doc" : {"title" : "My updated blog post"} }

测试批量数据:es测试数据.json · 坐看云起时/common_content - Gitee.com

 复杂检索

官方文档:Start searching | Elasticsearch Guide [7.5] | Elastic

1.SearchAPI

一个是通过使用 REST request URI发送搜索参数(uri+检索参数)

GET bank/_search?q=*&sort=account_number:asc

响应结果解释:
took - Elasticsearch 执行搜索的时间(毫秒)
time_out - 告诉我们搜索是否超时
_shards - 告诉我们多少个分片被搜索了,以及统计了成功/失败的搜索分片
hits - 搜索结果
hits.total - 搜索结果
hits.hits - 实际的搜索结果数组(默认为前 10 的文档)
sort - 结果的排序 key(键)(没有则按 score 排序)
score 和 max_score –相关性得分和最高得分(全文检索用)
另一个是通过使用REST request body 来发送它们(uri+请求体)

GET bank/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"account_number": {
"order": "desc"
}
}
]
}

2.Query DSL

基本语法

一个查询语句 的典型结构
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,
}
}

 如果是针对某个字段,那么它的结构如下:
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
}

GET bank/_search
{"query":{"match_all": {}},
  "sort": [
    {
      "balance": {
        "order": "desc"
      }
    }
  ]
}

可以简写为:

GET bank/_search
{"query":{"match_all": {}},
  "sort": [
    {
      "balance": "desc"
    }
  ]
}

GET bank/_search
{"query":{"match_all": {}},
  "sort": [
    {
      "balance": "desc"
    }
  ],
  "from": 5,
  "size": 5
}

返回部分字段

GET bank/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 5,
"_source": ["age","balance"]
}

匹配查询

相当于mysql的条件匹配,也可以做模糊查询

匹配查询:

GET bank/_search
{
  "query":{"match": {
    "firstname": "Elinor"
  }}
}

模糊查询

GET bank/_search
{
  "query": {"match": {
    "address": "mill lane"
  }}
}

match_phrase短语匹配

包含了一个完整的mill lane,以前是匹配mill或者lane或者mill lane,根据一些规则进行打分。存储的数据维护一张倒排索引表 (也就是把存储的东西进行分词),然后将要配对短语的与我们存储的倒排索引表对比,得出scode。

GET bank/_search
{
"query": {
"match_phrase": {
"address": "mill road"
}
}
}

multi_match 多字段匹配

GET bank/_search
{
  "query": {"multi_match": {
    "query": "MILL",
    "fields": ["address","city"]
  }}
}

BOOL符合查询

 GET bank/_search
{
  "query":{
    "bool": {
      "must": [
        {"match": {
          "gender": "F"
        }},
        {
          "match": {
            "address": "mill"
          }
        }
      ],
      "must_not": [
        {"match": {
          "age": "38"
        }}
      ],
      "should": [           //能匹配最好,不能匹配也行,满足得分高,不满足得分低。
        {"match": {
          "lastname": "Wallace"
        }}
      ]
    }
  }
}

GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {"range": {
          "age": {
            "gte": 10,
            "lte": 30
          }
        }},
        {
          "match": {
            "address": "mill"
          }
        }
      ]
    }
  }
}

Filter

并不是所有的查询都需要产生分数,特别是那些仅用于 “filtering”(过滤)的文档。为了不
计算分数 Elasticsearch 会自动检查场景并且优化查询的执行

GET bank/_search
{
  "query":{
    "bool": {
      "must": [
        {"match": {
          "gender": "F"
        }},
        {
          "match": {
            "address": "mill"
          }
        }
      ],
      "must_not": [
        {"match": {
          "age": "38"
        }}
      ],
      "should": [
        {"match": {
          "lastname": "Wallace"
        }}
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 10,
            "lte": 20
          }
        }
      }
    }
  }
}

term

和match都是用来匹配某个属性的值。全文检索字段用match,精确值检索用term

id推荐使用match,address推荐使用term,因为address会全文检索mill lane

aggregations

         聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致等于 SQL GROUP
BY 和 SQL 聚合函数。在 Elasticsearch 中,您有执行搜索返回 hits(命中结果),并且同时返
回聚合结果,把一个响应中的所有 hits(命中结果)分隔开的能力。这是非常强大且有效的,
您可以执行查询和多个聚合,并且在一次使用中得到各自的(任何一个的)返回结果,使用
一次简洁和简化的 API 来避免网络往返。

GET bank/_search
{
  "query": {},              //查询的结果
  "aggs": {                 //聚合
    "NAME": {             //此次聚合的名字
      "AGG_TYPE": {}     //此次聚合的类型
    }
  }
}

搜索 address 中包含 mill 的所有人的年龄分布以及平均年龄,但不显示这些人的详情。

##根据匹配的address中含有mill的结果,然后进行聚合,有terms()聚合,有avg(平均),term有的类型下得age出现的次数
GET bank/_search
{
  "query": {"match": { 
    "address": "mill"
  }},
  "aggs": {
    "ageagg": {
      "terms": {
        "field": "age",
        "size": 111
      }
    },
    "ageavg":{"avg": {
      "field": "age"
    }},
    "agebalance":{"avg": {
      "field": "balance"
    }}
  } 
}

按照年龄聚合,并且请求这些年龄段的这些人的平均薪资

##分清楚是基于在上一次聚合的基础上再聚合,还是在重新聚合(上面是重新聚合)
GET bank/_search
{"query": {"match_all": {}}, 
  "aggs": {
    "ageagg": {
      "terms": {
        "field": "age",
        "size": 100
      }
      , "aggs": {
        "ageavg": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
  , "size": 0  //不显示搜索数据
}

查出所有年龄分布,并且这些年龄段中 M 的平均薪资和 F 的平均薪资以及这个年龄段的总体平均薪资。

GET bank/_search
{
  "query": {"match_all": {}}
  , "aggs": {
    "aggage": {
      "terms": {
        "field": "age",
        "size": 100
      }
      , "aggs": {
        "allavgbalance": {
          "avg": {
            "field": "balance"
          }
        },
        "aggsM":{
          "terms": {
            "field": "gender.keyword",
            "size": 3
          }
          , "aggs": {
            "avgM": {
              "avg": {
                "field": "balance"
              }
            }
          }
          },
          "aggsF":{
            "terms": {
              "field": "gender.keyword",
              "size": 3
            }
            , "aggs": {
              "avgF": {
                "avg": {
                  "field": "balance"
                }
              }
            }
          }
      }
    }
  }
  , "size":0
}

mapping

Mapping 是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和
索引的(相当于sql的字段设置类型)

 1.创建一个mapping

##创建一个索引的mapping
GET bank/_mapping
PUT /myindex
{
  "mappings": {
    "properties": {
      "age":{"type": "integer"},
      "email":{"type": "keyword"},
      "name":{"type": "text"},
    }
  }
}

2.如果在一个已存在的索引要添加一个没有一个字段,将不能直接添加到name的下面,,我们只能重新设置该字段的index属性设置为false,设置为false的意思是不能检索,只能充当于是沉余信息。

往myindex中添加一个新的字段id

PUT /myindex
{
  "mappings": {"properties": {"id":{"type": "long","index": false}}}
}

GET myin/_mapping

 3.对于已经存在的映射字段,我们不能更新。更新必须创建新的索引把旧数据进行数据迁移到新索引中。

把我们的原来索引中的bank数据,迁移到我们newbank中,修改我们之前想修改的age类型

然后进行数据迁移 

POST _reindex
{
  "source": {
    "index": "bank"
    ”type“:"account"//type其实可以省略,自从6.6之后type就被省略了
  },
  "dest": {
    "index": "newbank"
  }
}

 keyword精确匹配,text是全文检索

分词

SpringCloud H版、SpringCloud Alibaba整合电商项目(谷粒商城2020)技术总结_m0_38140207的博客-CSDN博客

一个 tokenizer (分词器)接收一个字符流,将之分割为独立的 tokens (词元,通常是独立 的单词),然后输出 tokens 流。es默认设置的分词器都是支持英文的分词,所以我们要安装中文分词器。 standard分词器:
POST _analyze
{
  "tokenizer": "standard",
  "text": ["两只快速的棕狐跳过了懒狗的骨头。"]
}

ik分词器:

POST _analyze
{
  "analyzer": "ik_max_word",
  "text": ["超级喜欢彼岸舞"]
} 
POST _analyze
{
  "analyzer": "ik_smart",
  "text": ["李祖德吃屎"]
}

自定义词库

修改/usr/share/elasticsearch/plugins/ik/config/中的 IKAnalyzer.cfg.xml

 nginx里面有三个文件夹

[root@localhost nginx]# ls
conf  html  logs

conf是配置文件

html 是资源的存放处,相当于tomcat的web目录

logs是·日志信息

在nginx中我们事先放置了分词器的自定义词库

[root@localhost conf]# cd ..
[root@localhost nginx]# cd html
[root@localhost html]# ls
es  index.html
[root@localhost html]# cd es
[root@localhost es]# ls
fci.txt
[root@localhost es]#

我们只需要远程配置远程扩展地址,变为我们的nginx的分词库的地址,也就是

192.168.56.10:80/es/fci.txt

ik分词器的配置,nginx配置我们全部都挂载到了/mydata文件中的elasticsearch和nginx中,挂载就是把容器中的文件映射到其他文件下,如果我们删除容器,我们以前的配置却还在,更加方便。,修改容器配置也不用进入到容器中,我们只需要在映射文件中修改

Elasticsearch-Rest-Client 1 )、 9300 : TCP  spring-data-elasticsearch:transport-api.jar ;  springboot 版本不同, transport-api.jar 不同,不能适配 es 版本  7.x 已经不建议使用, 8 以后就要废弃 2 )、 9200 : HTTP  JestClient :非官方,更新慢  RestTemplate :模拟发 HTTP 请求, ES 很多 *** 作需要自己封装,麻烦  HttpClient :同上  Elasticsearch-Rest-Client :官方 RestClient ,封装了 ES *** 作, API 层次分明,上手简单 最终选择 Elasticsearch-Rest-Client ( elasticsearch-rest-high-level-client ) https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html ealsticsearch可以有多种语言对其 *** 作

 为什么不使用Javascript *** 作es的呢?

1.ES集群属于后端,端口暴露在前端不安全

springboot整合es:

1.导入依赖 (相当于mysql的驱动)


            org.elasticsearch.client
            elasticsearch-rest-high-level-client
            7.4.2
        

2.编写配置

根据官方文档的API,其实ealsticsearch很多 *** 作都被封装好了,我们直接通过引入的client的依赖,来使用其中的 *** 作在java端

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5679307.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存