文章目录

  • 前言
  • 一、商品模块分析
  • 二、场景分析
  • 三、高可用问题分析
  • 问题1:商品详情出现问题,需要其他服务器维护人员一起联调
  • 问题2:如果商品模块访问压力过大,会造成其他服务器性能页会收到影响
  • 四 、常见问题
  • 五、consul 商品服务部署
  • 1.部署多个server+多个client
  • 2.将商品服务,订单服务,秒杀等服务,注册到consul
  • 3.搭建一个consul集群
  • 3.1 加载镜像(镜像文件放在资源文件下)
  • 3.2构建docker-compose,内如如下:
  • 3.3. 构建consul客户端
  • 3.4 构建consul部署架构理解
  • 3.5 构建consul集群架构
  • 3.5 consul 服务发现原理及完整流程
  • 4.将商品服务自动注册和服务发现
  • 4.1. 拆分说明
  • 4.2 开发前的准备
  • 4.3 理解swoft的服务注册与发送功能的运用
  • 总结:



前言

consul介绍:

consul用于微服务下的服务治理,主要特点有:服务发现、服务配置、健康检查、键值存储、安全服务通信、多数据中心等。

什么叫服务治理发现?起初我们的服务比较单一,各服务之间通过接口就能访问。后面服务越来越复杂出现了分布式,为了不引起单点问题,必然是多服务部署,如果还用原来的方式直接连接,那么在某个服务挂掉或者修改了信息,就会导致连接失败。如果连接端能够不去关心具体的服务配置,他只要连接到那个服务,后续的工作由其它服务保证,包括负载均衡、健康检查等,保证总有可用的连接那就行了,consul就是做这个的,当然,它的功能远不止这些,这里只是以服务发现为例。

与它同类的东西,还有Eureka、zooKeeper、etcd等也能做这些事,说不上谁好谁坏,看场景挑合适的吧,不过Eureka现在已经闭源了,这个还是建议不要去用这个了。

本文主要针对商城系统为例,以swoft 为基础,对商品模块进行分析和实操。


一、商品模块分析

1.商品模块是商城的核心模块,重要度很高,因此高可必不少,

高可用比如mongodb,consul等,下边以consul为例:

mha mysql高可用 consul mysql高可用_mha mysql高可用


可以将商品详情单独拆分一个服务,实际场景中也是如此,这个实现起来很简单,增加商品详情服务然后注册到consul即可。

二、场景分析

商品有一个共同特点:查询多,插入少

对于商品详情及首页查询多,几乎无插入内容,我们可以考虑不同层面的策略以便于更好的提高查询效率,比如:浏览器缓存,客户端文件缓存,静态资源缓存,服务端nosql缓存。
下面列举缓存技术:
2.1使用浏览器缓存
2.2客户端应用缓存
2.3代理服务器开启缓存
2.4使用代理服务器(CND)
2.5使用镜像服务器
2.6使用p2p技术
2.7使用接入层提供的缓存机制
2.8使用应用层提供的缓存机制
2.9静态化,伪静态化
2.10使用服务器操作系统提供的缓存机制

三、高可用问题分析

商品数据来源与其他服务,例如:价格、店铺、活动、商品推荐、评价等,至少来源于两个以上的服务
如果我们正常的通过访问首页后者详情页去请求(mq、tcp)获取数据的话,频繁多次会消耗资源的同时,还会有较大的延迟时间问题。

问题1:商品详情出现问题,需要其他服务器维护人员一起联调

问题2:如果商品模块访问压力过大,会造成其他服务器性能页会收到影响

针对这个问题提供一个解决方案:数据闭环

方案1:采用数据聚合,将其他服务和模块的数据聚合到mongodb下,前端请求mongodb获得聚合数据,下边是聚合过程

mha mysql高可用 consul mysql高可用_mha mysql高可用_02

四 、常见问题

