AI模型部署:一文搞定Triton Inference Server的常用基础配置和功能特性

前言

Triton Inference Server是由NVIDIA提供的一个开源模型推理框架,在前文《AI模型部署:Triton Inference Server模型部署框架简介和快速实践》中对Triton做了简介和快速实践,本文对Triton的常用配置和功能特性做进一步的汇总整理,并配合一些案例来进行实践,本文以Python作为Triton的后端。


内容摘要
  • 数据维度配置
  • 数据类型配置
  • 模型状态管理
  • 模型版本管理
  • 服务端前处理
  • 服务端后处理
  • 执行实例设置和并发(见下一节)
  • 模型预热(见下一节)
  • 动态批处理(见下一节)

数据维度配置

数据维度是模型训练过程中就已经提前约定的,客户端和服务端都需要按照这个约定进行维度设置。在模型的配置文件config.pbtxt中有两个参数决定输入输出的维度,分别是max_batch_size和dims,一个config.pbtxt的例子如下

name: "linear"
backend: "python"max_batch_size: 4
input [{name: "x"data_type: TYPE_FP32dims: [ 3 ]}
]
output [{name: "y"data_type: TYPE_FP32dims: [ 1 ]}
]

在这个config.pbtxt中,输入x的维度是[batch, 3]的矩阵,输出y的维度是[batch, 1],其中batch最大是4,即一次推理最多接收4条样本。当max_batch_size大于0时,max_batch_size和dims一起决定输出和输出的维度,max_batch_size会作为第一维,dims代表从第二维开始每个维度的尺寸,当max_batch_size等于0时,dims就是实际的维度,此时dims的第一维就代表batch_size,例如以下config.pbtxt

name: "linear"
backend: "python"max_batch_size: 0
input [{name: "x"data_type: TYPE_FP32dims: [ 3, 3 ]}
]
output [{name: "y"data_type: TYPE_FP32dims: [ 3, 1 ]}
]

此时输入输出的维度固定batch_size为3,请求的客户端传入的数据的batch_size必须也是3,否则客户端会报维度错误,类似如下

{'error': "unexpected shape for input 'x' for model 'linear'. Expected [3,3], got [5,3]"}

特殊的,如果输入或者输出是不定长的,比如输出的是文本数据,每个批次之间的tokenizer后的长度可以不想等,此时可以将dims中的对应位置设置为-1,例如

max_batch_size: 0
input [{name: "x"data_type: TYPE_STRINGdims: [ -1 ]}
]

该config.pbtxt代表输入x是TYPE_STRING类型,长度不定,每次只能输入一条文本。
额外的可以在输出输出的配置中添加reshape属性,来适配客户端传过来的数据维度和模型需要的维度不完全符合的场景,假设有一个模型结构如下

class Model(nn.Module):def __init__(self):super(Model, self).__init__()self.linear = nn.Linear(3, 10)def forward(self, x):return self.linear(x).sum(dim=1, keepdim=True)

该模型要求输入的维度是[batch_size, 3],输出的维度是[batch_size, 1],而客户端传入的是一个长度为3的向量,要求输出是一个长度为1的向量,此时在config.pbtxt中reshape来弥合两者的差异,服务端配置如下

max_batch_size: 0
input [{name: "x"data_type: TYPE_FP32dims: [ 3 ]reshape { shape : [ 1 , 3 ] }}
]
output [{name: "y"data_type: TYPE_FP32dims: [ 1, 1 ]reshape { shape : [ 1 ] }}
]

客户端请求如下

raw_data = {"inputs": [{"name": "x","datatype": "FP32","shape": [3],"data": [2.0, 3.0, 4.0]}],"outputs": [{"name": "y"}]}

reshape将原始输入由[3]转化为[1, 3],在triton的日志中能够看到输入在经过推理之前已经被提前转化为了[1, 3]

2024-03-25 03:43:16,138 - model.py[line:103] - INFO: {'x': array([[2., 3., 4.]], dtype=float32)}

如果不添加reshape,则需要在服务端或者客户端进行数据匹配改造,否则推理会报错。


数据类型配置

