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节点会监控集群中的节点状态,如果发现有节点宕机,会立即将宕机节点的分片数据迁移到其它节点,确保数据安全
springcloud微服务基础--黑马笔记
最新推荐文章于 2024-09-13 21:40:38 发布