问题1:有些数据更新少,有些数据更新频繁,对一些用户来说,实时性要求也不一,有些数据需要请求后同步返回,而有些数据需要加载完后,在通过浏览器异步返回。
解决方案1:采用数据异构,将不同维度的数据存入不同的redis地址,
注意:一个商品详情的数据,异构后的多个redis数据,聚合到mongodb
问题2:查询量波动比较大,可能会造成不可控制项
解决方案2:采用集群的线性拓展

下面是具体的mongodb+consul设计方案:

mha mysql高可用 consul mysql高可用_数据中心_03

五、consul 商品服务部署

1.部署多个server+多个client

mha mysql高可用 consul mysql高可用_Server_04

2.将商品服务,订单服务,秒杀等服务,注册到consul

mha mysql高可用 consul mysql高可用_数据中心_05

为了提高qps,所以需要以内redis+mongodb

mha mysql高可用 consul mysql高可用_mha mysql高可用_06

3.搭建一个consul集群

说明:consul注册中心是可以针对整个项目进行,因此将consul放到公共服务器上,consul一般采用奇数3,5,7(官方未给出具体的原因)

3.1 加载镜像(镜像文件放在资源文件下)
docker load < consul1.4.tar
3.2构建docker-compose,内如如下:
# 编排php,redis,nginx容器
version: "3.6" # 确定docker-composer文件的版本
services: # 代表就是一组服务 - 简单来说一组容器
	# server
	consul_master_server_172_30: # 这个表示服务的名称, 课自定义; 注意不是容器名称
	image: consul1.4 # 指定容器的镜像文件
	networks: ## 引入外部预先定义的网段
		swoft_consul:
			ipv4_address: 172.200.7.30 #设置ip地址
	container_name: consul_master_server_172_30 # 这是容器的名称
	command: ./consul agent -server -bootstrap-expect 3 -data-dir /tmp/consul -node=consul_master_server_172_30 -bind=172.200.7.30 -ui -
client=0.0.0.0
	consul_slaves_server_172_20: # 这个表示服务的名称, 课自定义; 注意不是容器名称
		image: consul1.4 # 指定容器的镜像文件
		networks: ## 引入外部预先定义的网段
			swoft_consul:
				ipv4_address: 172.200.7.20 #设置ip地址
		container_name: consul_slaves_server_172_20 # 这是容器的名称
		command: ./consul agent -server -data-dir /tmp/consul -node=consul_slaves_server_172_20 -bind=172.200.7.20 -ui -client=0.0.0.0 -join
172.200.7.30
	consul_slaves_server_172_10: # 这个表示服务的名称, 课自定义; 注意不是容器名称
		image: consul1.4 # 指定容器的镜像文件  
		networks: ## 引入外部预先定义的网段
			swoft_consul:
				ipv4_address: 172.200.7.10 #设置ip地址
		container_name: consul_slaves_server_172_20 # 这是容器的名称
		command: ./consul agent -server -data-dir /tmp/consul -node=consul_slaves_server_172_10 -bind=172.200.7.10 -ui -client=0.0.0.0 -join
172.200.7.30
# 设置网络模块
networks:
	# 自定义网络
	swoft_consul:
		driver: bridge
		ipam: #定义网段
			config:
				- subnet: "172.200.7.0/24"

执行 docker-compose up -d 构建容器

[root@localhost consul]# docker-compose up -d
Creating network "consul_swoft_consul" with driver "bridge"
Creating consul_slaves_server_172_20 ... done
Creating consul_slaves_server_172_10 ... done
Creating consul_master_server_172_30 ... done
[root@localhost consul]# docker exec -it consul_master_server_172_30 sh
/ # ./consul operator raft list-peers
Node ID Address State Voter RaftProtocol
consul_master_server_172_30 82892b8f-278f-2d66-ef80-05332f70b880 172.200.7.30:8300 leader true 3
consul_slaves_server_172_10 7dfddc84-31bf-eb4e-a027-845434a3becf 172.200.7.10:8300 follower true 3
consul_slaves_server_172_20 5cece2b4-9e59-374e-dd5f-61b6600cdf5a 172.200.7.20:8300 follower true 3