config.pbtxt中支持的数据类型如下表中的Model Config,第二列API代表该类型对应的在Triton Inference Server后端C API和HTTP,GRPC协议中的数据类型,最后一列NumPy代表其对应在Python Numpy中的数据类型。

Model ConfigAPINumPy
TYPE_BOOLBOOLbool
TYPE_UINT8UINT8uint8
TYPE_UINT16UINT16uint16
TYPE_UINT32UINT32uint32
TYPE_UINT64UINT64uint64
TYPE_INT8INT8int8
TYPE_INT16INT16int16
TYPE_INT32INT32int32
TYPE_INT64INT64int64
TYPE_FP16FP16float16
TYPE_FP32FP32float32
TYPE_FP64FP64float64
TYPE_STRINGBYTESdtype(object)

这里对String字符串类型做简要说明,在自然语言任务中,客户端传入的是字符串,经过HTTP/GRPC协议后返回给Triton Inference Server后端的数据为编码后的BYTES字节数组,需要在后端逻辑中对数据进行解码转化为字符串,例如在客户端请求为

raw_data = {"inputs": [{"name": "x","datatype": "BYTES","shape": [2, 1],"data": ["你是", "我是"],}]...}response = requests.post(url=url, data=json.dumps(raw_data, ensure_ascii=True), headers={"Content_Type": "application/json"}, timeout=2000)

请求为传入两条文本作为一个批次,维度指定为[2, 1],服务端的解码逻辑,解码后拿到对应的请求字符串

        for request in requests:# [[b'\xe4\xbd\xa0\xe6\x98\xaf'],[b'\xe6\x88\x91\xe6\x98\xaf']]x = pb_utils.get_input_tensor_by_name(request, "x").as_numpy()# ['你是', '我是']x = np.char.decode(x, "utf-8").squeeze(1).tolist()

模型状态管理

模型状态管理包括模型的加载、卸载、切换等工作,Triton Inference Server通过启动命令tritonserver下的参数**–model-control-mode**来设置模型管理策略,它有以下三种设置方式

  • none:默认设置,该模式下Triton将会将所有在model_repository下的模型在启动的时候全部加载,并且在启动之后也不会感知到模型文件的改动
  • poll:poll模式,Triton将会轮询探查模型文件是否有变动,如果有变动Triton将会自动对模型进行重新加载,探查的频率将有参数–repository-poll-secs进行控制,该参数代表两次检查模型文件间的轮询间隔时间秒
  • explicit:explicit模式,Triton在启动的时候将不会自动加载模型,只能手动指定–load-model来加载指定的模型,或者使用API的方式逐个加载模型

在none和poll模式下,Triton Inference Server在启动阶段都会将所有model_repository下的模型进行加载,区别在于是否会感知到模型文件的变动,以none为例,我们请求一个线性模型,在首次推理之后修改model.py文件,改为直接输出一个固定值

# 首次推理结果
{'model_name': 'linear', 'model_version': '1', 'outputs': [{'name': 'y', 'datatype': 'FP32', 'shape': [1, 1], 'data': [-0.21258652210235596]}]}

修改model.py,写死为输出-100.0

# TODO 推理结果
# y = self.model(torch.tensor(x).float())
y = torch.tensor([[-100.0]])

重新请求结果不变

{'model_name': 'linear', 'model_version': '1', 'outputs': [{'name': 'y', 'datatype': 'FP32', 'shape': [1, 1], 'data': [-0.21258652210235596]}]}

将模型管理改为poll重新启动Triton服务,并且设置探查间隔为10秒

docker run --rm -p18999:8000 -p18998:8001 -p18997:8002 \
-v /home/model_repository/:/models \
nvcr.io/nvidia/tritonserver:21.02-py3 \
tritonserver \
--model-repository=/models \
--model-control-mode poll \
--repository-poll-secs=10

重复刚才的更改,在model.py更改完成后,Triton日志打印出模型reload信息,并提示新的模型已经加载成功

I0328 02:53:25.407021 1 model_repository_manager.cc:775] re-loading: linear:1
Cleaning up...
I0328 02:53:25.577220 1 model_repository_manager.cc:943] successfully unloaded 'linear' version 1
I0328 02:53:25.577251 1 model_repository_manager.cc:787] loading: linear:1
2024-03-28 02:53:27,687 - model.py[line:60] - INFO: model init success
I0328 02:53:27.687756 1 model_repository_manager.cc:960] successfully loaded 'linear' version 1

