微服务总结(一)

微服务总结(一):单点登录

什么是单点登录

首先,对于微服务来说,所有服务的请求是需要一个入口的,这个入口用于处理请求的分发,将不同服务的请求映射到不同的进程上去。

从另一点来讲,大部分的系统是需要经过身份认证和授权的。通俗一点就是有个登陆的过程。对于单体应用来讲,由于所有的请求都是由一个程序去处理的,所以本身也包含了登录和认证的过程。然而对于的微服务的架构,整体的功能被拆分成了多个服务,被部署在不同的服务器,不同的进程上。不可能访问每个微服务之前还要去走认证逻辑。因此这个入口除了分发请求还有一个单点登录的作用,用于整个系统的权限校验。

那么最简单的做法就是写一个请求分发的程序,但是如果是高并发的请求下,单靠一个进程是无法处理的,因此这里通常会做成负载均衡的模式。

单点登录的负载均衡模式

一个最简单的负载均衡模式是,一个ctrl 进程 + 多个work 进程,ctrl 进程相当于一个反向代理,接受所有用户的连接,然后将连接分发给work进程去处理连接。这里分发连接而不是分发请求,是因为ctrl 不需要关注具体的请求内容,这将降低ctrl 的工作量,而将请求的处理转移到 work 层。
这里写图片描述

在Linux的网络编程中,服务端监听在某个端口需要经过如下几个步骤

  1. 申请一个 fd

    int socket(int protofamily, int type, int protocol)
  2. 初始化要监听的地址和端口

    int  bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  3. 开始监听

    int listen(int sockfd, int backlog);
  4. 接受来自客户端的连接请求

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //返回连接 connect_fd

在第四步得到跟客户端的连接 fd 之后,此时 ctrl 程序会将该 fd 下发给work 进程,由work 进程来处理客户端的请求。

具体实现

具体应该怎么做?首先,明白 ctrl 和 work 之间是父子进程的关系。ctrl 仅仅是用于work 进程的管理。而work 进程的个数要做成可配置的,ctrl 根据配置来决定启用的 work 进程数。ctrl 和 work 之间的通信可以走RPC,由于在同一台主机上,可以使用 linux 的域套接字 unix-sock。
这里写图片描述

ctrl 的流程
  • 启动初始化

    ctrl 启动之后主要做以下几个初始化操作:

    1. 初始化 ip 池,ip 的分发主要由 ctrl 控制,在 login 的回包里将 ip 带下去

      int ctrl_ip_pool_init()
    2. 监听本地的域套接字端口,用于和 work 之间的通信,比如监听地址为 /tmp/ctrlunix.sock

      int ctrl_app_ctrl_sock_init()
    3. 根据配置文件启动多个 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;    
      }
  • 等待 work 连入

  • 处理 work 的请求

    1. LOGIN_REQUEST : work 的 login 请求,每个work 启动之后会主动上报自己的存在。
    2. KEEPALIVE_RSPONSE work回复的心跳包,用于和 work 保持联系。

    主要理解 login 请求的处理:

    ​ 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);
    }
work 的流程

work 的启动由ctrl 在第四步完成,启动之后进行初始化:

  • 初始化

    1. 启动之后第一步就是上报 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)
      int  usr_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 上,就可以收到来自客户端的包了。

    2. login 请求的处理

      未完待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值