当前位置: 首页 > 知识库问答 >
问题:

在PWS上使用SpringCloud/Netflix堆栈进行蓝色/绿色部署的典型方法是什么?

贺皓
2023-03-14

我正在尝试一种设置,该设置非常类似于此处图像中详细介绍的设置: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 . cloud foundry . org/dev guide/deploy-apps/blue-green . html

在我看来,这种方法与像Eureka这样的发现服务并不“兼容”。事实上,我的服务的新版本已在Eureka注册,甚至在我可以重新映射所有路由(CF路由器)之前就接收了流量。

这让我想到了另一种方法,在这种方法中,我依赖于Spring Cloud/Netflix中的故障切换机制

  1. 我启动了服务的新(向后兼容)版本。
  2. 当这个版本被Zuul/Eureka选中时,它开始获得50%的流量。
  3. 一旦我确认新版本正常工作,我就会删除“旧”实例。(我只需单击PWS中的“停止”按钮)

据我所知,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

我申请的一部分.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

我不知道哪里出了问题。

这是技术问题吗?

还是我做了错误的假设(我确实在某个地方读到过帖子无论如何都不会重试,我真的不明白)?

我很想听听你是怎么做到的。

谢了安迪

共有1个答案

傅兴平
2023-03-14

我也想知道这一点。我不会声称使用过“愤怒的春云”。我刚刚尝试了一段时间。

假设:我们假设所有实例状态的真实来源都存储在Eureka中,那么Eureka应该是我们的操作控制机制。我们可以使用Eureka通过将实例状态设置为< code>OUT_OF_SERVICE来使实例停止服务。当Ribbon刷新其服务器列表时,它不会使用这些停止服务的实例。Eureka为查询实例和设置实例状态提供了一个REST API。太好了。

问题是:如何识别哪些实例在蓝色组中,哪些实例在绿色组中?

我在想...Eureka为每个实例提供了一个元数据地图。假设在构建/烘焙步骤中,我们在元数据映射中设置了一个版本id?我们可以使用Git提交Id或者某种语义版本控制方案或者其他什么。好了,现在我可以查看Eureka元数据,并在给定版本值的情况下识别蓝色和绿色实例。我们可以使用属性设置每个服务中的元数据值。

eureka.instance.metadataMap.version=8675309

如果我们能告诉尤里卡就好了。“取消FUBAR服务和8675309版本的所有实例。”嗯,我不认为这是现成的。Spring Cloud最酷的地方在于,所有这些服务,包括Eureka Server,都只是我们可以根据自己的需要破解的Spring应用程序。下面的代码公开了一个endpoint,该endpoint将实例设置为给定应用程序名称和版本的“停止服务”。只需将此控制器添加到Eureka服务器。它还没有准备好生产,只是一个想法。

现在,一旦Eureka停止这些实例的服务,Ribbon刷新其服务器列表,就可以安全地终止或路由这些实例。

发布到:

http://[eurekahost:port]/takeInstancesOutOfService?applicationName=FOOBAR&version=8675309

希望这有帮助?

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();
    }
}
 类似资料:
  • 有没有一种方法可以轻松地将给定的十六进制颜色代码分配给更一般的类别(红色、绿色、蓝色、黄色、橙色、粉色、黑色、白色、灰色...)? 比如- 编辑:甚至与adobe photoshop类似,找到最接近的网络安全颜色,这样可以将颜色数量减少到256种,这已经是一个很好的解决方案了!

  • 问题内容: 该方法返回单个int。如何分别获得红色,绿色和蓝色作为0到255之间的值? 问题答案: Java的Color类可以进行转换:

  • 做一个Sylvain Ratabouil Android NDK(第二版)的例子,从相机获得图像预览,并对其进行本地处理,从YUV转换为RGB,并对其应用滤色器。 代码非常简单,问题发生在传递给这个函数的过滤器中: 目标是对ImageView的引用 源是帧预览数据 过滤器是彩色过滤器 *为红色图像用0xFFFF0000改变0xFF0000FF滤镜,反之亦然。 在本机部分中,它所做的只是用位运算符和

  • 如果知道红色、绿色和蓝色的“权重”,可以使用以下类创建颜色: 并在HTML中使用它,如下所示: 对于上面显示的值,为暗灰色,为白色。 但是,如果一个人想要代表其他颜色的组合,比如绿色、蓝色、橙色和金色,该怎么办? 有没有一种方法可以用下面这样的符号来定义这样的颜色? 或者使用,其中中的字母分别代表绿色、蓝色、橙色和金色? 其目的是通过上面的CSS定义 将以这四种颜色的加权组合显示文本。 我相信这是

  • 问题内容: 我的用例需要一个数据结构。我应该能够将项目推送到数据结构中,而我只想从堆栈中检索最后一个项目。该堆栈的JavaDoc说: Deque接口及其实现提供了一组更完整和一致的LIFO堆栈操作,应优先使用此类。例如: 我绝对不希望这里出现同步行为,因为我将使用方法本地的数据结构。除了这个,我为什么还要在这里呢? PS:Deque的Javadoc说: 双端队列也可以用作LIFO(后进先出)堆栈。

  • 问题内容: 我想了解这类线程提供的优势。 在哪些环境中,绿色线程比非绿色线程更好?有人说绿色线程更适合多核处理器。 任何预期的行为问题。 问题答案: 绿色线程是“用户级线程”。它们是由“普通”用户级进程而不是内核调度的。因此,它们可用于在不提供该功能的平台上模拟多线程。 特别是在Java上下文中,绿色线程已成为过去。请参见《JDK 1.1 for Solaris开发人员指南》。(这是关于Solar