此时再请求该服务,输出结果为更改模型之后的结果。

{'model_name': 'linear', 'model_version': '1', 'outputs': [{'name': 'y', 'datatype': 'FP32', 'shape': [1, 1], 'data': [-100.0]}]}

当Triton重新加载改动后的模型时,如果由于任何原因重新加载失败,则已加载模型将保持不变,如果重新加载成功,新加载的模型将替换已经加载的模型,因此模型文件变动的过程中不会丢失模型的可用性。但是官方文档指出poll模式存在同步的问题,某些时候poll可能只能观察到部分不完成的变动,因此不建议在生产环境使用poll模式。
explicit模式可以指定模型仓库下哪些模型提供服务,哪些不提供服务,启动如下

docker run --rm -p18999:8000 -p18998:8001 -p18997:8002 \
-v /home/model_repository/:/models \
nvcr.io/nvidia/tritonserver:21.02-py3 \
tritonserver \
--model-repository=/models \
--model-control-mode explicit

启动后Triton服务日志显示在服务的模型为空

I0328 03:01:41.811390 1 server.cc:538] 
+-------+---------+--------+
| Model | Version | Status |
+-------+---------+--------+
+-------+---------+--------+

如果不指定–load-model,默认Triton不加加载任何模型,可以使用–load-model添加模型加载在Triton启动的时候,命令如下

docker run --rm -p18999:8000 -p18998:8001 -p18997:8002 \
-v /home/model_repository/:/models \
nvcr.io/nvidia/tritonserver:21.02-py3 \
tritonserver --model-repository=/models \
--model-control-mode explicit \
--load-model linear \
--load-model reshape_test

如果需要启动多个模型就写多个–load-model语句,本例中启动了两个,启动日志显示两个模型已经READY

I0328 03:05:04.416497 1 server.cc:538] 
+--------------+---------+--------+
| Model        | Version | Status |
+--------------+---------+--------+
| linear       | 1       | READY  |
| reshape_test | 1       | READY  |
+--------------+---------+--------+

除此之外,explicit模式可以自由的使用HTTP API请求对模型进行加载和卸载,语句如下

# 加载
curl -X POST http://0.0.0.0:18999/v2/repository/models/sentiment/load
# 卸载
curl -X POST http://0.0.0.0:18999/v2/repository/models/sentiment/unload

还可以通过以下语句查看模型仓库下的所有模型和其服务状态

curl -X POST http://0.0.0.0:18999/v2/repository/indexp://0.0.0.0:18999/v2/repository/index
[{"name": "linear","version": "1","state": "READY"},{"name": "reshape_test","version": "1","state": "READY"},{"name": "sentiment"},{"name": "string"},{"name": "string_batch"}
]

explicit模式也无法自动感知到模型的改动,但是如果相对一个已经加载的模型做重新加载,可以手动load一次,此时如果模型有变动则会reload,效果和poll模式一样,如果错误保持在上一个版本模型,如果成功则替换,如果模型没有变动则此时load指定不会发生任何效果

curl -X POST http://0.0.0.0:18999/v2/repository/models/linear/load

此时Triton的日志同样会提示重新reload模型

I0328 05:39:41.889621 1 model_repository_manager.cc:775] re-loading: linear:1
Cleaning up...
I0328 05:39:42.083909 1 model_repository_manager.cc:943] successfully unloaded 'linear' version 1
I0328 05:39:42.083951 1 model_repository_manager.cc:787] loading: linear:1
I0328 05:39:42.185208 1 python.cc:615] TRITONBACKEND_ModelInstanceInitialize: linear_0 (CPU device 0)
2024-03-28 05:39:44,194 - model.py[line:60] - INFO: model init success
I0328 05:39:44.194935 1 model_repository_manager.cc:960] successfully loaded 'linear' version 1

注意如果模型目录下没有任何改动,此时发送load的请求没有任何作用。


模型版本管理

