elasticdump之python脚本

参考文章目录

elasticdump之shell备份脚本

前言

在企业实际生产环境中,避免不了要对es集群进行迁移、数据备份与恢复,以此来确保数据的可用性及完整性。因此,就涉及到了数据备份与恢复。本章主要以elasticdump+python为主,实现es集群索引备份、es集群索引恢复、两个网络互通的es集群直接迁移索引(通过nc命令判断网络是否互通)。其余备份和恢复方法见elasticsearch博客目录,总结来自于生产实战。


提示:以下是本篇文章正文内容,下面案例可供参考

一、脚本阅读注意事项

0、注意事项:a、python3.11版本b、es 6.8.13版本(其余版本es没有演练过)c、该脚本全程通过elasticdump插件进行索引的备份与恢复d、依赖的模块在requirements.txt文件中,在新机器中执行pip3 install -r requirements.txt 安装即可1、esdump_back.py脚本的作用:a、实现es集群索引备份b、实现es集群索引恢复c、实现两个网络互通的es集群直接迁移索引(通过nc命令判断网络是否互通)2、具体功能:a、将相关配置写入到json文件中,通过解析json文件拿到配置配置文件包含源(目的)es集群以下配置:用户名密码地址需要迁移的索引名称需要迁移的索引相关类型(例如索引的analyzer、mapping、data、settings...)存放备份好的索引数据目录日志文件b、有两种模式a、判断源es与目的es是否互通,如果通,则执行脚本时调用配置文件中pong配置b、如果不通,则在源机器上执行脚本时调用配置文件esdump_source配置,自行下载上传备份文件至目标机器后,在目标机器上执行脚本时调用配置文件esdump_dest配置c、支持迁移索引时,将迁移的索引名、大小保存到日志文件中3、执行步骤:a、源es与目的es网络互通python3 esdump_backup.py pongb、源es与目的es网络不通源es执行索引备份: python3 esdump_backup.py esdump_source目的es执行索引恢复: python3 esdump_backup.py esdump_dest4、日志文件:随着脚本的启动产生日志文件位置: 与脚本同级位置日志文件名称: esdump.log

二、模块文件的产生与安装

	模块导出到requirements.txt文件pip freeze > requirements.txt
	安装requirements.txt文件pip install -r requirements.txt

三、脚本依赖的配置文件详解

config.json
可以在配置文件中添加对应的配置,执行简单