从上面可以看到, 生成了一台leader和二台follower。

mha mysql高可用 consul mysql高可用_Server_07

3.3. 构建consul客户端

构建–基于之前的docker-compose.yaml构建

# 编排php,redis,nginx容器
version: "3.6" # 确定docker-composer文件的版本
services: # 代表就是一组服务 - 简单来说一组容器
	# server
	# ....
	# client
	consul_client_172_50: # 这个表示服务的名称, 课自定义; 注意不是容器名称
		image: consul1.4 # 指定容器的镜像文件
		ports: # 配置容器与宿主机的端口
		- "8550:8500"
		networks: ## 引入外部预先定义的网段
			swoft_consul:
				ipv4_address: 172.200.7.50 #设置ip地址
		container_name: consul_client_172_50 # 这是容器的名称
		command: ./consul agent -data-dir /tmp/consul -node=consul_client_172_50 -bind=172.200.7.50 -ui -client=0.0.0.0 -join 172.200.7.30
	consul_client_172_40: # 这个表示服务的名称, 课自定义; 注意不是容器名称
		image: consul1.4 # 指定容器的镜像文件
		ports: # 配置容器与宿主机的端口
		- "8540:8500"
		networks: ## 引入外部预先定义的网段
			swoft_consul:
				ipv4_address: 172.200.7.40 #设置ip地址
		container_name: consul_client_172_40 # 这是容器的名称
		command: ./consul agent -data-dir /tmp/consul -node=consul_client_172_40 -bind=172.200.7.40 -ui -client=0.0.0.0 -join 172.200.7.30
# 设置网络模块
networks:
	# 自定义网络
	swoft_consul:
		driver: bridge
		ipam: #定义网段
			config:
				- subnet: "172.200.7.0/24"

到此, 一主二从二客户端的consul高可用集群搭建完毕, 如下所示

mha mysql高可用 consul mysql高可用_mha mysql高可用_08

3.4 构建consul部署架构理解

集群

Consul 是一个分布式的解决方案, 可以部署多个 Consul 实例, 确保数据中心的持续稳定, 在 Consul 集群中, 内部采用投票的方式选举出 leader, 然后才开始运行整个集群, 只有正确选举出 leader 后, 集群才开始工作, 当一个服务注册到 Consul 后, 集群将该服务进行同步, 确保 Consul 集群内的每个节点都存储了该服务的信息; 然后, Consul 集群将对该服务进行健康检查和投票, 超过半数通过, 即认为该服务为正常(或者异常) ; 一旦被投票认定为异常的服务, 该服务将不会被外部发现(不可访问) , 在此过程中, Consul 将持续的对该异常的服务进行检查, 一旦服务恢复, Consul 即刻将其加入正常服务。

server与client

Consul 支持两种运行的方式, 即 server 和 client 模式, 当一个 Consul 节点以 server 模式运行的时候, 就表示该 Consul 节点会存储服务和配置等相关信息, 并且参与到健康检查、 leader 选举等服务器事务中, 与之相反的是, client 模式不会存储服务信息。

数据中心

每个Consul节点都需要加入一个命名的数据中心(DataCenter) , -个节点上,可以运行多个 数据中心, 数据中心的作用在于应用隔离,相当于服务分组。 可以简单理解为, -个数据中心 域为一个二层联通的子网。

3.5 构建consul集群架构

下面这张图来源于 Consul 官网, 很好的解释了 Consul 的工作原理, 先大致看一下:

mha mysql高可用 consul mysql高可用_consul_09

mha mysql高可用 consul mysql高可用_数据_10


首先 Consul 支持多数据中心, 在上图中有两个 DataCenter, 他们通过 Internet 互联, 同时请注意为了提高通信效率, 只有 Server 节点才加入跨数据中心的通信。在单个数据中心中, Consul 分为 Client 和 Server 两种节点(所有的节点也被称为 Agent) , Server 节点保存数据, Client 负责健康检查及转发数据请求到 Server。