模型和配置信息存储在model_repository目录下,下一层存放了各个需要部署的模型,每个模型作为一个目录,以linear为例,它下一层存放了多个版本,以数字id作为文件夹区分,例如

root@jump-1:/home/model_repository/linear# tree
.
├── 1
│   ├── linear
│   │   └── pytorch_model.bin
│   └── model.py
├── 2
│   ├── linear
│   │   └── pytorch_model.bin
│   └── model.py
└── config.pbtxt

Triton Inference Server启动后可以看到对于linear模型的2版本已经READY状态,这里的2值得是版本2,而不是一共有2个版本,暗示着linear的版本1已经不可用

ModelVersionStatus
linear2READY
reshape_test1READY
string1READY
string_batch1READY

在客户端以HTTP请求为例,推理请求范例如下

POST v2/models/${MODEL_NAME}[/versions/${MODEL_VERSION}]/infer

其中versions是可选的,如果需要请求不同版本的模型的结果,需要在url中带上versions版本号,我们以同样的数据分别请求linear的两个版本,先请求版本1,代码如下

# 请求模型版本1
url = "http://0.0.0.0:18999/v2/models/linear/versions/1/infer"
response = requests.post(url=url,data=json.dumps(raw_data, ensure_ascii=True),headers={"Content_Type": "application/json"},timeout=2000)

返回报错linear模型没有版本1

{'error': "Request for unknown model: 'linear' version 1 is not found"}

再请求版本2,只需要更换一下url中的数字即可

url = "http://0.0.0.0:18999/v2/models/linear/versions/2/infer"

返回结果正常,获得了模型推理的结果

{'model_name': 'linear', 'model_version': '2', 'outputs': [{'name': 'y', 'datatype': 'FP32', 'shape': [1, 1], 'data': [-2.7400970458984375]}]}

版本1访问不了,原因是Triton Inference Server默认只允许最大的那个版本号提供服务,忽略其他版本号,如果要让其他版本也能正常服务,需要在config.pbtxt中增加配置项version_policy,有三种设置情况

version_policy: { all { }}
version_policy: { latest: { num_versions: 2}}
version_policy: { specific: { versions: [1,3]}}

第一种指定所有版本皆可进行服务,第二种指定版本号最大的topN个版本可以被服务,第三种指定一个版本号列表,该列表中的版本号模型可以被服务。
我们把上面的config.pbtxt修改为所有版本都可以被服务的模式,如下

name: "linear"
backend: "python"max_batch_size: 4
input [{name: "x"data_type: TYPE_FP32dims: [ 3 ]}
]
output [{name: "y"data_type: TYPE_FP32dims: [ 1 ]}
]
version_policy: { all {} }

重启服务,发现在启动日志中linear的1,2两个版本都已经进入READY状态

ModelVersionStatus
linear1READY
linear2READY
reshape_test1READY
string1READY
string_batch1READY

两个版本的请求结果分别如下

# 版本1
url = "http://0.0.0.0:18999/v2/models/linear/versions/1/infer"
{'model_name': 'linear', 'model_version': '1', 'outputs': [{'name': 'y', 'datatype': 'FP32', 'shape': [1, 1], 'data': [-0.21258652210235596]}]}
# 版本2
url = "http://0.0.0.0:18999/v2/models/linear/versions/2/infer"
{'model_name': 'linear', 'model_version': '2', 'outputs': [{'name': 'y', 'datatype': 'FP32', 'shape': [1, 1], 'data': [-2.7400970458984375]}]}

服务端前处理

在模型推理之前, 一般需要对数据进行前处理,处理成模型需要的数据形式,在以Python为后端的情况下很容易在TritonPythonModel中添加前后处理逻辑,它允许数据前处理放在服务端来实现,使得服务更加通用化,对客户端更加友好。
本例以自然语言处理中的tokenizer分词编码为例,将该过程添加到服务端逻辑中,使得客户端只需要输入自然语言即可完成想要的输出结果,任务以情感三分类为背景。

