滚动升级

更新时间:
2024-01-11
下载文档

滚动升级

滚动升级是指在不中断服务的情况下,对应用程序进行升级,是 ECSM 中的一种重要功能。ECSM 会根据用户的要求,逐步将旧版本的微服务逐步替换为新版本的微服务,直到所有的微服务都已经被更新为止。通过滚动升级的方式可以减少服务中断的时间,同时也保证了应用程序的稳定性。

操作须知

ECSM 实现的滚动升级需要配置负载均衡中的轮询模式。负载均衡可以保证在服务升级过程中,业务不中断。当升级其中一个节点上的服务时,业务切换到另一个节点服务上。服务升级完成后,开始升级另一个节点上服务,业务重新切换到已经升级完成的节点服务上。

前提条件

在学习本章节前需要完成如下功能的学习,本章节在操作步骤中只做关键步骤说明:

代码示例

  1. 本章节滚动升级功能服务端模拟陀螺仪传感器场景,客户端订阅陀螺仪位置数据。通过查看客户端在服务端升级前后接收的数据格式对比,展示滚动升级的功能。

  2. 服务端提供两个版本的代码示例 axisSer1.0.0axisSer2.0.0 分别使用普通发布接口和快速发布接口,同时发布内容也有区别,具体差异请查看代码和最终运行结果。

  3. 客户端代码示例 axisCli 只订阅数据并在终端输出。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <pthread.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include "vsoa_server.h"
    #include "vsoa_platform.h"
    
    #define MY_SERVER_PASSWD  "123456"
    #define AXIS_SER_BUF_LEN  100
    #define AXIS_SER_PORT     3002
    #define AXIS_SER_AUTO_PORT "VSOA_AUTO_PORT="
    #ifndef TRUE
    #define TRUE              1
    #endif
    
    static vsoa_server_t *axisServer;
    
    /*
    * Publish axis thread
    */
    static void *publish_axis_thread (void *arg)
    {
        vsoa_url_t url;
        int roll, pitch,yaw;
        vsoa_payload_t payload;
        char param[AXIS_SER_BUF_LEN + 1];
    
        url.url     = "/axis";
        url.url_len = strlen(url.url);
    
        payload.data = NULL;
        payload.data_len  = 0;
        payload.param = param;
    
        roll  = 1;
        pitch = 1;
        yaw   = 1;
        while (TRUE) {
            sleep(1);
    
            if (!vsoa_server_is_subscribed(axisServer, &url)) {
                continue;
            }
    
            payload.param_len = snprintf(param, AXIS_SER_BUF_LEN,
                                        "{\"roll\": %d, \"pitch\": %d, \"yaw\": %d}",
                                        roll++, pitch++, yaw++);
    
            vsoa_server_publish(axisServer, &url, &payload);
        }
    
        return (NULL);
    }
    
    int main (int argc, char **argv)
    {
        uint16_t server_port = AXIS_SER_PORT;
        struct sockaddr_in addr;
    
        char *axis_serv_auto_port = getenv(AXIS_SER_AUTO_PORT);
        if (axis_serv_auto_port != NULL) {
            fprintf(stdout, "axis_ser port is %s .\n", axis_serv_auto_port);
            server_port = atoi(axis_serv_auto_port);
            if (server_port == 0) {
                server_port = AXIS_SER_PORT;
            }
        }
    
        memset(&addr, 0, sizeof(struct sockaddr_in));
        addr.sin_family      = AF_INET;
        addr.sin_port        = htons(server_port);
        addr.sin_addr.s_addr = INADDR_ANY;
    
    #ifdef VSOA_HAS_SIN_LEN
        addr.sin_len = sizeof(struct sockaddr_in);
    #endif
    
        /*
        * Initialize server
        */
        axisServer = vsoa_server_create("{\"name\":\"axis_server\"}");
        if (!axisServer) {
            fprintf(stderr, "Can not create VSOA server!\n");
            return  (-1);
        }
    
        /*
        * If need password
        */
        vsoa_server_passwd(axisServer, MY_SERVER_PASSWD);
    
        /*
        * Start server
        */
        if (!vsoa_server_start(axisServer, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) {
            vsoa_server_close(axisServer);
            fprintf(stderr, "Can not start VSOA server!\n");
            return  (-1);
        }
    
        fprintf(stderr, " start VSOA server success!\n");
    
        /*
        * Create publish thread
        */
        pthread_t pubThreadid;
        int threadRet = pthread_create(&pubThreadid, NULL, publish_axis_thread, NULL);
        if (threadRet) {
            fprintf(stderr, " create publish thread fail errno is %d!\n", errno);
            return (-1);
        }
    
        /*
        * set 1s timeout
        */
        struct timespec timeout = {1, 0};
    
        int cnt, max_fd;
        fd_set fds;
    
        while (TRUE) {
            FD_ZERO(&fds);
            max_fd = vsoa_server_fds(axisServer, &fds);
    
            cnt = pselect(max_fd + 1, &fds, NULL, NULL, &timeout, NULL);
            if (cnt > 0) {
                vsoa_server_input_fds(axisServer, &fds);
            }
        }
    
        return (0);
    }
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <pthread.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include "vsoa_server.h"
    #include "vsoa_platform.h"
    
    #define MY_SERVER_PASSWD  "123456"
    #define AXIS_SER_BUF_LEN  100
    #define AXIS_SER_PORT     3002
    #define AXIS_SER_AUTO_PORT "VSOA_AUTO_PORT="
    #ifndef TRUE
    #define TRUE              1
    #endif
    
    static vsoa_server_t *axisServer;
    
    /*
    * Publish axis thread
    */
    static void *publish_axis_thread (void *arg)
    {
        vsoa_url_t url;
        int roll, pitch,yaw;
        vsoa_payload_t payload;
        char param[AXIS_SER_BUF_LEN + 1];
    
        url.url     = "/axis";
        url.url_len = strlen(url.url);
    
        payload.data = NULL;
        payload.data_len  = 0;
        payload.param = param;
    
        roll  = 1;
        pitch = 1;
        yaw   = 1;
        while (TRUE) {
            sleep(1);
    
            if (!vsoa_server_is_subscribed(axisServer, &url)) {
                continue;
            }
    
            payload.param_len = snprintf(param, AXIS_SER_BUF_LEN,
                                        "{\"ROLL\": %d, \"PITCH\": %d, \"YAW\": %d}",
                                        roll++, pitch++, yaw++);
            roll  += 10;
            pitch += 10;
            yaw   += 10;
            vsoa_server_quick_publish(axisServer, &url, &payload);
        }
    
        return (NULL);
    }
    
    int main (int argc, char **argv)
    {
        uint16_t server_port = AXIS_SER_PORT;
        struct sockaddr_in addr;
    
        char *axis_serv_auto_port = getenv(AXIS_SER_AUTO_PORT);
        if (axis_serv_auto_port != NULL) {
            fprintf(stdout, "axis_ser port is %s .\n", axis_serv_auto_port);
            server_port = atoi(axis_serv_auto_port);
            if (server_port == 0) {
                server_port = AXIS_SER_PORT;
            }
        }
    
        memset(&addr, 0, sizeof(struct sockaddr_in));
        addr.sin_family      = AF_INET;
        addr.sin_port        = htons(server_port);
        addr.sin_addr.s_addr = INADDR_ANY;
    
    #ifdef VSOA_HAS_SIN_LEN
        addr.sin_len = sizeof(struct sockaddr_in);
    #endif
    
        /*
        * Initialize server
        */
        axisServer = vsoa_server_create("{\"name\":\"axis_server\"}");
        if (!axisServer) {
            fprintf(stderr, "Can not create VSOA server!\n");
            return  (-1);
        }
    
        /*
        * If need password
        */
        vsoa_server_passwd(axisServer, MY_SERVER_PASSWD);
    
        /*
        * Start server
        */
        if (!vsoa_server_start(axisServer, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) {
            vsoa_server_close(axisServer);
            fprintf(stderr, "Can not start VSOA server!\n");
            return  (-1);
        }
    
        fprintf(stderr, " start VSOA server success!\n");
    
        /*
        * Create publish thread
        */
        pthread_t pub_threadid;
        int threadRet = pthread_create(&pub_threadid, NULL, publish_axis_thread, NULL);
        if (threadRet) {
            fprintf(stderr, " create publish thread fail errno is %d!\n", errno);
            return (-1);
        }
    
        /*
        * set 1s timeout
        */
        struct timespec timeout = {1, 0};
    
        int cnt, max_fd;
        fd_set fds;
    
        while (TRUE) {
            FD_ZERO(&fds);
            max_fd = vsoa_server_fds(axisServer, &fds);
    
            cnt = pselect(max_fd + 1, &fds, NULL, NULL, &timeout, NULL);
            if (cnt > 0) {
                vsoa_server_input_fds(axisServer, &fds);
            }
        }
    
        return (0);
    }
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #ifdef SYLIXOS
    #include <sys/vproc.h>
    #endif
    #include "vsoa_cliauto.h"
    
    /* My server password */
    #define MY_SERVER_PASSWD "123456"
    #ifndef TRUE
    #define TRUE              1
    #endif
    
    /* My client */
    static vsoa_client_t *client;
    
    /* My client auto */
    static vsoa_client_auto_t *cliauto;
    
    /* My subscribe (string pointer array) */
    static char * const sub_urls[] = { "/axis" };
    
    static void onconnect (void *arg, vsoa_client_auto_t *cliauto, bool connect, const char *info)
    {
        printf("On connect, connect: %s, info: %s\n",
                (connect == true) ? "connected" : "disconnected", info);
    }
    
    /*
    * On subscribed messages received
    */
    static void onmessage (void *arg, struct vsoa_client *client, vsoa_url_t *url, vsoa_payload_t *payload, bool quick)
    {
        printf("On message, URL: %.*s payload: %.*s\n",
            (int)url->url_len, url->url, (int)payload->param_len, payload->param);
    }
    
    /*
    * main function
    */
    int main (int argc, char **argv)
    {
    #ifdef SYLIXOS
        vprocExitModeSet(getpid(), LW_VPROC_EXIT_FORCE);
    #endif
    
        /*
        * Create client auto robot
        */
        cliauto = vsoa_client_auto_create(onmessage, NULL);
        client  = vsoa_client_auto_handle(cliauto);
    
        if (!vsoa_client_auto_setup(cliauto, onconnect, NULL)) {
            vsoa_client_auto_delete(cliauto);
            fprintf(stderr, "Cannot register connect callback: %s (%d)\n", strerror(errno), errno);
            return -1;
        }
    
        /*
        * Client auto robot start
        * The robot will automatically connect to the specified server and maintain the connection.
        * At this time, the developer only needs to focus on the business.
        */
        vsoa_client_auto_start(cliauto, "vsoa://axis_server", MY_SERVER_PASSWD,
                            sub_urls, 1, 1000, 1000, 1000);
    
        while (TRUE) {
            sleep(1);
        }
    }
    
    

操作步骤

部署容器镜像

  1. 在容器部署页面,单击服务列表左上方的新建,进入新建容器部署页面的基本信息界面。

  2. 单击下一步,进入选择节点界面。

  3. 根据页面提示选择节点。

  4. 在资源配置界面,设置容器的资源配置参数,并单击部署,进入完成界面。

  5. 完成容器部署,新部署的容器会显示在容器部署页面的服务列表中。

  6. 通过相同的方式部署冗余服务镜像。

  7. 运行客户端程序,发起服务订阅。

配置负载均衡

  1. 服务治理页面,单击负载均衡,进入负载均衡模式配置页面。

  2. 点击轮询,完成负载均衡配置。

升级容器镜像

步骤 1:升级 axis_ser2 容器镜像

  1. 在容器部署页面,点击需要升级服务的右侧详情,进入详情页面。

  2. 点击修改,在容器部署的基本信息界面,选择新版本容器镜像。

  3. 根据提示信息,完成容器部署。

  4. 查看客户端回显页面,服务没有中断。

步骤 2:升级 axis_ser1 容器镜像

  1. 参考步骤 1 的升级方式,升级下一个服务,最终完成服务的滚动升级。

  2. 查看客户端回显页面,客户端已经订阅到新版本数据。

文档内容是否对您有所帮助?
有帮助
没帮助