负载均衡
在高吞吐量,高并发的场景中,单节点部署服务镜像容易受到硬件设备资源的限制而导致服务不可用,针对此场景 ECSM 提供了负载均衡的功能。负载均衡可以将服务的负载分配到多个节点单元上,提高了系统的性能和可靠性。当某个节点出现故障时,负载均衡器可以自动将负载转移到其他正常工作的节点上,确保服务的不间断运行。
操作须知
本章节通过配置负载均衡的轮询模式介绍负载均衡的功能。轮询模式是指调度器对每一个客户端的请求通过轮询的模式在多个服务端依次调度。
前提条件
在学习本章节前需要完成如下功能的学习,本章节在操作步骤中只做关键步骤说明:
开发示例
本次负载均衡功能服务端模拟陀螺仪传感器场景,客户端订阅陀螺仪位置数据。通过查看服务端和客户端的输出信息,展示负载均衡的功能。
服务端的代码示例 server 模拟陀螺仪位置信息,当客户端订阅成功后,输出客户端的连接请求,同时发送陀螺仪的位置信息。
客户端代码示例 client 只订阅数据并在终端输出。
#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); } void oncli(void *arg, vsoa_server_t *server, vsoa_cli_id_t id, bool connect) { if (connect) { printf("[server]: Accept a client connect request, client id is %d. \n", id); } } 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"); vsoa_server_on_cli(server, oncli, NULL); /* * 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 <unistd.h> #include <errno.h> #ifdef SYLIXOS #include <sys/vproc.h> #endif #include "vsoa_cliauto.h" /* My server password */ #define MY_SERVER_PASSWD "123456" /* 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); } }
操作步骤
部署容器镜像
在容器部署页面,单击服务列表左上方的新建,进入新建容器部署页面的基本信息界面。
单击下一步,进入选择节点界面。
根据页面提示选择节点。
在资源配置界面,设置容器的资源配置参数,并单击部署,进入完成界面。
完成容器部署,新部署的容器会显示在容器部署页面的服务列表中。
通过相同的方式部署 server2、client1 和 client2。
说明:
客户端镜像 clien1 和 client2 在部署阶段只加载不运行,需要在负载均衡验证阶段手动触发。
配置负载均衡
在左侧导航栏单击服务治理,进入服务治理页面。
在服务治理页面,选择需要配置负载均衡的微服务,单击其操作栏的负载均衡,打开负载均衡策略窗口。
选择轮询,并点击确认。
设置完成后可在服务治理页面查看设置结果。
触发负载均衡
选中 client1,点击启动,触发一个连接请求。
查看服务端 server1 的连接情况,如下图所示客户端 client1 连接到 server1。
查看客户端的数据订阅情况,如下图表示客户端成功连接并且成功获取数据。
选中 client2,点击启动,触发第二个连接请求。
查看服务端 server2 的连接情况,如下图所示客户端 client2 连接到 server2 。
查看 client2 的数据订阅情况,如下图表示客户端成功连接并且成功获取数据。