class TritonPythonModel:...def initialize(self, args):...model_path = os.path.dirname(os.path.abspath(__file__)) + "/sentiment"self.model = BertForSequenceClassification.from_pretrained(model_path).eval()self.tokenizer = BertTokenizer.from_pretrained(model_path)def execute(self, requests):responses = []for request in requests:text = pb_utils.get_input_tensor_by_name(request, "text").as_numpy()text = np.char.decode(text, "utf-8").squeeze(1).tolist()# 前处理,分词编码encoding = self.tokenizer.batch_encode_plus(text,max_length=512,add_special_tokens=True,return_token_type_ids=False,padding=True,return_attention_mask=True,return_tensors='pt',truncation=True)with torch.no_grad():outputs = self.model(**encoding)prob = softmax(outputs.logits, dim=1).detach().cpu().numpy()...def finalize(self):...

本例直接调用了HuggingFace的预训练情感分类模型,在推理之前使用分词编码器tokenizer将输入的中文编码为模型输入所需要的input_ids,attention_mask等,这块逻辑不需要客户端实现,直接在服务端实现, 客户端直接输入需要分类的文本即可,请求如下

    text = ["我爱你", "天气不好", "景色很不错"]url = "http://0.0.0.0:18999/v2/models/sentiment/infer"raw_data = {"inputs": [{"name": "text","datatype": "BYTES","shape": [3, 1],"data": text}],"outputs": [{"name": "prob","shape": [3, 1],}]}res = requests.post(url, json.dumps(raw_data, ensure_ascii=True), headers={"Content_Type": "application/json"},timeout=2000)print(json.loads(res.text)["outputs"][0]["data"])

分别对三个句子进行情感分类推理,返回结果如下

['0.09482009', '0.8857557', '0.019424219', '0.81316173', '0.16796581', '0.018872421', '0.3918507', '0.4720963', '0.13605309']

接口返回的data是一个长度为9的列表,接口将原始的[3, 3]的矩阵拉直为一个一维的列表。


服务端后处理

同服务端前处理,还是以情感分类为例,我们在推理结束之后,获取最大概率对应的下标,再映射为对应的情感标签,服务端代码做修改如下

label_map = {0: "负面", 1: "正向", 2: "中性"}with torch.no_grad():outputs = self.model(**encoding)prob = torch.nn.functional.softmax(outputs.logits, dim=1).argmax(dim=1).detach().cpu().numpy().tolist()prob = np.array([label_map[x].encode("utf8") for x in prob])out_tensor = pb_utils.Tensor("prob", prob.astype(self.output_response_dtype))
final_inference_response = pb_utils.InferenceResponse(output_tensors=[out_tensor])

重新请求,返回结果如下,直接返回了情感自然语言结果

['正向', '负面', '正向']

本篇介绍了Triton Inference Server的基础功能设置,下一篇将针对模型推理步骤中核心配置进行汇总整理。

如何系统的去学习大模型LLM ?

作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的 AI大模型资料 包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来

😝有需要的小伙伴,可以V扫描下方二维码免费领取🆓

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

在这里插入图片描述

四、AI大模型商业化落地方案

img

阶段1:AI大模型时代的基础理解

  • 目标:了解AI大模型的基本概念、发展历程和核心原理。
  • 内容
    • L1.1 人工智能简述与大模型起源
    • L1.2 大模型与通用人工智能
    • L1.3 GPT模型的发展历程
    • L1.4 模型工程
    • L1.4.1 知识大模型
    • L1.4.2 生产大模型
    • L1.4.3 模型工程方法论
    • L1.4.4 模型工程实践
    • L1.5 GPT应用案例

阶段2:AI大模型API应用开发工程

  • 目标:掌握AI大模型API的使用和开发,以及相关的编程技能。
  • 内容
    • L2.1 API接口
    • L2.1.1 OpenAI API接口
    • L2.1.2 Python接口接入
    • L2.1.3 BOT工具类框架
    • L2.1.4 代码示例
    • L2.2 Prompt框架
    • L2.2.1 什么是Prompt
    • L2.2.2 Prompt框架应用现状
    • L2.2.3 基于GPTAS的Prompt框架
    • L2.2.4 Prompt框架与Thought
    • L2.2.5 Prompt框架与提示词
    • L2.3 流水线工程
    • L2.3.1 流水线工程的概念
    • L2.3.2 流水线工程的优点
    • L2.3.3 流水线工程的应用
    • L2.4 总结与展望

