Orchestrator源码解读2-故障失败发现

目录

目录

前言

核心流程函数调用路径

GetReplicationAnalysis

故障类型和对应的处理函数

拓扑结构警告类型

与MHA相比


前言

Orchestrator另外一个重要的功能是监控集群,发现故障。根据从复制拓扑本身获得的信息,它可以识别各种故障场景。Orchestrator介绍四-失败/故障检测_orchestrator 心跳-CSDN博客

核心流程函数调用路径

ContinuousDiscovery
--> CheckAndRecover // 检查恢复的入口函数
--> GetReplicationAnalysis  // 查询SQL,根据实例的状态确定故障或者警告类型。检查复制问题  (dead master; unreachable master; 等)
--> executeCheckAndRecoverFunction  // 根据分析结果选择正确的检查和恢复函数。然后会同步执行该函数。
--> getCheckAndRecoverFunction // 根据分析结果选择正确的检查和恢复函数。然后会同步执行该函数。
--> runEmergentOperations // 
--> checkAndExecuteFailureDetectionProcesses //   尝试往数据库中插入这个故障发现记录,然后执行故障发现阶段所需的操作,执行 OnFailureDetectionProcesses (故障发现阶段的)钩子脚本
--> AttemptFailureDetectionRegistration //  尝试往数据库中插入故障发现记录 ,如果失败 意味着这个问题可能已经被发现了,
--> checkAndRecoverDeadMaster  // 根据故障情况 执行恢复,这里选择DeadMaster 故障类型举例 
--> AttemptRecoveryRegistration // 尝试往数据库中插入一条恢复记录;如果这一尝试失败,那么意味着恢复已经在进行中。
--> recoverDeadMaster //  用于恢复DeadMaster故障类型的函数,其中包含了完整的逻辑。会执行PreFailoverProcesses 钩子脚本

GetReplicationAnalysis

该函数将检查复制问题 (dead master; unreachable master; 等),根据实例的状态确定故障或者警告类型。

该函数会运行一个复杂SQL ,该SQL会每秒执行一次 ,执行间隔是由定时器 recoveryTick决定 ,SQL如下

