微服务Tars入门以及踩坑记录

微服务Tars入门以及踩坑记录

     什么是微服务

      近几年,微服务这个词闯入我们的视线范围。通常跟微服务相对的是单体应用,即将所有功能都打包成在一个独立单元的应用程序。微服务的架构就是将单个应用程序划分成各种小的、互相连接的微服务,一个微服务完成一个比较单一的功能,相互之间保持独立和解耦合。不同服务内部的开发技术可以不一致。

      当然,拆分成多个服务,关于服务的管理也引出了一系列问题。为了解决这些问题,提出了一系列概念:服务注册与发现、服务监控、服务治理等等。微服务的这些问题可以通过引入微服务框架来帮助我们去解决。

      目前业界比较成熟的微服务框架有阿里的Dubbo、Pivotal公司的Spring Cloud、腾讯的Tars、google的gRPC等等。

      我这里选择Tars作为入门学习的微服务框架。学习过程中,发现这跟我平时使用的PHP框架很不一样,除了要学习使用TarsPHP这一开发框架,微服务的环境部署和发布节点之外,还涉及到很多网络、服务器方面的知识。都是自己所欠缺需要恶补的。而且还需要考虑服务边界的划分服务与服务之间是如何调用的。

     发布节点时报错

      使用docker-compose进行部署,发布节点的时候遇到问题: 出现batchPatch err:NodeImp.cpp:patchPro:111| error:ip 172.25.0.1 is invalid错误

      

      看似一个ip无效的报错,其实涉及到容器通信方面,必须先了解很多关于网络的知识,才能逐一排查错误原因。这里就所涉及到的知识进行一个梳理,然后再排查分析。

    docker 网络

     1.  docker network操作

     先查看下docker针对网络有哪些操作,使用命令:docker  network  --help

     

    比如create命令:

    # 创建一个名为tars的桥接(bridge)虚拟网络,网关172.25.0.1,网段为172.25.0.0

    使用命令:docker network create -d bridge --subnet=172.25.0.0/16 --gateway=172.25.0.1 tars

    我们也可以使用命令查看创建网络的可选配置项:docker network create --help

    如下图:

 

   2.  docker的网络模式

   安装 Docker 以后,会默认创建三种网络,可以通过 docker network ls 查看:

   

   1)bridge(桥接模式)

   桥接模式是docker 的默认网络设置,当docker服务启动时,会在主机上创建一个名为docker0的虚拟以太网桥,并选择一个和宿主机不同的IP地址和子网分配给docker0网桥。

   示意图:

    

    网络模式选择桥接模式的容器,就会连接上docker0这个网桥,再通过nat的转换,通过宿主机的网卡,连接外网,就能达到上外网的目的。

    默认情况下,守护进程会创建一对对等虚拟设备接口 veth pair,将其中一个接口设置为容器的 eth0 接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似 vethxxx 这样的名字命名,从而将宿主机上的所有容器都连接到这个内部网络上。

    这里,我启动了三个容器mysql、tars-node ,tars-framework,就会有三个容器网卡,以及一个docker0虚拟网卡,这三个容器网卡都会桥接到docker0网卡,docker0网卡与物理机网卡连接使用的是nat技术,如下图:

    使用命令:ip addr (ip a 或  ip add list),查看网卡状态

       

     使用命令查看bridge模式的详细信息:docker network inspect bridge

     

     2)host模式

      该模式下容器是不会拥有自己的ip地址,而是使用宿主机的ip地址和端口。这种模式的好处就是网络性能比桥接模式的好。缺点就是会占用宿主机的端口,网络的隔离性不太好

      

3)none

      none模式没有IP地址,无法连接外网,等于就是断网的状态,作用就是用于测试,生产环境一般不会用到这种

4)container

     新创建的容器不会创建自己的网卡和配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。 

3.  docker-compose.yml文件分析

 1 version: "3"
 2 
 3 services:
 4   mysql:
 5     image: mysql:5.6
 6     container_name: compose-tars-mysql
 7     ports:
 8       - "3307:3306"
 9     restart: always