阶段3:AI大模型应用架构实践

  • 目标:深入理解AI大模型的应用架构,并能够进行私有化部署。
  • 内容
    • L3.1 Agent模型框架
    • L3.1.1 Agent模型框架的设计理念
    • L3.1.2 Agent模型框架的核心组件
    • L3.1.3 Agent模型框架的实现细节
    • L3.2 MetaGPT
    • L3.2.1 MetaGPT的基本概念
    • L3.2.2 MetaGPT的工作原理
    • L3.2.3 MetaGPT的应用场景
    • L3.3 ChatGLM
    • L3.3.1 ChatGLM的特点
    • L3.3.2 ChatGLM的开发环境
    • L3.3.3 ChatGLM的使用示例
    • L3.4 LLAMA
    • L3.4.1 LLAMA的特点
    • L3.4.2 LLAMA的开发环境
    • L3.4.3 LLAMA的使用示例
    • L3.5 其他大模型介绍

阶段4:AI大模型私有化部署

  • 目标:掌握多种AI大模型的私有化部署,包括多模态和特定领域模型。
  • 内容
    • L4.1 模型私有化部署概述
    • L4.2 模型私有化部署的关键技术
    • L4.3 模型私有化部署的实施步骤
    • L4.4 模型私有化部署的应用场景

学习计划:

  • 阶段1:1-2个月,建立AI大模型的基础知识体系。
  • 阶段2:2-3个月,专注于API应用开发能力的提升。
  • 阶段3:3-4个月,深入实践AI大模型的应用架构和私有化部署。
  • 阶段4:4-5个月,专注于高级模型的应用和部署。
这份完整版的大模型 LLM 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

😝有需要的小伙伴,可以Vx扫描下方二维码免费领取🆓

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

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

相关文章

STM32单片机选型方法

一.STM32单片机选型方法 1.首先要确定需求: 性能需求:根据应用的复杂度和性能要求,选择合适的CPU性能和主频。 内存需求:确定所需的内存大小,包括RAM和Flash存储空间。 外设需求:根据应用所需的功能&…

2024年社会发展与城市规划国际会议(SDUP 2024)

2024年社会发展与城市规划国际会议(SDUP 2024) 2024 International Conference on Social Development and Urban Planning 【重要信息】 大会地点:杭州 大会官网:http://www.iacsdup.com 投稿邮箱:iacsdupsub-conf.co…

mysql和redis的双写一致性问题

一,使用方案 在使用redis作为缓存的场景下,我们一般使用流程如下 二,更新数据场景 我们此时修改个某条数据,如何保证mysql数据库和redis缓存中的数据一致呢? 按照常规思路有四种办法,1.先更新mysql数据&a…

周五美国股市总结,标普止步四日连涨,纳指五日连创新高,法股单周跌幅两年多最深

美国消费者信心意外下滑至七个月新低,通胀预期反弹,标普大盘脱离历史最高,道指连跌四日,罗素小盘股跌至六周新低,有分析称对经济担忧浮现。全周标普和纳指分别累涨1.6%和3.2%,都是八周里第七周上涨&#xf…

mysql和redis备份和恢复数据的笔记

一、mysql的备份及恢复方法: 1.完全备份与恢复 1.1物理备份与恢复 物理备份又叫冷备份,需停止数据库服务,适合线下服务器 备份数据流程: 第一步:制作备份文件 systemctl stop mysqld #创建存放备份文件的目录 mkdir /bakdir …

连锁门店收银系统源码!

1.系统概况 智慧新零售系统是一套针对零售行业的saas收银系统,线下线上一体化的收银系统。核心功能涵盖了线下收银、小程序商城、会员管理、50营销插件、ERP进销存管理、跑腿配送等行业解决方案。 2.适用行业及门店 智慧新零售是针对零售行业的saas收银系统&#…

一文入门vim

先来波快问快答。 第一个问题,vim是什么? vim就是一文本编辑器。 第二个问题,我们为什么要使用vim? 好像在终端中可选择使用的文本编辑器也不多(其他有,但是相对而言vim用的比较广泛) 第三…

Java核心(四)反射