SELECT
		master_instance.hostname,
		master_instance.port,
		master_instance.read_only AS read_only,
		MIN(master_instance.data_center) AS data_center,
		MIN(master_instance.region) AS region,
		MIN(master_instance.physical_environment) AS physical_environment,
		MIN(master_instance.master_host) AS master_host,
		MIN(master_instance.master_port) AS master_port,
		MIN(master_instance.cluster_name) AS cluster_name,
		MIN(master_instance.binary_log_file) AS binary_log_file,
		MIN(master_instance.binary_log_pos) AS binary_log_pos,
		MIN(
			IFNULL(
				master_instance.binary_log_file = database_instance_stale_binlog_coordinates.binary_log_file
				AND master_instance.binary_log_pos = database_instance_stale_binlog_coordinates.binary_log_pos
				AND database_instance_stale_binlog_coordinates.first_seen < NOW() - interval 10 second,
				0
			)
		) AS is_stale_binlog_coordinates,
		MIN(
			IFNULL(
				cluster_alias.alias,
				master_instance.cluster_name
			)
		) AS cluster_alias,
		MIN(
			IFNULL(
				cluster_domain_name.domain_name,
				master_instance.cluster_name
			)
		) AS cluster_domain,
		MIN(
			master_instance.last_checked <= master_instance.last_seen
			and master_instance.last_attempted_check <= master_instance.last_seen + interval 6 second
		) = 1 AS is_last_check_valid,
		/* To be considered a master, traditional async replication must not be present/valid AND the host should either */
		/* not be a replication group member OR be the primary of the replication group */
		MIN(master_instance.last_check_partial_success) as last_check_partial_success,
		MIN(
			(
				master_instance.master_host IN ('', '_')
				OR master_instance.master_port = 0
				OR substr(master_instance.master_host, 1, 2) = '//'
			)
			AND (
				master_instance.replication_group_name = ''
				OR master_instance.replication_group_member_role = 'PRIMARY'
			)
		) AS is_master,
		MIN(
			master_instance.replication_group_name != ''
			AND master_instance.replication_group_member_state != 'OFFLINE'
		) AS is_replication_group_member,
		MIN(master_instance.is_co_master) AS is_co_master,
		MIN(
			CONCAT(
				master_instance.hostname,
				':',
				master_instance.port
			) = master_instance.cluster_name
		) AS is_cluster_master,
		MIN(master_instance.gtid_mode) AS gtid_mode,
		COUNT(replica_instance.server_id) AS count_replicas,
		IFNULL(
			SUM(
				replica_instance.last_checked <= replica_instance.last_seen
			),
			0
		) AS count_valid_replicas,
		IFNULL(
			SUM(
				replica_instance.last_checked <= replica_instance.last_seen
				AND replica_instance.slave_io_running != 0
				AND replica_instance.slave_sql_running != 0
			),
			0
		) AS count_valid_replicating_replicas,
		IFNULL(
			SUM(
				replica_instance.last_checked <= replica_instance.last_seen
				AND replica_instance.slave_io_running = 0
				AND replica_instance.last_io_error like '%error %connecting to master%'
				AND replica_instance.slave_sql_running = 1
			),
			0
		) AS count_replicas_failing_to_connect_to_master,
		MIN(master_instance.replication_depth) AS replication_depth,
		GROUP_CONCAT(
			concat(
				replica_instance.Hostname,
				':',
				replica_instance.Port
			)
		) as slave_hosts,
		MIN(
			master_instance.slave_sql_running = 1
			AND master_instance.slave_io_running = 0
			AND master_instance.last_io_error like '%error %connecting to master%'
		) AS is_failing_to_connect_to_master,
		MIN(
			master_downtime.downtime_active is not null
			and ifnull(master_downtime.end_timestamp, now()) > now()
		) AS is_downtimed,
		MIN(
			IFNULL(master_downtime.end_timestamp, '')
		) AS downtime_end_timestamp,
		MIN(
			IFNULL(
				unix_timestamp() - unix_timestamp(master_downtime.end_timestamp),
				0
			)
		) AS downtime_remaining_seconds,
		MIN(
			master_instance.binlog_server
		) AS is_binlog_server,
		MIN(master_instance.pseudo_gtid) AS is_pseudo_gtid,
		MIN(
			master_instance.supports_oracle_gtid
		) AS supports_oracle_gtid,
		MIN(
			master_instance.semi_sync_master_enabled
		) AS semi_sync_master_enabled,
		MIN(
			master_instance.semi_sync_master_wait_for_slave_count
		) AS semi_sync_master_wait_for_slave_count,
		MIN(
			master_instance.semi_sync_master_clients
		) AS semi_sync_master_clients,
		MIN(
			master_instance.semi_sync_master_status
		) AS semi_sync_master_status,
		SUM(replica_instance.is_co_master) AS count_co_master_replicas,
		SUM(replica_instance.oracle_gtid) AS count_oracle_gtid_replicas,
		IFNULL(
			SUM(
				replica_instance.last_checked <= replica_instance.last_seen
				AND replica_instance.oracle_gtid != 0
			),
			0
		) AS count_valid_oracle_gtid_replicas,
		SUM(
			replica_instance.binlog_server
		) AS count_binlog_server_replicas,
		IFNULL(
			SUM(
				replica_instance.last_checked <= replica_instance.last_seen
				AND replica_instance.binlog_server != 0
			),
			0
		) AS count_valid_binlog_server_replicas,
		SUM(
			replica_instance.semi_sync_replica_enabled
		) AS count_semi_sync_replicas,
		IFNULL(
			SUM(
				replica_instance.last_checked <= replica_instance.last_seen
				AND replica_instance.semi_sync_replica_enabled != 0
			),
			0
		) AS count_valid_semi_sync_replicas,
		MIN(
			master_instance.mariadb_gtid
		) AS is_mariadb_gtid,
		SUM(replica_instance.mariadb_gtid) AS count_mariadb_gtid_replicas,
		IFNULL(
			SUM(
				replica_instance.last_checked <= replica_instance.last_seen
				AND replica_instance.mariadb_gtid != 0
			),
			0
		) AS count_valid_mariadb_gtid_replicas,
		IFNULL(
			SUM(
				replica_instance.log_bin
				AND replica_instance.log_slave_updates
			),
			0
		) AS count_logging_replicas,
		IFNULL(
			SUM(
				replica_instance.log_bin
				AND replica_instance.log_slave_updates
				AND replica_instance.binlog_format = 'STATEMENT'
			),
			0
		) AS count_statement_based_logging_replicas,
		IFNULL(
			SUM(
				replica_instance.log_bin
				AND replica_instance.log_slave_updates
				AND replica_instance.binlog_format = 'MIXED'
			),
			0
		) AS count_mixed_based_logging_replicas,
		IFNULL(
			SUM(
				replica_instance.log_bin
				AND replica_instance.log_slave_updates
				AND replica_instance.binlog_format = 'ROW'
			),
			0
		) AS count_row_based_logging_replicas,
		IFNULL(
			SUM(replica_instance.sql_delay > 0),
			0
		) AS count_delayed_replicas,
		IFNULL(
			SUM(replica_instance.slave_lag_seconds > 10),
			0
		) AS count_lagging_replicas,
		IFNULL(MIN(replica_instance.gtid_mode), '') AS min_replica_gtid_mode,
		IFNULL(MAX(replica_instance.gtid_mode), '') AS max_replica_gtid_mode,
		IFNULL(
			MAX(
				case when replica_downtime.downtime_active is not null
				and ifnull(replica_downtime.end_timestamp, now()) > now() then '' else replica_instance.gtid_errant end
			),
			''
		) AS max_replica_gtid_errant,
		IFNULL(
			SUM(
				replica_downtime.downtime_active is not null
				and ifnull(replica_downtime.end_timestamp, now()) > now()
			),
			0
		) AS count_downtimed_replicas,
		COUNT(
			DISTINCT case when replica_instance.log_bin
			AND replica_instance.log_slave_updates then replica_instance.major_version else NULL end
		) AS count_distinct_logging_major_versions
	FROM
		database_instance master_instance
		LEFT JOIN hostname_resolve ON (
			master_instance.hostname = hostname_resolve.hostname
		)
		LEFT JOIN database_instance replica_instance ON (
			COALESCE(
				hostname_resolve.resolved_hostname,
				master_instance.hostname
			) = replica_instance.master_host
			AND master_instance.port = replica_instance.master_port
		)
		LEFT JOIN database_instance_maintenance ON (
			master_instance.hostname = database_instance_maintenance.hostname
			AND master_instance.port = database_instance_maintenance.port
			AND database_instance_maintenance.maintenance_active = 1
		)
		LEFT JOIN database_instance_stale_binlog_coordinates ON (
			master_instance.hostname = database_instance_stale_binlog_coordinates.hostname
			AND master_instance.port = database_instance_stale_binlog_coordinates.port
		)
		LEFT JOIN database_instance_downtime as master_downtime ON (
			master_instance.hostname = master_downtime.hostname
			AND master_instance.port = master_downtime.port
			AND master_downtime.downtime_active = 1
		)
		LEFT JOIN database_instance_downtime as replica_downtime ON (
			replica_instance.hostname = replica_downtime.hostname
			AND replica_instance.port = replica_downtime.port
			AND replica_downtime.downtime_active = 1
		)
		LEFT JOIN cluster_alias ON (
			cluster_alias.cluster_name = master_instance.cluster_name
		)
		LEFT JOIN cluster_domain_name ON (
			cluster_domain_name.cluster_name = master_instance.cluster_name
		)
	WHERE
		database_instance_maintenance.database_instance_maintenance_id IS NULL
		AND '' IN ('', master_instance.cluster_name)
	GROUP BY
		master_instance.hostname,
		master_instance.port

			HAVING
				(
					MIN(
						master_instance.last_checked <= master_instance.last_seen
						and master_instance.last_attempted_check <= master_instance.last_seen + interval 6 second
					) = 1
					/* AS is_last_check_valid */
				) = 0
				OR (
					IFNULL(
						SUM(
							replica_instance.last_checked <= replica_instance.last_seen
							AND replica_instance.slave_io_running = 0
							AND replica_instance.last_io_error like '%error %connecting to master%'
							AND replica_instance.slave_sql_running = 1
						),
						0
					)
					/* AS count_replicas_failing_to_connect_to_master */
					> 0
				)
				OR (
					IFNULL(
						SUM(
							replica_instance.last_checked <= replica_instance.last_seen
						),
						0
					)
					/* AS count_valid_replicas */
					< COUNT(replica_instance.server_id)
					/* AS count_replicas */
				)
				OR (
					IFNULL(
						SUM(
							replica_instance.last_checked <= replica_instance.last_seen
							AND replica_instance.slave_io_running != 0
							AND replica_instance.slave_sql_running != 0
						),
						0
					)
					/* AS count_valid_replicating_replicas */
					< COUNT(replica_instance.server_id)
					/* AS count_replicas */
				)
				OR (
					MIN(
						master_instance.slave_sql_running = 1
						AND master_instance.slave_io_running = 0
						AND master_instance.last_io_error like '%error %connecting to master%'
					)
					/* AS is_failing_to_connect_to_master */
				)
				OR (
					COUNT(replica_instance.server_id)
					/* AS count_replicas */
					> 0
				)

	ORDER BY
		is_master DESC,
		is_cluster_master DESC,
		count_replicas DESC\G