Server 节点有一个 Leader 和多个 Follower, Leader 节点会将数据同步到 Follower, Server 的数量推荐是 3 个或者 5 个, 在 Leader 挂掉的时候会启动选举机制产生一个新的 Leader。集群内的 Consul 节点通过 gossip 协议(流言协议) 维护成员关系, 也就是说某个节点了解集群内现在还有哪些节点, 这些节点是 Client 还是 Server。单个数据中心的流言协议同时使用 TCP 和 UDP 通信, 并且都使用 8301 端口。 跨数据中心的流言协议也同时使用 TCP 和 UDP 通信, 端口使用 8302。集群内数据的读写请求既可以直接发到 Server, 也可以通过 Client 使用 RPC 转发到 Server, 请求最终会到达 Leader 节点。在允许数据轻微陈旧的情况下, 读请求也可以在普通的 Server 节点完成, 集群内数据的读写和复制都是通过 TCP 的 8300 端口完成。

3.5 consul 服务发现原理及完整流程

mha mysql高可用 consul mysql高可用_mha mysql高可用_11

首先需要有一个正常的 Consul 集群, 有 Server, 有 Leader。 这里在服务器 Server1、 Server2、 Server3 上分别部署了 Consul Server。假设他们选举了 Server2 上的 Consul Server 节点为 Leader。

然后在服务器 Server4 和 Server5 上通过 Consul Client 分别注册 Service A、 B、 C, 这里每个 Service 分别部署在了两个服务器上, 这样可以避免 Service 的单点问题。

服务注册到 Consul 可以通过 HTTP API(8500 端口) 的方式, 也可以通过 Consul 配置文件的方式。Consul Client 将注册信息通过 RPC 转发到 Consul Server, 服务信息保存在 Server 的各个节点中, 并且通过 Raft 实现了强一致性。

最后在服务器 Server6 中 Program D 需要访问 Service B, 这时候 Program D 首先访问本机 Consul Client 提供的 HTTP API, 本机 Client 会将请求转发到 ConsulServer。

Consul Server 查询到 Service B 当前的信息返回, 最终 Program D 拿到了 Service B 的所有部署的 IP 和端口, 然后就可以选择 Service B 的其中一个部署并向其发起请求了

4.将商品服务自动注册和服务发现

4.1. 拆分说明

在之前有讲过, 关于商品这一块我们会拆分为两个大的方面client与server;
为什么这么做呢?
client同比与传统框架为controller, 而server则为业务+数据库处理; 如果说是简单的微服务我们可以两者合一, 但是如果说考虑到后期的扩展和维护则可以需要做好拆分, client会负责请求的处理。
client与server之间采用 rpc通信访问流程 用户-》 nginx(负载)-》 client(通过 consul 发现server) -》 rpc-》 serverclient采用httpServer
server采用rpcServer

4.2 开发前的准备

首先第一步构建的是goods-server

4.3 理解swoft的服务注册与发送功能的运用

https://www.swoft.org/documents/v2/microservice/register-find/ 在官方的手册中有描述关于服务注册与发现的案例, 并且采用的是consul并且也提供了相应的案例
快速运用
服务注册:
我们可以先基于官方案例来完成注册与注销
首先我们需要修改 bean.php 的配置信息

<?php
return [
	// ...
	'consul' => [
	'host' => '192.168.169.110',
	'port' => '8540'
	]
];
?>

注意这里我们选择的是consul的client

app\server\swoft\app\Listener\RegisterServiceListener.php
<?php
/**
* Class RegisterServiceListener
* @since 2.0
* @Listener(event=SwooleEvent::START)
*/
class RegisterServiceListener implements EventHandlerInterface
{
	/**
	* @Inject()
	**
	@var Agent
	*/
	private $agent;
	