10     environment:
11       MYSQL_ROOT_PASSWORD: "123456"
12     volumes:
13       - ./mysql/data:/var/lib/mysql:rw
14       - ./source/Shanghai:/etc/localtime
15     networks:
16       internal:
17         ipv4_address: 172.25.1.2
18   framework:
19     image: tarscloud/framework:v2.4.0
20     container_name: compose-tars-framework
21     ports:
22       - "3000:3000"
23       - "3001:3001"
24     restart: always
25     networks:
26       internal:
27         ipv4_address: 172.25.1.3
28     environment:
29       MYSQL_HOST: "172.25.1.2"
30 #      MYSQL_HOST: "123.56.***.184"
31       MYSQL_ROOT_PASSWORD: "123456"
32       MYSQL_USER: "root"
33       MYSQL_PORT: 3306
34 #      MYSQL_PORT: 3307
35       REBUILD: "false"
36       INET: eth0
37       SLAVE: "false"
38     volumes:
39       - ./framework/data:/data/tars:rw
40       - ./source/Shanghai:/etc/localtime
41     depends_on:
42       - mysql
43   node:
44     image: tarscloud/tars-node:latest
45     container_name: compose-tars-node
46     restart: always
47     networks:
48       internal:
49         ipv4_address: 172.25.1.5
50     volumes:
51       - ./node/data:/data/tars:rw
52       - ./source/Shanghai:/etc/localtime
53     environment:
54       INET: eth0
55       WEB_HOST: http://172.25.1.3:3000
56 #      WEB_HOST: http://123.56.***.184:3000
57     ports:
58       - "9000-9009:9000-9009"
59     depends_on:
60       - framework
61 networks:
62   internal:
63     driver: bridge
64     ipam:
65       config:
66         - subnet: 172.25.1.0/16

    depends_on:定义容器启动顺序 (此选项解决了容器之间的依赖关系)

    4.   IP、网段、子网掩码(网络掩码)

        从上面看到networks的设置中,网段为172.25.1.0/16,这里面就涉及到ip、相同网段、网络掩码的相关知识。

        1)什么是IP地址

        IP地址相当于网络中的身份唯一认证ID,跟身份证ID一样是唯一的,唯一不同的是,IP地址是可以变的,只是不管怎么变,都将会是唯一的。Mac地址的性质更加接近于身份证ID,它是设备的唯一ID。

        IP地址目前普遍是IPv4版本,由32位二进制数分成4组,每组1字节Byte(8Bit)组成。分别用十进制表示再用圆点隔开,就是现在的172.25.1.0。

        2)IP地址的构成

        IP地址 = 网络地址 + 主机地址

        比如:192.168.1.168(IP地址) = 192.168.1.0 (网络地址) + 0.0.0.168(主机地址)

        网络地址、主机地址是怎么计算出来的呢?就需要先简单学习下子网掩码

        3)子网掩码(subnet mask)

        比如这里的172.25.1.0/16中的16,指的是子网掩码的长度,16代表16个1,用子网掩码来表示,就是:255.255.0.0。它的作用主要是用来区分网络地址和主机地址。

        将ip地址转为二进制,子网掩码转为二进制,通过按位与最终得到网段号。根据按位与的特性,可以看到172.25这个网段是不变的,后面的都可以改变。

    排查错误原因

    下面我们就开始提到用TarsDocker部署后,针对发布节点时遇到的错误进行排查分析。

    分析:这个错误是这台机器上的tarnode识别过来的发布请求的非法,不是tarsAdminRegistry的ip。

    1)查看想要发布节点到的对应容器

    可以看到,这里发布的结点是172.25.1.5,我们是想通过这个ip发布到对应的容器tars-node

   

    现在我们来看下这个容器的详细信息:docker inspect containerid

    根据报错的信息:error:ip 172.25.0.1 is invalid,反应出tars找到的容器节点错误,找到的其实是网关,tars无法根据ip:172.25.0.1找到与它连接对应的容器,因此也就无法将服务发布到对相应容器。因此很快报ip无效的错误,流程根本都还没有走到检查打包的代码这一步。

    2) 考虑换成容器逐个启动的方式,看能否成功发布节点

    我先使用docker-compose down将启动的容器都卸载,然后用docker run将mysql、tars-node、tars-framework逐个启动

 1 docker run --name tars-mysql -e MYSQL_ROOT_PASSWORD='123456' -d -p 3307:3306 \
 2         -v/etc/localtime:/etc/localtime \
 3         -v /data/mysql-data:/var/lib/mysql mysql:5.6
 4 
 5 docker run -d \
 6     --name=tars-framework \
 7     -e MYSQL_HOST="123.56.***.184" \
 8     -e MYSQL_ROOT_PASSWORD="123456" \
 9     -e MYSQL_USER=root \
10     -e MYSQL_PORT=3307 \
11     -e REBUILD=false \
12     -e SLAVE=false \
13     -e INET=eth0 \
14     -p 3000:3000 \
15     -p 3001:3001 \
16     -v /etc/localtime:/etc/localtime \
17     -v /tmp/test/data:/data/tars \
18     tarscloud/framework:v2.4.0
19     
20 docker run -d \
21     --name=tars-node \
22     -e INET=eth0 \
23     -e WEB_HOST="http://123.56.***.184:3000" \
24     -p "9000-9010:9000-9010" \
25     -v /data/tars:/data/tars \
26     -v /etc/localtime:/etc/localtime \
27     tarscloud/tars-node:latest
28     

     这里将服务部署和发布节点的流程走一遍,可以发布成功。于是进行分析:

     容器通信的两种方式

     1)不需要给容器建立虚拟网络,直接通过eth0,也就是宿主机的外网环境直接访问

     2)容器的虚拟网络,通过暴露端口给宿主机映射的端口,通过宿主机+映射的端口访问。

     这个地方用单个容器逐一启动,发布节点时能把服务成功发布到相应容器,容器之间的通信是通过宿主机的外网环境直接访问。

     经过反复排查,最终定位到问题到docker的网络设置不对,导致发布时tarnode获得的ip地址是网关地址172.25.0.1,而不是容器的网络地址,因而无法发布服务到相应的容器。

     我这边使用的是阿里云服务器,通过重启云服务器,以及重新启动docker。恢复正常。

    TarsDocker重新部署

    1.  重新部署,然后发布节点

    docker-compose up 不加-d,我们来看下容器启动的流程

    

    可以看到,一个容器要等待它所依赖的其他容器启动成功后,才能够启动。这期间开启着定时任务,一直在尝试着启动各个容器,串行执行。

    启动之后,通过宿主机地址+端口访问,注意右上角是tars-framework版本

    

    2.  运维管理-服务部署

     

    3. 发布节点

    

    

 

    4.  切换到服务管理,刷新下页面

    

      5.  输入地址,访问下运行的服务

      

     Ok,发布成功了,服务正常运行,并且能够成功访问了。

     部署和发布的过程中可能会遇到各种各样的问题,有问题是好事,重点是我们要有足够的知识储备,去一步一步排查,分析原因,解决问题。

 

参考链接:

https://juejin.cn/post/6868086876751085581#heading-1

https://blog.csdn.net/qq_33355821/article/details/104173831

https://segmentfault.com/a/1190000022864573

https://doc.tarsyun.com/adminer/start/index.html#/tarsdoc/gateway/README.md 

posted @ 2021-02-25 17:11  欢乐豆123  阅读(2262)  评论(0编辑  收藏  举报