故障类型和对应的处理函数

故障类型处理函数
NoProblem没有
DeadMasterWithoutReplicas没有
DeadMastercheckAndRecoverDeadMaster
DeadMasterAndReplicascheckAndRecoverGenericProblem
DeadMasterAndSomeReplicascheckAndRecoverDeadMaster
UnreachableMasterWithLaggingReplicascheckAndRecoverGenericProblem
UnreachableMastercheckAndRecoverGenericProblem
MasterSingleReplicaNotReplicating
MasterSingleReplicaDead
AllMasterReplicasNotReplicatingcheckAndRecoverGenericProblem
AllMasterReplicasNotReplicatingOrDeadcheckAndRecoverGenericProblem
LockedSemiSyncMasterHypothesis
LockedSemiSyncMastercheckAndRecoverLockedSemiSyncMaster
MasterWithTooManySemiSyncReplicascheckAndRecoverMasterWithTooManySemiSyncReplicas
MasterWithoutReplicas
DeadCoMastercheckAndRecoverDeadCoMaster
DeadCoMasterAndSomeReplicascheckAndRecoverDeadCoMaster
UnreachableCoMaster
AllCoMasterReplicasNotReplicating
DeadIntermediateMastercheckAndRecoverDeadIntermediateMaster
DeadIntermediateMasterWithSingleReplicacheckAndRecoverDeadIntermediateMaster
DeadIntermediateMasterWithSingleReplicaFailingToConnectcheckAndRecoverDeadIntermediateMaster
DeadIntermediateMasterAndSomeReplicascheckAndRecoverDeadIntermediateMaster
DeadIntermediateMasterAndReplicascheckAndRecoverGenericProblem
UnreachableIntermediateMasterWithLaggingReplicascheckAndRecoverGenericProblem
UnreachableIntermediateMaster
AllIntermediateMasterReplicasFailingToConnectOrDeadcheckAndRecoverDeadIntermediateMaster
AllIntermediateMasterReplicasNotReplicating
FirstTierReplicaFailingToConnectToMaster
BinlogServerFailingToConnectToMaster
// Group replication problems
DeadReplicationGroupMemberWithReplicascheckAndRecoverDeadGroupMemberWithReplicas