	/* @param EventInterface $event
	*/
	public function handle(EventInterface $event): void
	{
		$rpcServer = $event->getTarget();
		$service = [
			'ID' => 'swoft_goods_server_173_110',
			'Name' => 'swoft_goods_server',
			'Tags' => [
				'RPC'
			],
			'Address' => '192.168.169.120',
			'Port' => $rpcServer->getPort(),
			'Meta' => [
				'version' => '1.0'
			],
			'EnableTagOverride' => false,
			'Weights' => [
				'Passing' => 10,
				'Warning' => 1
			]
		];
		// Register
		$this->agent->registerService($service);
		echo "Swoft http register service success by consul!\n";
	}
}
?>

然后可以定义容器进行测试

# 编排php,redis,nginx容器
version: "3.6" # 确定docker-composer文件的版本
services: # 代表就是一组服务 - 简单来说一组容器
	swoft_goods_server_173_110: # 这个表示服务的名称, 课自定义; 注意不是容器名称
		image: swoft # 指定容器的镜像文件
		container_name: swoft_goods_server_173_110 # 这是容器的名称
networks: ## 引入外部预先定义的网段
	app_swoft:
		ipv4_address: 173.200.7.110 #设置ip地址
		volumes: # 配置数据挂载
		- /www/wwwroot/2007_SRM/app/server/swoft:/www/swoft
		working_dir: /www/swoft #工作目录
		command: php bin/swoft rpc:start
# 设置网络模块
networks:
	# 自定义网络
	app_swoft:
		driver: bridge
		ipam: #定义网段
			config:
				- subnet: "173.200.7.0/24"

mha mysql高可用 consul mysql高可用_mha mysql高可用_12

服务注销:

服务启动注册服务, 服务关闭或者退出则需要取消服务注册, 此时这里和注册一样监听一个 SwooleEvent::SHUTDOWN 事件即可, 本章这里还是以 取消 Http
server 服务为例:
app\server\swoft\app\Listener\DeregisterServiceListener.php

<?php declare(strict_types=1);
/**
* Class DeregisterServiceListener
* @since 2.0
* @Listener(SwooleEvent::SHUTDOWN)
*/
class DeregisterServiceListener implements EventHandlerInterface
{
	/**
	* @Inject()
	**
	@var Agent
	*/
	private $agent;
	public function handle(EventInterface $event): void
	{
		$httpServer = $event->getTarget();
		$this->agent->deregisterService('swoft_goods_server_173_110');
		echo "Swoft rpc register service deregisterService\n";;
	}
}
?>

演示就跳过了…

理解运行

在监听中, 主要是通过 Swoft\Consul\Agent 实现服务的注册和注销的功能

mha mysql高可用 consul mysql高可用_consul_13

同时利用在对象上增加的 @Listener(SwooleEvent::SHUTDOWN) 指定运行的周期地址;
回顾swoole声明周期简化版:

通过new 创建服务 -》 进入start事件初始化-》 managerStar -》 worker/task start -》 往后交互都在中间的监听如(request,message,receive) 等事件 -》
worker/task stop-》 managerStop-》 结束swoole进程Shutdown
而swoft的事件监听就是在这些节点增加的事件监听方法; 通过 SHUTDOWN确定执行节点;

关于方法的封装主要是在 app\server\swoft\vendor\swoft\consul\src\Consul.php 与 app\server\swoft\vendor\swoft\consul\src\Agent.php

其中注释: @Bean() 当一个对象中标有这个注解代表在启动的时候会注册到容器中, 然后使用的时候我们无需手动的new 只需要在属性上运用@Inject()注解可以创
建实例;

注意注意! ! ! @Inject()注解是需要配合@var一起运用负责报错;

在 app\server\swoft\vendor\swoft\consul\src\Consul.php 发送数据实际底层是运用了协程客户端处理的

mha mysql高可用 consul mysql高可用_数据_14


总结:

以上是 consul 介绍、应用场景介绍、常见问题汇总、部署配置介绍等,如有问题欢迎留言指正!