三合一网站怎么做,深圳市建设局官方网站,国外教程 网站,规划设计公司年终总结1. IP列表
公司发展到一定的规模之后#xff0c;应用拆分是无可避免的。假设我们有2个服务(服务A、服务B)#xff0c;如果服务A要调用服务B#xff0c;我们能怎么做呢#xff1f;最简单的方法是让服务A配置服务B的所有节点的IP#xff0c;在服务A内部做负载均衡调用服务B…1. IP列表
公司发展到一定的规模之后应用拆分是无可避免的。假设我们有2个服务(服务A、服务B)如果服务A要调用服务B我们能怎么做呢最简单的方法是让服务A配置服务B的所有节点的IP在服务A内部做负载均衡调用服务B的不同节点。 这种方式有3个明显的问题 服务B的节点变更需要将服务B的IP列表更新进每个服务A可以是通过配置文件、配置中心甚至是数据库 服务A需要对服务B的节点做健康检测避免将调用无效的节点 服务A要实现服务B调用的负载均衡策略
2. 反向代理
熟悉反向代理的人发现反向代理不正是解决这个问题的办法吗如果在服务A和服务B之间添加一个nginx网络拓扑看起来就是这样的 我们需要将服务B的节点配置为upstream定义nginx的server服务A通过nginx调用服务B我们看看下面的核心配置 weight指定每个服务器的权重值越大调用的次数越多 max_fails指定失败多少次后标记为不可用fail_timeout指过多长时间后将失败节点再次加入到服务列表中 backup作为备用节点其他节点不可用的时候back节点会接受负载均衡 down标记节点下线 ip_hash指定负载均衡策略通一个IP调度到同一个IP默认是round-robin proxy_next_stream指定哪些条件认为是请求失败的(max_fails统计的条件)
upstream service_b { # 默认轮询策略round-robin默认权重1server 192.168.100.11 weight1; server 192.168.100.12 weight2 max_fails10 fail_timeout30s ;server 192.168.100.13 backup; # 备用服务器当其他服务器都不可用时才使用 server 192.168.100.14 down; # 标记为不可用不参与负载均衡 ip_hash # 负载均衡策略基于客户端IP选择默认round-robin
}server { listen 80; location / {proxy_pass http://service_b; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; }
}
通过这种方式基本解决1.1里提到的3个问题了不过upstream的修改仍然是手动的而且需要重启nginx。 nginx提供了一个模块ngx_http_dyups_module让我们可以通过HTTP调用动态的修改upstream如果我们想要将service_b的节点改成下面2个节点我们可以这么做:
curl 127.0.0.1:8000/upstream/service_b -d
server 192.168.100.11:8080 max_fails3 fail_timeout5s weight10;server 192.168.100.12:8080 max_fails3 fail_timeout5s weight10;
不过这个方案没有开始流行就已经没落了最明显的问题是所有对服务B的调用都要经过中心节点(nginx)而且经过了一次转发影响了调用性能。
3. 注册中心
大概在2010年开始国内的大中厂都开始走向服务化但并没有一个成熟的中间件dubbo、motan、hedwig都是这个时代产物。服务提供者在启动的时候会将自己注册到服务注册中心(zookeeper、consul等实现)服务消费者从注册中心拿到服务提供者的IP在客户端做负载均衡直接连接服务提供者的IP相较于反向代理的方案好处是服务A和服务B是直接调用避免了一次中间转发。 现在主流的注册中心实现有很多这里我们选几个常见的对比一下 名称 CAP 语言 算法 数据结构 场景 存储 Zookeeper CP Java Zab协议 树ZNode 服务发现、锁、选主、配置 文件 Eureka AP Java Gossip key-value 服务发现 内存 Nacos CP AP Java Raft key-value 服务发现、锁、选主、配置 配置推送、流量管理(灰度发布) MySQL Consul AP Go Raft key-value 类似于Nacos 文件 Zookeeper最早出现常用于大数据系统的协调比如Hadoop/Kafka等生态成熟但特性就比较老出现在云原生之前没有考虑云原生/微服务的支持 Eureka专门为微服务设计不支持一致性协议适用gossip同步数据选择AP一致性较弱功能单一仅用于服务发现 Nacos基于Raft算法支持云原生比如流量管理、灰度发布等功能
一般Java语言开发的新系统的注册中心是在Eureka和Nacos之间选择Eureka天然和Spring Cloud集成适用简单当然功能也相当较弱。我们先来看看Eureka的使用。
4. Eureka入门
1. 创建应用
先创建Spring Boot应用参见1. 手动创建应用引入Spring Cloud的依赖管理
project...parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactId !-- 创建为SpringBoot应用 --version3.2.7/version/parent...propertiesproject.build.sourceEncodingUTF-8/project.build.sourceEncoding/propertiesdependencyManagementdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-parent/artifactId !-- 使用Spring Cloud依赖 --version2023.0.0/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagementdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-server/artifactId !-- 添加EurekaServer依赖 --/dependency/dependencies
/project
2. 启动类
添加启动类除了正常的Spring Boot应用的注解额外增加了EnableEurekaServer注解
package org.keyniu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;SpringBootApplication
EnableEurekaServer
public class StartEurekaServer {public static void main(String[] args) {SpringApplication.run(StartEurekaServer.class, args);}
}3. 核心配置
创建配置文件 application.yml包含的内容如下我们我看看每个配置字段的含义 配置 含义 Eureka字段 spring.application.name 应用名注册Eureka是的应用名 application.instance.app eureka.instance.hostname 运行实例的主机名或IP默认取当前机器的主机名 ; 为了方便识别一般会在/etc/hosts绑定IP和主机名设置对应节点机器名 ; Docker环境会选择prefer-ip-addresstrue直接采用IP地址 application.instance.hostName eureka.instance.lease-renewal-interval-in-seconds 客户端向EurekaServer续租的心跳默认30s application.instance.leaseInfo.renewalIntervalInSecs eureka.instance.lease-expiration-duration-in-seconds 最大的心跳时间间隔超过时间没心跳的客户端被认为宕机默认90s application.instance.leaseInfo.durationInSecs eureka.server.eviction-interval-timer-in-ms Eureka定时任务清理lease-expiration-duration没心跳的节点默认60s eureka.client.register-with-eureka 是否向EurekaServer注册自己 eureka.client.fetch-registry 是否从EurekaServer获取注册表信息 eureka.client.registry-fetch-interval-seconds 从EurekaServer获取注册表信息的时间间隔 eureka.client.serviceUrl.defaultZone 客户端向这个地址注册和拉取注册信息服务端节点用它来感知其他peer节点 eureka.server.wait-time-in-ms-when-sync-empty 长轮询的概念同步数据时如果没有数据变更请求会阻塞等待的时间 eureka.server.renewal-percent-threshold 心跳到底比例如果少于少于这个比例不会清理无心跳的节点默认0.85
注意点: Eureka服务端一般register-with-eureka、fetch-registry都设置为false不注册自己也从eureka拉取注册信息信息的同步通过内部的gossip协议进行 Eureka服务端通过eureka.server.serviceUrl的配置感知其他peer节点运行期间新增/删除节点通过修改配置文件实现或配置中心配置 Client周期性(lease-renewal-interval-in-seconds)向服务端续租如果超过最大时间(lease-expiration-duration-in-seconds)没收到续租请求这个节点被认为不可用 Server周期性(eviction-interval-timer-in-ms)检查服务器节点清理不可用的节点 Client向Server注册后Server之间通过gossip同步同步后每个Server节点存储自己的注册表evict线程(eviction-interval-timer-in-ms)统计本地注册表查看阈值(renewal-percent-threshold)看是否进入保护模式如果不是保护模式清理过去的节点节点的leaseInfo中保存了每个节点最后一次renewal的时间
server:port: 8080
spring:application:name: keyniu-eureka-server
eureka:instance:hostname: localhostlease-renewal-interval-in-seconds: 30lease-expiration-duration-in-seconds: 90client:register-with-eureka: falsefetch-registry: falseservice-url:defaultZone: http://127.0.0.1:${server.port}/eureka/server:wait-time-in-ms-when-sync-empty: 5enable-self-preservation: trueeviction-interval-timer-in-ms: 10000renewal-percent-threshold: 0.855. REST API
默认Eureka的接口返回的XML可以通过提交请求时指定Accept HTTP头设置响应内容的格式为JSON这一点对所有接口有效后续不再赘述
curl -s -H Accept: application/json http://192.168.31.52:8080/eureka/apps/${app}/${instanceId}
1. 获取所有实例
通过curl http://192.168.31.52:8080/eureka/apps能查看所有可用的节点列表包括所有的应用(application)应用下所有的节点(instance)节点的元数据(metadata)、租约(leaseInfo)等等 2. 指定app的实例
通过如下命令读取数据这里的KEYNIU-EUREKA-SERVER是app需要替换成对应的值。
curl http://192.168.31.52:8080/eureka/apps/${app}
curl http://192.168.31.52:8080/eureka/apps/KEYNIU-EUREKA-SERVER
3. 指定app/instanceId的实例
通过如下命令读取数据其中KEYNIU-EUREKA-SERVER是appRandy:keyniu-eureka-server:8080是instanceId
curl http://192.168.31.52:8080/eureka/apps/${app}/${instanceId}
curl http://192.168.31.52:8080/eureka/apps/KEYNIU-EUREKA-SERVER/Randy:keyniu-eureka-server:8080
4. 服务上下线
通过修改instance的status字段我们能控制服务的上下线比如将节点状态改为OUT_OF_SERVICE
curl -v -XPUT http://192.168.31.52:8080/eureka/apps/${app}/${instanceId}/status?valueOUT_OF_SERVICE
curl -v -XPUT http://192.168.31.52:8080/eureka/apps/KEYNIU-EUREKA-SERVER/Randy:keyniu-eureka-server:8080/status?valueOUT_OF_SERVICE
如果想让节点恢复为上线状态通过如下命令修改
curl -v -XDELETE http://192.168.31.52:8080/eureka/apps/${app}/${instanceId}/status?valueUP
curl -v -XDELETE http://192.168.31.52:8080/eureka/apps/KEYNIU-EUREKA-SERVER/Randy:keyniu-eureka-server:8080/status?valueUP
5. 更新元数据
比如我们要在元数据里添加一个admin字段值是zhangsan我们可以这么做
curl -v -XPUT http://192.168.31.52:8080/eureka/apps/${app}/${instanceId}/metadata?${key}${value}
curl -v -XPUT http://192.168.31.52:8080/eureka/apps/KEYNIU-EUREKA-SERVER/Randy:keyniu-eureka-server:8080/metadata?adminzhangsan 6. 新增instance
通过POST请求请求体可以是JSON格式按我们读取到的实例格式假设我们要新增一个节点: Randy1:keyniu-eureka-server:8080 命令看起来是这样的
curl -v -H Content-Type: application/json -XPOST http://192.168.31.52:8080/eureka/apps/KEYNIU-EUREKA-SERVER -d {instance: {instanceId: Randy1:keyniu-eureka-server:8080,hostName: 192.168.31.53,app: KEYNIU-EUREKA-SERVER,ipAddr: 192.168.31.53,status: UP,overriddenStatus: UNKNOWN,port: {$: 8080,enabled: true},securePort: {$: 443,enabled: false},countryId: 1,dataCenterInfo: {class: com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo,name: MyOwn},leaseInfo: {renewalIntervalInSecs: 30,durationInSecs: 90,registrationTimestamp: 1719660811233,lastRenewalTimestamp: 1719661187133,evictionTimestamp: 0,serviceUpTimestamp: 1719655154360},metadata: {admin: zhangsan,management.port: 8080,group: secondKill},homePageUrl: http://192.168.31.53:8080/,statusPageUrl: http://192.168.31.53:8080/actuator/info,healthCheckUrl: http://192.168.31.53:8080/actuator/health,vipAddress: keyniu-eureka-server,secureVipAddress: keyniu-eureka-server,isCoordinatingDiscoveryServer: true,lastUpdatedTimestamp: 1719660811233,lastDirtyTimestamp: 1719655154170,actionType: ADDED}
}
7. 删除instance
通过指定app、instanceId删除对应实例
curl -XDELETE http://192.168.31.52:8080/eureka/${app}/${instanceId}
curl -XDELETE http://192.168.31.52:8080/eureka/KEYNIU-EUREKA-SERVER/Randy1:keyniu-eureka-server:8080
8. 发送心跳
curl -XPUT http://192.168.31.52:8080/eureka/apps/${app}/${instanceId}
curl -XPUT http://192.168.31.52:8080/eureka/apps/KEYNIU-EUREKA-SERVER/Randy1:keyniu-eureka-server:8080
6. 案例解析
现在我们反过来从Eureka UI来看显示的每个字段是从何而来怎么配置
1. Eureka首页
下图是Eureka UI首页显示的内容我们主要关系其中的6个显示字段对应图上的数字下面列表中是它的说明 环境通过eureka.environment配置默认test 数据中心通过eureka.datacenter配置默认MyOwn 是否删除过去租约只要不处于自我保护模式这个值就是true不启动eureka.server.enable-self-preservation 进入自我保护模式的阈值资料上计算公式: 客户端数量 * (60 / lease-renewal-interval-in-seconds ) * renewal-percent-threshold实测下来有出入待进一步研究 仅一个客户端lease-renewal-interval-in-seconds 30 Renews threshod 1计算值 1 * (60/30) * 0.85 1.7 仅一个客户端lease-renewal-interval-in-seconds 20 Renews threshod 3计算值 1 * (60/20) * 0.85 2.55 EurekaServer的节点取值是eureka.client.serviceUrl.defaultZone中配的机器 注册到EurekaServer的节点这个值是我们配置的spring.application.nameStatus里显示的是我们的nodeName默认格式是: ${hostName}:${app.name}:${server.port} 2. 注册表信息
通过Eureka Server的REST接口我们能读到注册表信息下面这个连接能查看所有的APP信息不过我们这里只有一个节点
http://127.0.0.1:8080/eureka/apps
下面是其中一个节点的内容下面有序列表的数字对应图片里的数字 dataCenterInfo表示数据中心一般配置到Eureka Client定义是个枚举DataCenterInfo.Name类可选值有Netflix、Amazon、MyOwn默认MyOwn 对应配置项eureka.instance.data-center-info eureka.datacenter也是数据中心的概念一般配置到Eureka Server 暂时没看到这两个值如果不同的话有什么影响但会让人觉得混乱需要进一步研究 metadata元数据信息默认只有management.port可以做自定义配置 对应配置项eureka.instance.metadata-map 基于元数据可以做服务分组用MetadataAwarePredicate实现调用对应分组的节点 instanceId实际是拼接值: ${主机名}:${app.name}:${server.port} overriddenstatus用来覆盖默认状态节点的状态默认通过心跳来维护心跳正常状态为UP lastRenewalTimestamp表示最后一次收到心跳的时间Eureka用这个时间来判断节点是否可用 lastDirtyTimestamp表示节点信息最后一次更新的时间用来Eureka Server节点之间的增量