# springcloud-abtest **Repository Path**: null_678_4940/springcloud-abtest ## Basic Information - **Project Name**: springcloud-abtest - **Description**: 基于springcloud gateway和eureka的abtest - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2023-03-08 - **Last Updated**: 2023-03-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 基于springcloud-abtest的AB-test ## 抽象系统架构 1. 网关:gateway 2. eureka集群:eureka-1. eureka-2 3. 应用:api * api-a:a版本 * api-b:b版本 ## a/b版本切换逻辑(方案一:基于eureka) 1. gateway通过eureka集群获取api的服务列表 2. 重写eureka心跳的健康检查方法,加入内存开关flag 3. a/b两个应用注册到eureka集群上的服务名均为api 4. a版本的服务状态为up,b版本的服务状态为down 5. 当发生需要切换a/b版本的情况时,通过接口将a版本的服务状态切换为down,b版本的服务状态为up 6. 在一次心跳之后,eureka集群调整a版本的注册状态为down,b版本的注册状态为up 7. 三次服务续约之后(默认为90秒),网关不再路由到a版本,转而路由到b版本 8. 在三次服务续约期间,a/b都可能被网关选中 ## a/b版本切换逻辑(方案二:基于gateway) 改造gateway 1. 引入redis,配置RedisTemplate 2. 重写RouteDefinitionRepository接口的get、save、delete方法,改为操作redis 3. 提供RouteController接口,接口中提供路由的get、save、delete方法 4. 接口入参为RouteDefinition对象 ## 项目关键配置 ### eureka集群 ```yaml server: port: 31001 spring: application: name: eureka eureka: instance: hostname: ${spring.application.name} lease-renewal-interval-in-seconds: 5 # 表示服务的续约时间,默认是 30 秒。 lease-expiration-duration-in-seconds: 5 # 表示服务失效时间,默认是 90 秒。 client: service-url: defaultZone: http://localhost:31001/eureka,http://localhost:31002/eureka register-with-eureka: false server: enableSelfPreservation: true # 关闭自我保护模式(缺省为打开) eviction-interval-timer-in-ms: 5000 # 续期时间,即扫描失效服务的间隔时间(缺省为60*1000ms),测试环境修改小点 registry-fetch-interval-seconds: 10 # 客户端拉取readOnly缓存的时间间隔,默认是30s,可以根据需要调整,我们线上是使用的10s response-cache-update-interval-ms: 3000 #readWrite缓存到readOnly缓存的同步时间,调整eureka的server端配置参数 对应的配置参数,#只读缓存更新频率,单位:毫秒,默认是30s,我们线上使用的是3s钟 ``` ### api-a ```yaml spring: application: name: api-a # 注册到eureka server的服务名 eureka: client: service-url: defaultZone: http://localhost:31001/eureka/,http://localhost:31002/eureka/ # eureka server的地址 ``` ### api-b ```yaml spring: application: name: api-b # 注册到eureka server的服务名 eureka: client: service-url: defaultZone: http://localhost:31001/eureka/,http://localhost:31002/eureka/ # eureka server的地址 ``` ### gateway配置(完整) ```yaml server: port: 31005 spring: application: name: gateway cloud: gateway: discovery: locator: enabled: true #开启自动代理 # 动态路由 从redis中读取并重写 routes: - id: api-route #路由的ID,没有固定规则但要求唯一,简易配合服务名 uri: lb://api #匹配后提供服务的路由地址 predicates: - Path=/test/** #断言,路径相匹配的进行路由 redis: password: 123456 cluster: #设置key的生存时间,当key过期时,它会被自动删除; expire-seconds: 120 #设置命令的执行时间,如果超过这个时间,则报错; command-timeout: 5000 #设置redis集群的节点信息,其中namenode为域名解析,通过解析域名来获取相应的地址; nodes: localhost:6379 eureka: client: service-url: defaultZone: http://localhost:31001/eureka,http://localhost:31002/eureka instance: #不加的话我看过eureka注册界面,是以docker容器的container id注册过去的,譬如container id为abcde, #那么当访问该微服务时,eureka以http://abcde/xxx,去访问的,当然是访问不到该服务. #配置下面的选项后,就会以内网ip加端口去访问就能访问到了。 prefer-ip-address: true instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} ``` ## 切换路由地址 ### 新增 `http://localhost:31005/gateway/add` ```json { "filters": [], "id": "api-route", "metadata": {}, "order": 0, "predicates": [ { "args": { "pattern": "/test/**" }, "name": "Path" } ], "uri": "lb://API-A" } ``` ### 更新 `http://localhost:31005/gateway/update` ```json { "filters": [], "id": "api-route", "metadata": {}, "order": 0, "predicates": [ { "args": { "pattern": "/test/**" }, "name": "Path" } ], "uri": "lb://API-B" } ``` ## 项目源码 `https://gitee.com/wuhong12306/springcloud-abtest.git`