拓扑结构警告类型

  • StatementAndMixedLoggingReplicasStructureWarning
  • StatementAndRowLoggingReplicasStructureWarning
  • MixedAndRowLoggingReplicasStructureWarning
  • MultipleMajorVersionsLoggingReplicasStructureWarning
  • NoLoggingReplicasStructureWarning
  • DifferentGTIDModesStructureWarning
  • ErrantGTIDStructureWarning
  • NoFailoverSupportStructureWarning
  • NoWriteableMasterStructureWarning
  • NotEnoughValidSemiSyncReplicasStructureWarning

与MHA相比

MHA探活

核心功能主要有 MHA::HealthCheck::wait_until_unreachable 实现:

  1. 该函数通过一个死循环,检测 4 次,每次 sleep ping_interval 秒(这个值在配置文件指定,参数是 ping_interval),持续四次失败,就认为数据已经宕机;

  2. 如果有二路检测脚本,需要二路检测脚本检测主库宕机,才是真正的宕机,否则只是推出死循环,结束检测,不切换

  3. 通过添加锁来保护数据库的访问,防止脚本多次启动;

  4. 该函数可调用三种检测方法:ping_select、ping_insert、ping_connect

MHA探活流程图

MHAOC
故障类型

故障类型单一,

主要就是主库是否存活

