微服务|微服务总结(一)
-
- 微服务总结(一):单点登录
- 什么是单点登录
- 单点登录的负载均衡模式
- 具体实现
- ctrl 的流程
- work 的流程
- 微服务总结(一):单点登录
微服务总结(一):单点登录 什么是单点登录
首先,对于微服务来说,所有服务的请求是需要一个入口的,这个入口用于处理请求的分发,将不同服务的请求映射到不同的进程上去。
从另一点来讲,大部分的系统是需要经过身份认证和授权的。通俗一点就是有个登陆的过程。对于单体应用来讲,由于所有的请求都是由一个程序去处理的,所以本身也包含了登录和认证的过程。然而对于的微服务的架构,整体的功能被拆分成了多个服务,被部署在不同的服务器,不同的进程上。不可能访问每个微服务之前还要去走认证逻辑。因此这个入口除了分发请求还有一个单点登录的作用,用于整个系统的权限校验。
那么最简单的做法就是写一个请求分发的程序,但是如果是高并发的请求下,单靠一个进程是无法处理的,因此这里通常会做成负载均衡的模式。
单点登录的负载均衡模式
一个最简单的负载均衡模式是,一个ctrl 进程 + 多个work 进程,ctrl 进程相当于一个反向代理,接受所有用户的连接,然后将连接分发给work进程去处理连接。这里分发连接而不是分发请求,是因为ctrl 不需要关注具体的请求内容,这将降低ctrl 的工作量,而将请求的处理转移到 work 层。
文章图片
在Linux的网络编程中,服务端监听在某个端口需要经过如下几个步骤
- 申请一个 fd
int socket(int protofamily, int type, int protocol)
- 初始化要监听的地址和端口
intbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 开始监听
int listen(int sockfd, int backlog);
- 接受来自客户端的连接请求
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //返回连接 connect_fd
具体实现
具体应该怎么做?首先,明白 ctrl 和 work 之间是父子进程的关系。ctrl 仅仅是用于work 进程的管理。而work 进程的个数要做成可配置的,ctrl 根据配置来决定启用的 work 进程数。ctrl 和 work 之间的通信可以走RPC,由于在同一台主机上,可以使用 linux 的域套接字 unix-sock。
文章图片
ctrl 的流程
- 启动初始化
ctrl 启动之后主要做以下几个初始化操作:
- 初始化 ip 池,ip 的分发主要由 ctrl 控制,在 login 的回包里将 ip 带下去
int ctrl_ip_pool_init()
- 监听本地的域套接字端口,用于和 work 之间的通信,比如监听地址为
/tmp/ctrlunix.sock
int ctrl_app_ctrl_sock_init()
- 根据配置文件启动多个 work
这里先 kill 掉所有的 work 进程,然后 fork() 一个子进程,在子进程中调用 exev() 来启动 work ,再退出子进程。启动 work 的同时也为每个 work 启动一个定时器,定时发送 keeplive 心跳包。
static int __ctrl_start_app(ctrl_app_st *app) { if (app->path == NULL) return 0; int pid = fork(); BGOTO(pid != -1); if (pid != 0)/* 父进程 */ { app->pid = pid; return pid; } mstr_pointer2 pargs = NULL; if (app->args != NULL) { char *pbuf = (char *)MEM_ALLOC(strlen(app->path) + 2 + strlen(app->args)); sprintf(pbuf, "%s %s", app->path, app->args); moa_split_string(pbuf, ' ', &pargs); } execv(app->path, pargs); exit(1); return 0; FAILED: return -1; }
- 初始化 ip 池,ip 的分发主要由 ctrl 控制,在 login 的回包里将 ip 带下去
- 等待 work 连入
- 处理 work 的请求
LOGIN_REQUEST
: work 的 login 请求,每个work 启动之后会主动上报自己的存在。KEEPALIVE_RSPONSE
work回复的心跳包,用于和 work 保持联系。
? ctrl 内部会保存成功上报上来的 work 的信息,当上报上来的 work 的个数大于1 时,即表示至少有一个work 可以工作了,此时即可以向客户端开放服务了。
int32_t ctrl_user_sock_init(PBctrlApp *app, ctrl_app_man_st *man)
当客户端连上来的时候 ctrl 负责将 connectfd 下发给 work
static int __entry_cb(struct msock* ms) {//复制出 connectfd 然后发送给 work SOCKET fd = dup(moasock_get_fd(ms)); ctrl_man_send_work_fd(fd, listen_st->srvtype, listen_st->listen_type); sock_close(msock); return 0; }
这里具体选择发送给哪一个 work时,只做了一个简单的轮询
具体的发送fd 的请求是SEND_FD_REQ
int ctrl_man_send_work_fd(SOCKET fd, mh_servertype type, uint32_t listen_type) { ctrl_app_man_st *man = NULL; int cnt = 0; if (s_ctrl_man.app_hash == NULL) return -1; hash_search(s_ctrl_man.app_hash, &type, sizeof(type), (void **)&man); if (man == NULL || man->runing_app <= 0) return -1; do {/* 轮询做业务负载,当连接比较多的时候,轮询基本能达到平均*/ man->poll_index = (man->poll_index + 1) % man->n_apps; cnt++; } while (man->apps[man->poll_index].status != AS_RUNNING && cnt < man->n_apps); if (man->apps[man->poll_index].status != AS_RUNNING) return -1; return ctrl_app_ctrl_send_fd(&man->apps[man->poll_index], fd, listen_type); }
- 初始化
- 启动之后第一步就是上报 ctrl 自己的存在,即主动连接 ctrl 在初始化步骤2 中监听的本地域套接字地址,并在连接成功之后即发送 login 请求。
__ctrl_login_req(msrv);
在连接的回包里有以下的几种请求:
LOGIN_RESPONSE
login的回包
【微服务|微服务总结(一)】KEEPALIVE_REQ
来自 ctrl 的心跳包:主要与work保活
SEND_FD_REQ
来自 ctrl 下发的客户端 connectfd
static int __ctrl_assign_fd(mserver *msrv, PBSrvHead *sh, mpacket *pk)
intusr_sock_attach(long fd)
static void __user_stcp_peek_recv(cl_tcp*sock,char *buf,int nread,int err,void* data)
然后是根据 connectfd 的类型是 tcp 还是 ssl 进行不同的初始化,将 server attach 到该 fd 上,就可以收到来自客户端的包了。
- login 请求的处理
未完待续
- 启动之后第一步就是上报 ctrl 自己的存在,即主动连接 ctrl 在初始化步骤2 中监听的本地域套接字地址,并在连接成功之后即发送 login 请求。
推荐阅读
- 7.9号工作总结~司硕
- 基于微信小程序带后端ssm接口小区物业管理平台设计
- CET4听力微技能一
- 微习惯复盘
- 社保代缴公司服务费包含哪些
- 员工的微信朋友圈是公司的宣传阵地吗()
- 私有化轻量级持续集成部署方案--03-部署web服务(下)
- 最有效的时间管理工具(赢效率手册和总结笔记)
- FBI怎么和恐怖分子谈判
- 探索免费开源服务器tomcat的魅力