{"pong" : {                                             #两个网络互通的es集群直接迁移索引时,脚本的位置参数"source": {"source_index": ["xxx-search-test-v1"],        #源索引名称(有几个,添加几个。格式["xx","xxx"])"source_type": ["analyzer","mapping","data"],  #源索引依赖的类型(需要什么添加什么就行,例如分词、mapping、data、settings...)"endpoints": "xx.xx.xx.xx:9200",               #源es地址"es_user": "xx",                            #源es用户"es_password": "xx"                         #源es密码},"dest": {"es_user": "xx",                            #目的es用户"es_password": "xx",                        #目的es密码"dest_type": ["analyzer","mapping","data"],    #目的es索引依赖的类型(源es索引有什么类型,目的索引也必要有)"endpoints": "xxx.xxx.xxx.xx:9200"             #目的es地址}},"esdump_source": {                                     #源es执行索引备份时,脚本的位置参数"source_index": ["xxx-search-test-v1"],"source_type": ["analyzer","mapping","data"],"endpoints": "xxx.xxx.xxx.xx:9200","es_user": "xx","es_password": "xx","source_backupdir": "/export/backup/"              #源es索引备份后存放的目录},"esdump_dest": {                                       #目的es执行索引恢复时,脚本的位置参数"es_user": "xx","es_password": "xx","dest_type": ["analyzer","mapping","data"],"endpoints": "xxx.xxx.xxx.xx:9200","dest_backupdir": "/export/backup/"               #源es执行索引备份后上传到目的服务器的目录位置}
}

四、python代码

代码如下(示例)esdump_back.py :

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#author: wxd
#date: 2024/04/13 20:08:13
import json
import os
import subprocess
import sys
import logging
import requests
from requests.auth import HTTPBasicAuth
from elasticsearch import Elasticsearch
from elasticsearch.client import IndicesClientelasdump_dir = "/usr/local/bin/elasticdump"
nc_dir="/usr/bin/nc"
# 配置日志记录
logging.basicConfig(filename='esdump.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# 连接es集群
def connect_es(value):url = "http://{}".format(value["endpoints"])es = Elasticsearch([url], http_auth=(value["es_user"], value["es_password"]),verify_certs=False)return es
# 检查并安装elasticdump工具
def check_and_install_tool():try:# 检查工具是否存在if not os.path.exists(elasdump_dir) and not os.path.exists(nc_dir):logging.info("elasticdump和nc 工具未找到,开始安装...")install_esdump = "yum -y install npm nodejs nc && npm config set registry https://registry.npmmirror.com/ && npm install elasticdump -g"install_result = subprocess.run(install_esdump, shell=True, capture_output=True, text=True)if install_result.returncode != 0:logging.error("安装 elasticdump、nc 工具失败: %s", install_result.stderr)return Falseelse:logging.info("elasticdump、nc 工具安装成功")return Trueelse:logging.info("elasticdump、nc 工具已安装")return Trueexcept Exception as e:logging.error("安装工具异常: %s", e)return False
#获取索引信息
def get_index_stats(endpoint, index_name,user,password):try:url = f"http://{endpoint}/{index_name}/_stats"response = requests.get(url,auth=HTTPBasicAuth(user, password))if response.status_code == 200 and response.status_code < 400:stats = response.json()#总文档数total_docs = stats["_all"]["primaries"]["docs"]["count"]#索引大小index_size = stats["_all"]["primaries"]["store"]["size_in_bytes"]return total_docs, index_sizeelse:logging.error(f"Failed to get stats for index {index_name}: {response.text}")return None, Noneexcept Exception as e:logging.error(f"获取索引信息异常: {e}")return None, None#索引备份操作
def esdump_back(value):# exist_ok=True 当设置为True时,如果目标目录已经存在,os.makedirs()函数不会引发错误,而是静默地忽略这种情况。如果设置为False(默认值),并且目标目录已经存在,那么会引发FileExistsError异常try:os.makedirs(value["source_backupdir"], exist_ok=True)# 执行备份脚本for item in value["source_index"]:for items in value["source_type"]:url = f'http://{value["es_user"]}:{value["es_password"]}@{value["endpoints"]}/{item}'dir=os.path.join(value["source_backupdir"],items)os.makedirs(dir,exist_ok=True)output_file = f'{dir}/{item}_{items}.json'commands = f'{elasdump_dir} --input {url} --output {output_file} --type={items} --limit=10000'result = subprocess.run(commands, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)if result.returncode == 0:logging.info(f"{items}备份命令 {commands} 执行成功")else:logging.error(f"{items}备份命令 {commands} 执行失败")logging.error(f'{items}命令失败原因是{result.stderr.decode("utf-8")}')except Exception as e:logging.error("备份索引异常: %s", e)return False#索引备份入口
def esdump_source(file):try:# 检查配置文件中是否存在 esdump_sourceif "esdump_source" not in file:logging.error("配置文件中未找到 'esdump_source' 键")return#判断es集群连接是否成功value = file["esdump_source"]es = connect_es(value)if not  es.ping():logging.error("ES集群连接失败")return# 判断工具安装是否成功if not check_and_install_tool():logging.error("未检测到所需工具或安装失败")return#执行索引备份入口logging.info("开始备份~~~")esdump_back(value)for idx in value["source_index"]:if es.indices.exists(idx):# 获取索引统计信息total_docs, index_size = get_index_stats(value["endpoints"], idx,value["es_user"],value["es_password"])if total_docs is not None and index_size is not None:logging.info(f"索引 '{idx}' 的总文档数: {total_docs}")logging.info(f"索引 '{idx}' 的大小: {index_size} bytes")else:logging.error(f"索引 '{idx}' 不存在")except Exception as e:logging.error("开启索引备份异常: %s", e)return False#索引恢复操作
def esdump_restore(value):try:#判断是否已存在索引恢复目录if not os.path.exists(value["dest_backupdir"]):logging.error(f'恢复索引备份失败 {value["dest_backupdir"]} 不存在')return#执行恢复脚本url = f'http://{value["es_user"]}:{value["es_password"]}@{value["endpoints"]}'# 读取配置中的类型列表types = value["dest_type"]for type_idx in types:dir_path = os.path.join(value["dest_backupdir"], type_idx)for file in os.listdir(dir_path):if file.endswith(f"_{type_idx}.json"):index_name = file.split("_")[0]input_file = os.path.join(dir_path, file)output_url = f"{url}/{index_name}"command = [elasdump_dir, "--input", input_file, "--output", output_url, f"--type={type_idx}","--limits=10000"]result =subprocess.run(command,stdout=subprocess.PIPE, stderr=subprocess.PIPE)if result.returncode == 0:logging.info(f"{type_idx}恢复命令 {command} 执行成功")else:logging.error(f"{type_idx}备份命令 {command} 执行失败:")logging.error(f'{type_idx}命令失败原因是{result.stderr.decode("utf-8")}')total_docs, index_size = get_index_stats(value["endpoints"], index_name,value["es_user"],value["es_password"])if total_docs is not None and index_size is not None:logging.info(f"索引 '{index_name}' 的总文档数: {total_docs}")logging.info(f"索引 '{index_name}' 的大小: {index_size} bytes")except Exception as e:logging.error("索引恢复异常: %s", e)return False
#将本地备份拷贝到目标机器,恢复入口
def esdump_dest(file):try:# 检查配置文件中是否存在 esdump_destif "esdump_dest" not in file:logging.error("配置文件中未找到 'esdump_dest' 键")return#判断es集群连接是否成功value = file["esdump_dest"]es = connect_es(value)if not es.ping():logging.error("ES集群连接失败")return#判断工具安装是否成功if not check_and_install_tool():logging.error("未检测到所需工具或安装失败")return#索引恢复入口logging.info("开始恢复~~~")esdump_restore(value)except Exception as e:logging.error("恢复索引异常: %s", e)return False#两台服务器网络相通,走这个索引迁移函数
def migrate_index(source_url, dest_url, source_index, source_type,source_es_user,source_es_password,dest_es_user,dest_es_password):try:# 执行索引迁移的逻辑commands = f'{elasdump_dir} --input http://{source_es_user}:{source_es_password}@{source_url}/{source_index} \--output http://{dest_es_user}:{dest_es_password}@{dest_url}/{source_index} --type={source_type} --limit=10000'result = subprocess.run(commands, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)if result.returncode != 0:logging.error(f"索引: {source_index}  命令: {commands} 执行失败")logging.error(f'索引: {source_index}  命令失败原因是: {result.stderr.decode("utf-8")}')return Falselogging.info(f"索引: {source_index}   命令: {commands} 执行成功")return Trueexcept Exception as e:logging.error("migrate_index函数迁移索引异常: %s", e)return Falsedef pong(file):try:# 检查配置文件中是否存在 esdump_sourceif "pong" not in file:logging.error("配置文件中未找到 'pong' 键")return#判断es集群连接是否成功value = file["pong"]source_es = connect_es(value["source"])dest_es= connect_es(value["dest"])if not source_es.ping() or not dest_es.ping():logging.error("源ES或目的ES集群连接失败")return# 判断工具安装是否成功if not check_and_install_tool():logging.error("未检测到所需工具或安装失败")return# 判断源es和目的es网络是否互通nc_command=f'{nc_dir} -zv {value["dest"]["endpoints"].split(":")[0]} {value["dest"]["endpoints"].split(":")[1]}'result_nc = subprocess.run(nc_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)if result_nc.returncode != 0:logging.error(f"命令: {nc_command} 执行失败,网络不通")logging.error(f'命令失败返回的结果是: {result_nc.stderr.decode("utf-8")}')return#执行索引迁移for source_index in value["source"]["source_index"]:if source_es.indices.exists(source_index):# 获取源索引统计信息total_docs, index_size = get_index_stats(value["source"]["endpoints"],source_index,value["source"]["es_user"],value["source"]["es_password"])if total_docs is not None and index_size is not None:logging.info(f"源索引 '{source_index}' 的总文档数: {total_docs}")logging.info(f"源索引 '{source_index}' 的大小: {index_size} bytes")for source_type in value["source"]["source_type"]:success=migrate_index(value["source"]["endpoints"],value["dest"]["endpoints"],source_index,source_type,value["source"]["es_user"],value["source"]["es_password"],value["dest"]["es_user"],value["dest"]["es_password"])if success:logging.info("等待索引迁移完毕...")# 获取迁移后索引的信息total_docs, index_size = get_index_stats(value["dest"]["endpoints"],source_index,value["dest"]["es_user"],value["dest"]["es_password"])if total_docs is not None and index_size is not None:logging.info(f"目的索引 '{source_index}' 迁移后的总文档数: {total_docs}")logging.info(f"目的索引 '{source_index}' 迁移后的大小: {index_size} bytes")else:logging.error("索引迁移失败")except Exception as e:logging.error("不同集群间迁移索引异常: %s", e)return Falseif __name__ == "__main__":if len(sys.argv) != 2:print("Usage: python script.py pong|esdump_source|esdump_dest")else:with open("config.json", "r") as file:response_file = json.load(file)command = sys.argv[1]if command == "pong" and "pong" in response_file:pong(response_file)if command == "esdump_source" and "esdump_source" in response_file:esdump_source(response_file)if command == "esdump_dest" and "esdump_dest" in response_file:esdump_dest(response_file)

五、执行脚本示例

	源es与目的es网络互通[root@python1 esdump]# python3 esdump_backup.py pong  #此处的pong就是config.json文件中第一行指定的key[root@python1 esdump]# tail -f esdump.log2024-04-13 18:22:43,694 - INFO - HEAD http://xxx.xxx.xxx.xxx:9200/ [status:200 request:0.003s]2024-04-13 18:22:43,694 - INFO - elasticdump、nc 工具已安装2024-04-13 18:22:43,709 - INFO - HEAD http://xxx.xxx.xxx.xxx:9200/xxx-search-test-v1 [status:200 request:0.003s]2024-04-13 18:22:43,721 - INFO - 源索引 'xxx-search-test-v1' 的总文档数: 14372024-04-13 18:22:43,721 - INFO - 源索引 'xxx-search-test-v1' 的大小: 17846006 bytes2024-04-13 18:23:14,688 - INFO - 索引: xxx-search-test-v1   命令: /usr/local/bin/elasticdump --input http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1  --output http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1 --type=analyzer --limit=10000 执行成功2024-04-13 18:23:15,609 - INFO - 索引: xxx-search-test-v1   命令: /usr/local/bin/elasticdump --input http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1  --output http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1 --type=mapping --limit=10000 执行成功2024-04-13 18:23:25,345 - INFO - 索引: xxx-search-test-v1   命令: /usr/local/bin/elasticdump --input http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1  --output http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1 --type=data --limit=10000 执行成功2024-04-13 18:23:25,345 - INFO - 等待索引迁移完毕...2024-04-13 18:23:25,374 - INFO - 目的索引 'xxx-search-test-v1' 迁移后的总文档数: 14372024-04-13 18:23:25,374 - INFO - 目的索引 'xxx-search-test-v1' 迁移后的大小: 15417346 bytes
	源es与目的es网络不通源es执行索引备份:[root@python1 esdump]# python3 esdump_backup.py esdump_source[root@python1 esdump]# tail -f esdump.log2024-04-13 18:24:25,542 - INFO - HEAD http://xxx.xxx.xxx.xxx:9200/ [status:200 request:0.009s]2024-04-13 18:24:25,542 - INFO - elasticdump、nc 工具已安装2024-04-13 18:24:25,542 - INFO - 开始备份~~~2024-04-13 18:24:26,319 - INFO - analyzer备份命令 /usr/local/bin/elasticdump --input http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1 --output /export/backup/analyzer/xxx-search-test-v1_analyzer.json --type=analyzer --limit=10000 执行成功2024-04-13 18:24:27,278 - INFO - mapping备份命令 /usr/local/bin/elasticdump --input http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1 --output /export/backup/mapping/xxx-search-test-v1_mapping.json --type=mapping --limit=10000 执行成功2024-04-13 18:24:28,613 - INFO - data备份命令 /usr/local/bin/elasticdump --input http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1 --output /export/backup/data/xxx-search-test-v1_data.json --type=data --limit=10000 执行成功2024-04-13 18:24:28,618 - INFO - HEAD http://xxx.xxx.xxx.xxx:9200/xxx-search-test-v1 [status:200 request:0.004s]2024-04-13 18:24:28,644 - INFO - 索引 'xxx-search-test-v1' 的总文档数: 14372024-04-13 18:24:28,645 - INFO - 索引 'xxx-search-test-v1' 的大小: 17846006 bytes
	源es与目的es网络不通目的es执行索引恢复:[root@python1 esdump]# python3 esdump_backup.py esdump_dest[root@python1 esdump]# tail -f esdump.log2024-04-13 18:25:05,002 - INFO - HEAD http://xxx.xxx.xxx.xxx:9200/ [status:200 request:0.004s]2024-04-13 18:25:05,002 - INFO - elasticdump、nc 工具已安装2024-04-13 18:25:05,002 - INFO - 开始恢复~~~2024-04-13 18:25:36,020 - INFO - analyzer恢复命令 ['/usr/local/bin/elasticdump', '--input', '/export/backup/analyzer/xxx-search-test-v1_analyzer.json', '--output', 'http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1', '--type=analyzer', '--limits=10000'] 执行成功2024-04-13 18:25:36,728 - INFO - mapping恢复命令 ['/usr/local/bin/elasticdump', '--input', '/export/backup/mapping/xxx-search-test-v1_mapping.json', '--output', 'http://xx:xx@xxx.xxx.xxx.xxx:9200/xxx-search-test-v1', '--type=mapping', '--limits=10000'] 执行成功2024-04-13 18:25:57,440 - INFO - data恢复命令 ['/usr/local/bin/elasticdump', '--input', '/export/backup/data/xxx-search-test-v1_data.json', '--output', 'http://xx:xx@xxx.xxx.xxx.xxx:9200/huizhanyun-search-test-v1', '--type=data', '--limits=10000'] 执行成功2024-04-13 18:25:57,458 - INFO - 索引 'xxx-search-test-v1' 的总文档数: 14372024-04-13 18:25:57,458 - INFO - 索引 'xxx-search-test-v1' 的大小: 17456898 bytes

总结

以上就是今天的python脚本内容分享,因为最近刚好在学python,趁此机会强化一下自身的python基础,夯实自身.多了解一些python自动化运维常用的模块及json序列化,加油,奥里给!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【opencv】示例-npr_demo.cpp 非真实感渲染:边缘保留平滑、细节增强、铅笔素描/彩色铅笔绘图和风格化处理...

Edge Preserve Smoothing- Using Normalized convolution Filter Edge Preserve Smoothing-Using Recursive Filter Detail Enhancement Pencil sketch/Color Pencil Drawing Stylization /* * npr_demo.cpp * * 作者: * Siddharth Kherada <siddharthkherada27[at]gmail[do…

JavaScript代码挑战

让我们回到朱莉娅和凯特关于狗的研究。这次&#xff0c;他们想把狗的年龄转换成人的年龄&#xff0c;并计算出研究中狗的平均年龄。 创建一个函数 “calcAverageHumanAge”&#xff0c;该函数接受一个狗的年龄数组&#xff08;‘age’&#xff09;&#xff0c;并按顺序执行以下…

KDTree索引(K近邻搜索,半径R内近邻搜索)——PCL

K近邻搜索&#xff08;K Nearest Neighbors&#xff09; K近邻搜索是一种基于点数量的搜索方法&#xff0c;它会找到指定点附近最接近的K个邻居点。K近邻搜索中的K值是一个参数&#xff0c;您需要指定要搜索的邻居数量。该方法适用于需要查找固定数量邻居点的情况&#xff0c;…

Redis队列与Stream

Redis队列与Stream、Redis 6多线程详解 Redis队列与StreamStream总述常用操作命令生产端消费端单消费者消费组消息消费 Redis队列几种实现的总结基于List的 LPUSHBRPOP 的实现基于Sorted-Set的实现PUB/SUB&#xff0c;订阅/发布模式基于Stream类型的实现与Java的集成消息队列问…

.NET/C#汇总 —— 集合、异常、泛型、LINQ、委托、EF

集合 1. IList 接⼝与List的区别是什么? IList 泛型接⼝是 Icollection 接⼝的⼦代,并且是所有⾮泛型列表的基接⼝。 Ilist 实现有三种类别:只 读、固定⼤⼩、可变⼤⼩。 ⽆法修改只读 Ilist。 固定⼤⼩的 Ilist 不允许添加或移除元素,但允许修改 现有元素。 可变⼤⼩的 I…

Django模型入门

Django模型入门 为了能够学会使用Django模型&#xff0c;本节通过构建一个实际的Django模型来帮助读者尽快入门。 3.2.1 定义模型 既然Django模型实现了ORM功能&#xff0c;那么它就是对数据库实例的描述和实现。下面&#xff0c;我们通过一个简单的实例进行讲解。 如果需…

C语言-详解内存函数

文章目录 1.memcpy使用和模拟实现1.1 memcpy函数的使用规则1.2 memcpy函数的使用1.2 模拟实现memcpy函数 2.memmove 函数的使用和模拟实现2.1 memmove 函数使用规则2.2 memmove函数的使用2.3 模拟实现memmove函数2.3.1 从后往前移2.3.2 从前往后移 2.4 算法实现2.4.1 从前往后移…

机器学习之特征选择(Feature Selection)

1 引言 特征提取和特征选择作为机器学习的重点内容&#xff0c;可以将原始数据转换为更能代表预测模型的潜在问题和特征的过程&#xff0c;可以通过挑选最相关的特征&#xff0c;提取特征和创造特征来实现。要想学习特征选择必然要了解什么是特征提取和特征创造&#xff0c;得…

算法100例(持续更新)

算法100道经典例子&#xff0c;按算法与数据结构分类 1、祖玛游戏2、找下一个更大的值3、换根树状dp4、一笔画完所有边5、树状数组&#xff0c;数字1e9映射到下标1e56、最长回文子序列7、超级洗衣机&#xff0c;正负值传递次数8、Dijkstra9、背包问题&#xff0c;01背包和完全背…

React Hooks 全解: 常用 Hooks 及使用场景详解

React Hooks 是 React 16.8 版本引入的一项重要特性,它极大地简化和优化了函数组件的开发过程。 React 中常用的 10 个 Hooks,包括 useState、useEffect、useContext、useReducer、useCallback、useMemo、useRef、useLayoutEffect、useImperativeHandle 和 useDebugValue。这些…

计算机网络——实现smtp和pop3邮件客户端

实验目的 运用各种编程语言实现基于 smtp 协议的 Email 客户端软件。 实验内容 1. 选择合适的编程语言编程实现基于 smtp 协议的 Email 客户端软件。 2. 安装 Email 服务器或选择已有的 Email 服务器&#xff0c;验证自己的 Email 客户端软件是否能进行正常的 Email 收发功…

GAMS104 现代游戏引擎 2

渲染的难点可以分为一下三部分&#xff1a;如何计算入射光线、如何考虑材质以及如何实现全局光照。 渲染的难点之一在于阴影&#xff0c;或者说是光的可见性。如何做出合适的阴影效果远比想象中要难得多&#xff0c;在实践中往往需要通过大量的技巧才能实现符合人认知的阴影效…

基于React Router6 TS实现路由守卫

定义路由表 import {BrowserRouter, Route, RouteObject, Routes,} from "react-router-dom"; import {Home, Login, NotFound} from "/views"; import {RouterGuard} from "/routers/router_guard.tsx"; import {ReactNode} from "react&…

js实现webp转png/jpg

网上保存的图片是webp类型的&#xff0c;但是我把它嵌入flac格式的音频里后导致网页中无法播放 wps要会员&#xff0c;真麻烦。 完整代码&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head> <meta charset"UTF-8">…

OpenHarmony实例应用:【常用组件和容器低代码】

介绍 本篇Codelab是基于ArkTS语言的低代码开发方式实现的一个简单实例。具体实现功能如下&#xff1a; 创建一个低代码工程。通过拖拽的方式实现任务列表和任务信息界面的界面布局。在UI编辑界面实现数据动态渲染和事件的绑定。 最终实现效果如下&#xff1a; 相关概念 低代…

leetcode刷题记录 day21

每日一题 找到冠军 I 一场比赛中共有 n 支队伍&#xff0c;按从 0 到 n - 1 编号。 给你一个下标从 0 开始、大小为 n * n 的二维布尔矩阵 grid 。对于满足 0 < i, j < n - 1 且 i ! j 的所有 i, j &#xff1a;如果 grid[i][j] 1&#xff0c;那么 i 队比 j 队 强 &a…

Tuxera Ntfs for mac 2023中文解锁版安装、密钥下载与激活教程 Tuxera激活码 tuxera破解

Tuxera Ntfs for mac2023是Mac中专用于读写外置存储的工具&#xff0c;具有强大的磁盘管理和修复功能&#xff0c;它在Mac上完全读写NTFS格式硬盘&#xff0c;快捷的访问、编辑、存储和传输文件。能够在 Mac 上读写 Windows NTFS 文件系统。Tuxera NTFS 实现在Mac OS X系统读写…

2024妈妈杯数学建模A 题思路分析-移动通信网络中 PCI 规划问题

# 1 赛题 A 题 移动通信网络中 PCI 规划问题 物理小区识别码(PCI)规划是移动通信网络中下行链路层上&#xff0c;对各覆盖 小区编号进行合理配置&#xff0c;以避免 PCI 冲突、 PCI 混淆以及 PCI 模 3 干扰等 现象。 PCI 规划对于减少物理层的小区间互相干扰(ICI)&#xff0c;增…

Java基础_19 IO流【重点】

1.File类会将此磁盘上面的文件或者文件夹抽象成为一个对象&#xff0c;可以拿对象调用方法来对咱们的文件或者文件夹操作(创建,删除&#xff0c;各种判断&#xff0c;查询)File类很多的方法createNewFilemkdirmkdirsdeleteisFileisDirectorygetNamegetPathgetParent2.递归算法【…

mysql搭建主从

mysql搭建主从: 1:拉取mysql镜像 docker pull mysql2:创建主从对应目录 3:建立一个简易的mysql docker run -it --name mytest -e MYSQL_ROOT_PASSWORD123 -d mysql4:进入这个简易的mysql;从中获取my.cnf文件 docker exec -it mytest bash5:从容器中将my.cnf拷贝到 /3306/c…