故障类型丰富

有多种故障与警告类型

见上面的总结

探活节点

支持多个节点探活

即manager服务器与二次检查脚本中定义的服务器

多个OC节点 以及 配合该实例的从库复制状态是否正常进行检测
探活方式

ping_select、

ping_insert、

ping_connect

查询被管理的数据库,将数据写入到OC的后台管理数据库中,进行时间戳的比较或状态值比较等方式
探活间隔默认3秒默认每1秒
探活次数4次1次
故障探测速度慢,需要多次探活。
探活理念多次多个节点避免网络抖动等配合从副本的主从状态以及OC节点的探活

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/305866.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue2.v-指令

v-if 在双引号中写判断条件。 <div v-if"score>90">A</div> <div v-else-if"score>80">B</div> <div v-else>C</div>v-on: :冒号后面跟着事件。 为了简化&#xff0c;可以直接用代替v-on:。 事件名“内联语…

【前端素材】同城服务分类手机APP页面的设计实现

一、需求分析 一个同城服务分类手机页面是一个用于提供同城服务分类信息的移动设备页面。它通常具有以下功能&#xff1a; 地理定位&#xff1a;同城服务分类手机页面可以利用用户的地理定位功能&#xff0c;获取用户当前所在的城市或地区信息&#xff0c;以便提供与用户所在地…

一、Mybatis 简介

本章概要 简介持久层框架对比快速入门&#xff08;基于Mybatis3方式&#xff09; 1.1 简介 https://mybatis.org/mybatis-3/zh/index.html MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投G…

12、DolphinScheduler

1、DolphinScheduler简介 1.1、 DolphinScheduler概述 Apache DolphinScheduler是一个分布式、易扩展的可视化DAG工作流任务调度平台。致力于解决数据处理流程中错综复杂的依赖关系&#xff0c;使调度系统在数据处理流程中开箱即用。 1.2、 DolphinScheduler核心架构 Dolph…

UV贴图和展开初学者指南

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 介绍 这正是本文的主题——UV贴图——登上舞台的时候。大多数 3D 建…

基于YOLOv8 + BotSORT实现球员和足球检测与跟踪 (步骤 + 源码)

导 读 本文主要介绍基于YOLOv8和BotSORT实现球员和足球检测与跟踪 &#xff0c;并给出步骤和代码。 背景介绍 本文旨在了解 YOLO 架构并在自定义数据集上对其进行训练&#xff0c;然后微调模型以获得更好的结果&#xff0c;并运行推理以了解最有效的方法。 什么是YOLO&#x…

练习-指针笔试题

目录 前言一、一维整型数组1.1 题目一1.2 题目二 二、二维整型数组2.1 题目一2.2 题目二2.3 题目三 三、结构体3.1 题目一&#xff08;32位机器运行&#xff09; 四、字符数组4.1 题目一4.2 题目二 总结 前言 本篇文章记录关于C语言指针笔试题的介绍。 一、一维整型数组 1.1 …

探索人工智能:深度学习、人工智能安全和人工智能

深度学习是人工智能的一种重要技术&#xff0c;它模拟了人类大脑神经网络的工作原理&#xff0c;通过建立多层次的神经元网络来实现对数据的分析和处理。这种技术的引入使得人工智能的发展进入到了一个新的阶段。 现如今&#xff0c;深度学习在各个领域都有着广泛的应用。例如…

简单的MOV转MP4方法

1.下载腾讯的QQ影音播放器, 此播放器为绿色视频播放器, 除了播放下载好的视频外没有臃肿无用功能 官网 QQ影音 百度网盘链接&#xff1a;https://pan.baidu.com/s/1G0kSC-844FtRfqGnIoMALA 提取码&#xff1a;dh4w 2.用QQ影音打开MOV文件 3.右下角打开影音工具箱 , 选择截取…

开启Android学习之旅-6-实战答题App

不经过实战&#xff0c;看再多理论&#xff0c;都是只放在笔记里&#xff0c;活学活用才是硬道理。同时开发应用需要循序渐进&#xff0c;一口气规划300个功能&#xff0c;400张表&#xff0c;会严重打击自己的自信。这里根据所学的&#xff0c;开发一个答题App。 题库需求分析…