这篇内容叫反射也不够准确,其实它更像是java类加载的一个延申。 Java类加载过程 之前解释过一个Java的类的加载过程,现在回顾一下类的加载: 类的加载指的是将类的字节码文件(.class文件)中数据读入到内存中&#xff…

C语言之数组

目录 一、数组的概念 二、一维数组的使用 数组的创建 数组的初始化 数组的使用 三、一维数组在内存中的存储 四、sizeof计算数组元素个数 五、二维数组的使用 数组的创建 数组的初始化 数组的使用 六、二维数组在内存中的存储 七、C99中的变长数组 八、总结 一、…

ComfyUI 宝藏插件之辅助工具

今天我们就来分享下这个 ComfyUI 辅助脚本工具的功能。 插件安装,小伙伴们直接在管理器里搜索「ComfyUI-Custom-Scripts」,点击安装就可以了,这里再告诉小伙伴们一个小技巧,点击名称可以跳转到插件所在的官网哦。 没有安装管理器…

Rust 实战丨并发构建倒排索引

引言 继上篇 Rust 实战丨倒排索引,本篇我们将参考《Rust 程序设计(第二版)》中并发编程篇章来实现高并发构建倒排索引。 本篇主要分为以下几个部分: 功能展示:展示我们最终实现的 2 个工具的效果(构建索…

Python武器库开发-武器库篇之SMB服务暴力破解(五十五)

Python武器库开发-武器库篇之SMB服务暴力破解(五十五) SMB服务(Server Message Block)是一种用于文件共享、打印机共享和其他资源共享的网络协议。它最初由IBM开发,后来被微软广泛采用。 SMB服务允许多台计算机在网络上共享文件和资源&…

笔记本硬盘对拷:升级硬盘的好方法!

如今电子产品更新换代的速度不断加快,笔记本电脑的配置也日新月异。几年前购买的笔记本硬盘容量350G曾经令你感到相当满意。但时至今日,这样的容量是否已经显得有些落后?如果你想要升级硬盘,笔记本硬盘对拷是一个很好的选择。 需要…

Radis初阶 Radis基本命令与在Springboot中访问Radis

阿里网盘链接 文章目录 初始NoSQL数据库对比MySQL数据库从结构方面:从关系方面:从查询方式:从事物方面: Redis入门Redis数据结构访问Radis通用命令(tab键:自动补全)KEYSDELEXISTSEXPIRETTL Str…

Liquibase(Oracle SQLcl集成版)简明示例

本文使用的是Oracle SQLcl中集成的Liquibase,而非开源版Liquibase。 Liquibase的快速入门可以参见Liquibase Core Concepts。需要了解一下概念: Change log:基于文本的更改日志文件按顺序列出对数据库所做的所有更改Change set:…

LabVIEW开发中的常见通讯协议详解

介绍LabVIEW开发中常见的通讯协议,包括RS-232、RS-485、I2C、SPI、CAN、Ethernet、Modbus和GPIB等。通过对各协议的具体内容、特点、使用范围及注意事项进行全面解析,帮助开发者选择合适的通讯协议,提高系统性能和可靠性。 1. RS-232 内容&a…

Python基础教程(十五):面向对象编程

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 💝&#x1f49…

DataFrames相关介绍文件读取

目录 1.初识DataFrame 2.DataFrame的构造函数 3.数据框的轴 4.CSV文件读取 5.Excel文件读取 1.初识DataFrame (1)昨天,我们学习了Series。而Pandas的另一种数据类型:DataFrame,在许多特性上和Series有相似之处。 …

Spring应用如何打印access日志和out日志(用于分析请求总共在服务耗费多长时间)

我们经常会被问到这样一个问题。你接口返回的好慢呀,能不能提升一下接口响应时间啊?这个时候我们就需要去分析,为什么慢,慢在哪。而这首先应该做的就是确定接口返回时间过长确实是在服务内消耗的时间。而不是我们将请求发给网关或…

字符串及其应用

内容 编写程序实现字符串的基本运算&#xff1a; (1) 求串的长度、两串连接、串比较、子串匹配&#xff1b; (2) 用库函数直接实现上一步的字符申操作 完整代码 #include <iostream> #include <stdio.h> #include<string.h> using namespace std; #define M…