And*_*unt 10 blue-green-deployment spring-cloud pivotal-cloud-foundry spring-cloud-netflix
我正在尝试一个与图像中详细描述的设置非常相似的设置:https://raw.githubusercontent.com/Oreste-Luci/netflix-oss-example/master/netflix-oss-example.png
在我的设置中,我使用的是客户端应用程序(https://www.joedog.org/siege-home/),代理(Zuul),发现服务(Eureka)和简单的微服务.一切都部署在PWS上.
我想从我的简单微服务的一个版本迁移到下一个版本,没有任何停机时间.最初我开始使用这里描述的技术:https://docs.cloudfoundry.org/devguide/deploy-apps/blue-green.html
在我看来,这种方法与Eureka等发现服务并不"兼容".实际上,我的服务的新版本在Eureka中注册并且甚至在我可以重新映射所有路由(CF路由器)之前接收流量.
这引出了另一种方法,我依赖于Spring Cloud/Netflix中的故障转移机制:
据我所知,Zuul在引擎盖下使用了Ribbon(负载均衡),所以在旧实例仍然在Eureka但实际上关闭的那一瞬间,我期望在新实例上重试而不会对客户端产生任何影响.
但是,我的假设是错误的.我的客户端出现了几个502错误:
Lifting the server siege... done.
Transactions: 5305 hits
Availability: 99.96 %
Elapsed time: 59.61 secs
Data transferred: 26.06 MB
Response time: 0.17 secs
Transaction rate: 89.00 trans/sec
Throughput: 0.44 MB/sec
Concurrency: 14.96
Successful transactions: 5305
Failed transactions: 2
Longest transaction: 3.17
Shortest transaction: 0.14
Run Code Online (Sandbox Code Playgroud)
我的application.yml的一部分
server:
port: ${PORT:8765}
info:
component: proxy
ribbon:
MaxAutoRetries: 2 # Max number of retries on the same server (excluding the first try)
MaxAutoRetriesNextServer: 2 # Max number of next servers to retry (excluding the first server)
OkToRetryOnAllOperations: true # Whether all operations can be retried for this client
ServerListRefreshInterval: 2000 # Interval to refresh the server list from the source
ConnectTimeout: 3000 # Connect timeout used by Apache HttpClient
ReadTimeout: 3000 # Read timeout used by Apache HttpClient
hystrix:
threadpool:
default:
coreSize: 50
maxQueueSize: 100
queueSizeRejectionThreshold: 50
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 10000
Run Code Online (Sandbox Code Playgroud)
我不确定出了什么问题.
这是技术问题吗?
或者我做出了错误的假设(我确实在某处读过POST没有重试过,我真的不明白)?
我很想听听你是怎么做到的.
谢谢,安迪
我也想知道这个问题。我不会声称自己在“愤怒中”使用过 Spring Cloud。我刚刚尝试了一段时间。
假设:我们假设所有实例状态的真实来源都存储在Eureka中,那么Eureka应该是我们的操作控制机制。我们可以使用 Eureka 通过将实例状态设置为 来停止实例的服务OUT_OF_SERVICE。当 Ribbon 刷新其服务器列表时,它不会使用这些停止服务的实例。Eureka 提供了 REST API 用于查询实例和设置实例状态。伟大的。
问题是:如何识别哪些实例在蓝色组中,哪些实例在绿色组中?
我在想... Eureka 为每个实例提供一个元数据映射。假设在构建/烘焙步骤中我们在元数据映射中设置了版本 ID?我们可以使用 Git 提交 ID 或某种语义版本控制方案等。好的,现在我可以查看 Eureka 元数据,并根据该版本值识别蓝色实例和绿色实例。我们可以使用属性设置每个服务中的元数据值。
例如eureka.instance.metadataMap.version=8675309
现在如果我们能告诉尤里卡就好了。“停止使用 FUBAR 服务和版本 8675309 的所有实例。” 嗯,我不认为这是开箱即用的。Spring Cloud 的酷之处在于,所有这些服务,包括 Eureka Server,都是 Spring 应用程序,我们可以根据自己的需求进行修改。下面的代码公开了一个端点,该端点根据应用程序名称和版本将实例设置为“停止服务”。只需将此控制器添加到您的尤里卡服务器即可。它还没有准备好生产,只是一个想法。
现在,一旦 Eureka 使这些实例停止服务并且 Ribbon 刷新其服务器列表,就可以安全地终止或路由离开这些实例。
发布到:
http://[eurekahost:port]/takeInstancesOutOfService?applicationName=FOOBAR&version=8675309
Run Code Online (Sandbox Code Playgroud)
希望有帮助吗?
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
import com.netflix.discovery.shared.Application;
import com.netflix.eureka.EurekaServerContextHolder;
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
@RestController
public class EurekaInstanceStateController {
@RequestMapping(value="/instancesQuery", method=RequestMethod.POST)
public Collection<String> queryInstancesByMetaData(
@RequestParam("applicationName") String applicationNameCriteria,
@RequestParam("version") String versionCriteria)
{
return getRegistry().getSortedApplications()
.stream()
.filter(hasApplication(applicationNameCriteria))
.flatMap(app -> app.getInstances().stream())
.filter(hasVersion(versionCriteria))
.map(info -> info.getAppName() + " - " + info.getId() + " - " + info.getStatus() + " - " + info.getMetadata().get("version"))
.collect(Collectors.toList());
}
@RequestMapping(value="/takeInstancesOutOfService", method=RequestMethod.POST)
public Collection<String> takeInstancesOutOfService(
@RequestParam("applicationName") String applicationNameCriteria,
@RequestParam("version") String versionCriteria)
{
return getRegistry().getSortedApplications()
.stream()
.filter(hasApplication(applicationNameCriteria))
.flatMap(app -> app.getInstances().stream())
.filter(hasVersion(versionCriteria))
.map(instance -> updateInstanceStatus(instance, InstanceStatus.OUT_OF_SERVICE) )
.collect(Collectors.toList());
}
/**
* @param instance
* @return
*/
private String updateInstanceStatus(InstanceInfo instance, InstanceStatus status)
{
boolean isSuccess = getRegistry().statusUpdate(instance.getAppName(), instance.getId(),
status, String.valueOf(System.currentTimeMillis()),
true);
return (instance.getAppName() + " - " + instance.getId() + " result: " + isSuccess);
}
/**
* Application Name Predicate
* @param applicationNameCriteria
* @return
*/
private Predicate<Application> hasApplication(final String applicationNameCriteria)
{
return application -> applicationNameCriteria.toUpperCase().equals(application.getName());
}
/**
* Instance Version Predicate. Uses Eureka Instance Metadata value name "version".</br>
*
* Set / Bake the instance metadata map to contain a version value.</br>
* e.g. eureka.instance.metadataMap.version=85839c2
*
* @param versionCriteria
* @return
*/
private Predicate<InstanceInfo> hasVersion(final String versionCriteria)
{
return info -> versionCriteria.equals(info.getMetadata().get("version"));
}
private PeerAwareInstanceRegistry getRegistry() {
return EurekaServerContextHolder.getInstance().getServerContext().getRegistry();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2951 次 |
| 最近记录: |