公司新买的BI,和金蝶系统配合太默契了

公司一直都用金蝶系统来实现包括财务管理、供应链管理、人力资源管理等多个方面的资源的合理配置和业务流程的自动化。但到了数据分析这块&#xff0c;金蝶系统就明显力不从心&#xff0c;需要一个专业的数据分析工具来接手。财务经理推荐用奥威BI&#xff0c;说这款BI的一大特…

光纤知识总结

1光纤概念&#xff1a; 光导纤维&#xff08;英语&#xff1a;Optical fiber&#xff09;&#xff0c;简称光纤&#xff0c;是一种由玻璃或塑料制成的纤维&#xff0c;利用光在这些纤维中以全内反射原理传输的光传导工具。 微细的光纤封装在塑料护套中&#xff0c;使得它能够…

OpenAI ChatGPT-4开发笔记2024-01:开发环境

ChatGPT发展一日千里。工具、函数少则数日&#xff0c;多则数月就加入了Deprecated行列不再如预期般工作。元旦闲来无事&#xff0c;用最新的ChatGPT重写一下各种开发场景&#xff0c;全部实测通过。 开发环境&#xff1a; 电脑&#xff1a;两台笔记本&#xff1a;HP和MacBoo…

Pixi.js的魅力

摘要&#xff1a;官网 Web开发的时代&#xff0c;图形和动画已经成为了吸引用户注意力的重要手段之一。而 Pixi.js 作为一款高效、易用的2D渲染引擎&#xff0c;已经成为了许多开发者的首选~~ 项目中&#xff0c;有一些图像的处理操作&#xff08;3D图&#xff0c;2D图都有&…

49寸OLED拼接屏:技术、应用与市场前景

作为“49寸OLED拼接屏”技术总监&#xff0c;我深知这一产品对于显示行业的重要性。随着显示技术的不断进步&#xff0c;OLED拼接屏在高端显示市场占据了一席之地。下面&#xff0c;我将从技术的角度深入剖析这一产品。 一、参数 49寸OLED拼接屏是一款高端大屏显示产品&#x…

在线文本转语音工具的实现

文章目录 文章最下面有工具链接&#xff01;前言edge-tts库1.首先使用pip安装这个库2.写一段示例代码3.多线程 pydub库1.介绍2.示例 将他们整合起来我把他们部署到了我的服务器上&#xff0c;可以在线使用点我使用工具 文章最下面有工具链接&#xff01; 前言 最近有文字转语…

Halcon3D篇-3D预处理,滤波,点云筛选

前言 由于3D相机采集到的数据通常通过Tiff格式的深度图进行显示或者保存。 深度图与模型的互转可以访问另一篇博客&#xff1a;https://blog.csdn.net/m0_51559565/article/details/135362674 关于3D相机的数据采集&#xff0c;可以访问我们另一篇关于LMI3D相机SDK的二次开发…

Redis主从复制哨兵及集群

目录 一.主从复制 主从复制的工作原理如下&#xff1a; 主从复制的作用&#xff1a; 搭建Redis 主从复制 每台服务器配置&#xff1a; ​编辑进行编译安装&#xff1a; 定义systemd服务管理脚本&#xff1a; 开启服务&#xff0c;报错看下内容&#xff1a; 修改 Redis…

Hyperledger Fabric 二进制安装部署 Peer 节点

规划网络拓扑 3 个 orderer 节点&#xff1b;组织 org1 , org1 下有两个 peer 节点&#xff0c; peer0 和 peer1; 组织 org2 , org2 下有两个 peer 节点&#xff0c; peer0 和 peer1; 节点宿主机 IPhosts端口cli192.168.1.66N/AN/Aorderer0192.168.1.66orderer0.example.com70…

深入浅出:原生态App封装的艺术

一、原生态App封装的优势 性能的极致&#xff1a;原生App直接调用设备的硬件资源&#xff0c;减少了中间层的干扰&#xff0c;从而实现更快的运行速度和更流畅的动画效果。 2. 用户体验的完美&#xff1a;原生App可以访问并遵循特定平台的设计指南&#xff0c;提供与操作系统无…