Ubuntu部署ktransformers
准备工作
一台服务器
CPU:500G
GPU:48G(NVIDIA4090)
系统:Ubuntu20.04(github的文档好像用的是22.04)
第一步:下载权重文件
1.下载hfd
wget https://hf-mirror.com/hfd/hfd.sh
chmod a+x hfd.sh
2.设置环境变量
export HF_ENDPOINT=https://hf-mirror.com
3.下载模型(需要梯子,需要带上huggingface的token)
./hfd.sh gpt2
4.下载数据集(需要梯子,需要带上huggingface的token)
./hfd.sh wikitext --dataset
5.下载大文件(需要梯子,文件很大,大约四五百G)
./hfd.sh unsloth/DeepSeek-R1-GGUF --include DeepSeek-R1-Q4_K_M/*
第二步:拉代码,编译代码
1.使用Anaconda3安装Python3.11
conda create --name ktransformers python=3.11
conda activate ktransformers
conda install -c conda-forge libstdcxx-ng
2.安装其他依赖
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip3 install packaging ninja cpufeature numpy
sudo add-apt-repository ppa: ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install --only-upgrade libstdc++6
pip install flash-attn --no-build-isolation
3.查看显卡版本及cuda版本
以下两条指令显示的CUDA版本需要一致,若不一致,系统会以nvcc --version的为准
nvcc --version
nvidia-smi
4.拉代码
git clone https://github.com/kvcache-ai/ktransformers.git
cd ktransformers
git submodule init
git submodule update
5.编译
export USE_NUMA=1
make dev_install
第三部:运行
python ktransformers/local_chat.py --model_path deepseek-ai/DeepSeek-R1 --gguf_path /home/dpkj/deepseek/DeepSeek-R1-GGUF/DeepSeek-R1-Q4_K_M/ --cpu_infer 50 --cache_lens 1536 --max_new_tokens 8192
# --model_path:模型位置,不需要修改
# --gguf_path:前面下载的大文件,模型文件位置,按照实际情况而定
# --cpu_infer:CPU占用,单位百分比,如果服务器不死DDR5双路CPU,可以适量调低此占比
其他启动参数
python -m transformers.local_chat --model_path deepseek-ai/DeepSeek-R1 --gguf_path /root/DeepSeek-R1-GGUF/DeepSeek-R1-Q4_K_M/ --cpu_infer 53 --cache_lens 1536
python ./transformers/local_chat.py --model_path deepseek-ai/DeepSeek-R1 --gguf_path /home/shadeform/DeepSeek-R1-GGUF/DeepSeek-R1-Q4 K M/ --cpu_infer 53 --cache_lens 1536 --optimize_config_path transformers/optimize/optimize_rules/DeepSeek-V3-Chat-multi-gpu-marlin.yaml
python -m transformers.local_chat --model_path deepseek-ai/DeepSeek-R1 --gguf_path /root/autodi-tmp/DeepSeek-R1-GGUF/DeepSeek-R1-Q4 K M/ --cpu_infer 128 --cache_lens 1536 --max_new_tokens 8192 --optimize_config_path ./transformers/optimize/optimize_rules/DeepSeek-V3-Chat-multi-gpu-marlin-4.yaml
transformers --model_path deepseek-ai/DeepSeek-R1 --gguf_path /root/autodi-tmp/DeepSeek-R1-GGUF/DeepSeek-R1-Q4 K M/ --cpu_infer 65 --cache_lens 1536 --max_new_tokens 8192 --port 6006 --optimize_config_path /transformers/optimize/optimize_rules/DeepSeek-V3-Chat-multi-gpu-marlin-4.yaml
curl -X 'POST"
"http://localhost:6006/v1/chat/completions'\
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d'{
"messages": [
"content": "tell a joke",
"role": "user"
],
"model": "ktranformers-model",
"stream": true
}'
外传
1. 使用API方式调用
新建文件:chat_openai.py
import argparse
import uvicorn
from typing import List, Dict, Optional, Any
from fastapi import FastAPI, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import os
import sys
import time
from fastapi import Request
from fastapi.responses import StreamingResponse, JSONResponse
import json
import logging# 设置日志记录
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)project_dir = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, project_dir)
import torch
from transformers import (
AutoTokenizer,
AutoConfig,
AutoModelForCausalLM,
GenerationConfig,
TextStreamer,
)
from ktransformers.optimize.optimize import optimize_and_load_gguf
from ktransformers.models.modeling_deepseek import DeepseekV2ForCausalLM
from ktransformers.models.modeling_qwen2_moe import Qwen2MoeForCausalLM
from ktransformers.models.modeling_deepseek_v3 import DeepseekV3ForCausalLM
from ktransformers.models.modeling_llama import LlamaForCausalLM
from ktransformers.models.modeling_mixtral import MixtralForCausalLM
from ktransformers.util.utils import prefill_and_generate
from ktransformers.server.config.config import Configcustom_models = {
"DeepseekV2ForCausalLM": DeepseekV2ForCausalLM,
"DeepseekV3ForCausalLM": DeepseekV3ForCausalLM,
"Qwen2MoeForCausalLM": Qwen2MoeForCausalLM,
"LlamaForCausalLM": LlamaForCausalLM,
"MixtralForCausalLM": MixtralForCausalLM,
}ktransformer_rules_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "optimize", "optimize_rules")
default_optimize_rules = {
"DeepseekV2ForCausalLM": os.path.join(ktransformer_rules_dir, "DeepSeek-V2-Chat.yaml"),
"DeepseekV3ForCausalLM": os.path.join(ktransformer_rules_dir, "DeepSeek-V3-Chat.yaml"),
"Qwen2MoeForCausalLM": os.path.join(ktransformer_rules_dir, "Qwen2-57B-A14B-Instruct.yaml"),
"LlamaForCausalLM": os.path.join(ktransformer_rules_dir, "Internlm2_5-7b-Chat-1m.yaml"),
"MixtralForCausalLM": os.path.join(ktransformer_rules_dir, "Mixtral.yaml"),
}# 全局变量,存储初始化后的模型
chat_model = Noneclass OpenAIChat:
def __init__(
self,
model_path: str,
optimize_rule_path: str = None,
gguf_path: str = None,
cpu_infer: int = Config().cpu_infer,
use_cuda_graph: bool = True,
mode: str = "normal",
):
torch.set_grad_enabled(False)
Config().cpu_infer = cpu_inferself.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
config = AutoConfig.from_pretrained(model_path, trust_remote_code=True)
self.streamer = TextStreamer(self.tokenizer, skip_prompt=True) if not Config().cpu_infer else None
if mode == 'long_context':
assert config.architectures[0] == "LlamaForCausalLM", "Only LlamaForCausalLM supports long_context mode"
torch.set_default_dtype(torch.float16)
else:
torch.set_default_dtype(config.torch_dtype)with torch.device("meta"):
if config.architectures[0] in custom_models:
if "Qwen2Moe" in config.architectures[0]:
config._attn_implementation = "flash_attention_2"
if "Llama" in config.architectures[0]:
config._attn_implementation = "eager"
if "Mixtral" in config.architectures[0]:
config._attn_implementation = "flash_attention_2"
model = custom_models[config.architectures[0]](config)
else:
model = AutoModelForCausalLM.from_config(
config, trust_remote_code=True, attn_implementation="flash_attention_2"
)if optimize_rule_path is None:
if config.architectures[0] in default_optimize_rules:
optimize_rule_path = default_optimize_rules[config.architectures[0]]optimize_and_load_gguf(model, optimize_rule_path, gguf_path, config)
try:
model.generation_config = GenerationConfig.from_pretrained(model_path)
except:
model.generation_config = GenerationConfig(
max_length=128,
temperature=0.7,
top_p=0.9,
do_sample=True
)
if model.generation_config.pad_token_id is None:
model.generation_config.pad_token_id = model.generation_config.eos_token_id
model.eval()
self.model = model
self.use_cuda_graph = use_cuda_graph
self.mode = mode
logger.info("Model loaded successfully!")def create_chat_completion(
self,
messages: List[Dict[str, str]],
temperature: float = 0.7,
max_tokens: int = 1000,
top_p: float = 0.9,
force_think: bool = False,
) -> Dict:
input_tensor = self.tokenizer.apply_chat_template(
messages, add_generation_prompt=True, return_tensors="pt"
)
if force_think:
token_thinks = torch.tensor([self.tokenizer.encode("<think>\\n", add_special_tokens=False)],
device=input_tensor.device)
input_tensor = torch.cat([input_tensor, token_thinks], dim=1)generation_config = GenerationConfig(
temperature=temperature,
top_p=top_p,
max_new_tokens=max_tokens,
do_sample=True # Ensure do_sample is True if using temperature or top_p
)generated = prefill_and_generate(
self.model,
self.tokenizer,
input_tensor.cuda(),
max_tokens,
self.use_cuda_graph,
self.mode,
force_think
)# Convert token IDs to text
generated_text = self.tokenizer.decode(generated, skip_special_tokens=True)return {
"choices": [{
"message": {
"role": "assistant",
"content": generated_text
}
}],
"usage": {
"prompt_tokens": input_tensor.shape[1],
"completion_tokens": len(generated),
"total_tokens": input_tensor.shape[1] + len(generated)
}
}class ChatMessage(BaseModel):
role: str
content: strclass ChatCompletionRequest(BaseModel):
messages: List[ChatMessage] # 确保 messages 是 Pydantic 模型实例的列表
model: str = "default-model"
temperature: Optional[float] = 0.7
top_p: Optional[float] = 0.9
max_tokens: Optional[int] = 1000
stream: Optional[bool] = False
force_think: Optional[bool] = Trueclass ChatCompletionResponse(BaseModel):
id: str = "chatcmpl-default"
object: str = "chat.completion"
created: int = 0
model: str = "default-model"
choices: List[Dict[str, Any]]
usage: Dict[str, int]app = FastAPI(title="KVCache.AI API Server")
@app.get("/health")
async def health_check():
return {"status": "healthy"}@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = f"{process_time:.4f}s"
return responseapp.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)@app.post("/v1/chat/completions", response_model=ChatCompletionResponse)
async def chat_completion(request: ChatCompletionRequest):
try:
# 如果 messages 是 Pydantic 模型实例列表,使用 model_dump
messages = [m.model_dump() for m in request.messages]
response = chat_model.create_chat_completion(
messages=messages,
temperature=request.temperature,
max_tokens=request.max_tokens,
top_p=request.top_p,
force_think=request.force_think
)return {
"id": f"chatcmpl-{int(time.time())}",
"object": "chat.completion",
"created": int(time.time()),
"model": request.model,
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": response['choices'][0]['message']['content']
},
"finish_reason": "stop"
}],
"usage": response['usage']
}
except Exception as e:
logger.error(f"API Error: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Internal server error: {str(e)}"
)def create_app(model_path: str, gguf_path: str, cpu_infer:int, optimize_rule_path: Optional[str] = None):
global chat_model
chat_model = OpenAIChat(
model_path=model_path,
gguf_path=gguf_path,
optimize_rule_path=optimize_rule_path,
cpu_infer=cpu_infer
)
return appdef main():
parser = argparse.ArgumentParser(description="KVCache.AI API Server")
parser.add_argument("--model_path", type=str, required=True, help="HuggingFace模型路径")
parser.add_argument("--gguf_path", type=str, required=True, help="GGUF模型文件路径")
parser.add_argument("--optimize_rule_path", type=str, help="优化规则文件路径")
parser.add_argument("--port", type=int, default=8000, help="服务端口号")
parser.add_argument("--cpu_infer", type=int, default=10, help="使用cpu数量")
parser.add_argument("--host", type=str, default="0.0.0.0", help="绑定地址")
args = parser.parse_args()create_app(
model_path=args.model_path,
gguf_path=args.gguf_path,
optimize_rule_path=args.optimize_rule_path,
cpu_infer=args.cpu_infer
)uvicorn.run(
app,
host=args.host,
port=args.port,
loop="uvloop",
http="httptools",
timeout_keep_alive=300,
log_level="info",
access_log=False
)if __name__ == "__main__":
main()
文件防止位置:
安装依赖:
pip install protobuf uvicorn httptools
pip install uvloop
启动:
python ktransformers/chat_openai.py --model_path deepseek-ai/DeepSeek-R1 --gguf_path /home/dpkj/deepseek/DeepSeek-R1-GGUF/DeepSeek-R1-Q4_K_M/
2.使用open-WEBUI进行可视化对接
# 使用Pip下载OPEN-WEBUI
pip install open-webui# 下载完成后开启服务open-webui serve





import os
import json
import requests
from pydantic import BaseModel, Field
from typing import List, Union, Iterator# Set DEBUG to True to enable detailed logging
DEBUG = False
class Pipe:
class Valves(BaseModel):
openai_API_KEY: str = Field(default="none") # Optional API key if needed
DEFAULT_MODEL: str = Field(default="DeepSeek-R1") # Default model identifierdef __init__(self):
self.id = "DeepSeek-R1"
self.type = "manifold"
self.name = "KT: "
self.valves = self.Valves(
**{
"openai_API_KEY": os.getenv("openai_API_KEY", "none"),
"DEFAULT_MODEL": os.getenv("openai_DEFAULT_MODEL", "DeepSeek-R1"),
}
)
# Self-hosted FastAPI server details
self.api_url = (
"http://localhost:8000/v1/chat/completions" # FastAPI server endpoint
)
self.headers = {"Content-Type": "application/json"}def get_openai_models(self):
"""Return available models - for openai we'll return a fixed list"""
return [{"id": "KT", "name": "DeepSeek-R1"}]def pipes(self) -> List[dict]:
return self.get_openai_models()def pipe(self, body: dict) -> Union[str, Iterator[str]]:
try:
# Use default model ID since OpenAI has a single endpoint
model_id = self.valves.DEFAULT_MODEL
messages = []# Process messages including system, user, and assistant messages
for message in body["messages"]:
if isinstance(message.get("content"), list):
# For OpenAI, we'll join multiple content parts into a single text
text_parts = []
for content in message["content"]:
if content["type"] == "text":
text_parts.append(content["text"])
elif content["type"] == "image_url":
# OpenAI might not support image inputs - add a note about the image
text_parts.append(f"[Image: {content['image_url']['url']}]")
messages.append(
{"role": message["role"], "content": "".join(text_parts)}
)
else:
# Handle simple text messages
messages.append(
{"role": message["role"], "content": message["content"]}
)if DEBUG:
print("FastAPI API request:")
print(" Model:", model_id)
print(" Messages:", json.dumps(messages, indent=2))# Prepare the API call parameters
payload = {
"model": model_id,
"messages": messages,
"temperature": body.get("temperature", 0.7),
"top_p": body.get("top_p", 0.9),
"max_tokens": body.get("max_tokens", 8192),
"stream": body.get("stream", True),
}# Add stop sequences if provided
if body.get("stop"):
payload["stop"] = body["stop"]# Sending request to local FastAPI server
if body.get("stream", False):
# Streaming response
def stream_generator():
try:
response = requests.post(
self.api_url,
json=payload,
headers=self.headers,
stream=True,
)
for line in response.iter_lines():
if line:
yield line.decode("utf-8")
except Exception as e:
if DEBUG:
print(f"Streaming error: {e}")
yield f"Error during streaming: {str(e)}"return stream_generator()
else:
# Regular response
response = requests.post(
self.api_url, json=payload, headers=self.headers
)
if response.status_code == 200:
generated_content = (
response.json()
.get("choices", [{}])[0]
.get("message", {})
.get("content", "")
)
return generated_content
else:
return f"Error: {response.status_code}, {response.text}"
except Exception as e:
if DEBUG:
print(f"Error in pipe method: {e}")
return f"Error: {e}"def health_check(self) -> bool:
"""Check if the OpenAI API (local FastAPI service) is accessible"""
try:
# Simple health check with a basic prompt
response = requests.post(
self.api_url,
json={
"model": self.valves.DEFAULT_MODEL,
"messages": [{"role": "user", "content": "Hello"}],
"max_tokens": 5,
},
headers=self.headers,
)
return response.status_code == 200
except Exception as e:
if DEBUG:
print(f"Health check failed: {e}")
return False


相关文章:

Ubuntu部署ktransformers
准备工作 一台服务器 CPU:500G GPU:48G(NVIDIA4090) 系统:Ubuntu20.04(github的文档好像用的是22.04) 第一步:下载权重文件 1.下载hfd wget https://hf-mirror.com/hfd/hfd.s…...

助力DeepSeek私有化部署服务:让企业AI落地更简单、更安全
在数字化转型的浪潮中,越来越多的企业选择私有化部署AI技术,以保障数据安全、提升业务效率并实现自主可控。DeepSeek作为行业领先的AI开源技术,其技术可以支持企业私有化部署,企业需要一站式服务私有化部署,涵盖硬件采…...
面试官询问项目前后端人员配比之高分示范回答
面试官询问项目前后端人员配比之高分示范回答 以下是对两个项目前后端人员配置的精准分析,结合 技术复杂度、协作效率、风险控制 三个维度设计回答,突出合理性与团队协作意识: 一、《x能x服》项目(Vue重构) 1. 人员配置与分工 前端:1人(独立开发) 负责旧系统业务逻辑…...
MyBatis中的日志和映射器说明
1.MyBatis中的日志 1.1 什么是日志 在我们编写应用的时候,有一些信息需要及时查看,查看的时候有时需要输出到控制台,有时需要输出到文件。MyBatis也需要日志,一般情况下,使用log4j进行日志管理。 1.2 在MyBatis中…...
深入了解 Pinia:Vue 的下一代状态管理工具 (上篇)
引言 在现代前端开发中,状态管理是构建复杂应用的关键。Vue 生态系统中,Vuex 一直是官方推荐的状态管理工具。然而,随着 Vue 3 的发布,一个新的状态管理工具——Pinia,逐渐崭露头角。Pinia 不仅继承了 Vuex 的优点&am…...

Unity 中导入的VRM模型渲染为VRoid风格
按照前篇Unity VRoidBlenderUnity 3D人物模型导入使用-CSDN博客 导入到Unity之后,可以按需调整模型在场景中的渲染表现, 但是按照教程中完成的情况, 整个模型没有进行材质区分, 仅用一个材质表现整个模型, 导致不能给不同部位进行渲染调整. 这里我希望能够在Unity中获得跟VRoi…...
【ELK】【Elasticsearch 】DSL 和 DQL
1. DSL 查询(Query DSL) 全称:Domain Specific Language(领域特定语言)。 定义:Elasticsearch 提供的一种基于 JSON 的查询语言,用于构建复杂的查询逻辑。 特点: 支持多种查询类型…...

最新版本Exoplayer扩展FFmpeg音频软解码保姆级教程
ExoPlayer 是一个开源的 Android 媒体播放库,由 Google 开发和维护,用于替代 Android 系统自带的 MediaPlayer。它提供了更强大的功能、更好的性能和更高的灵活性,适用于各种复杂的媒体播放场景。所以被广泛用于各种播放器场景。 最近项目中…...

面对低消费欲人群,我们如何开发其需求?
在市场增量放缓的当下,开发深度开发各层次的人群已经成为现实需求。低消费欲人群并非“没有需求”,而是更谨慎、更理性。他们可能对价格敏感,但对实用性、情感共鸣和生活品质的追求依然存在。就让我们从以下四个角度,拆解如何激发…...
《算法基础入门:最常用的算法详解与应用(持续更新实战与面试题)》
1. 排序算法 排序算法是将一组数据按特定的顺序排列起来的算法,常见的有: 冒泡排序(Bubble Sort)选择排序(Selection Sort)插入排序(Insertion Sort)归并排序(Merge So…...

Linux设备驱动-练习
练习要求: 一、设备树 1、配置设备树信息:将3个led灯和1个风扇使用到的设备信息配置到设备树中 二、设备驱动层 1、通过of_find_node_by_name、of_get_named_gpion等内核核心层统一的api接口调用外设; 2、通过udev设备管理器自动注册并创建设…...

蓝桥杯核心内容
核心内容 数学 质数与筛质数,分解质因数 分解质因数 所有的数都可以写成有限个数相乘质数:可以写成1✖本身(如131✖13)合数:ab1✖...✖bn-》把乘数里面是合数的再分(如b3是合数-》b3c1✖c2)进…...

Spring Boot拦截器(Interceptor)详解
拦截器Interceptor 拦截器我们主要分为三个方面进行讲解: 介绍下什么是拦截器,并通过快速入门程序上手拦截器拦截器的使用细节通过拦截器Interceptor完成登录校验功能 1. 快速入门 什么是拦截器? 是一种动态拦截方法调用的机制ÿ…...

非常好用的ssh工具Xterminal
免安装 Xterminal - 更好用的开发工具,但不止于(SSH/控制台/More)...

【Python项目】基于Django的医疗领域用户问答意图识别系统
【Python项目】基于Django的医疗领域用户问答意图识别系统 技术简介:采用Python技术、MySQL数据库、Neo4j图形数据库、Django框架、BERTLSTMCRF模型等技术实现。 系统简介: 医疗领域用户问答意图识别系统是一个基于知识图谱的智能问答平台,旨…...

深入理解指针(六)
一、字符指针变量 1.1字符指针变量 在指针的类型中我们知道有一种指针类型为字符指针char* 一般有以下两种使用方式: #include<stdio.h> int main() { char ch w; char* pc &ch; *pc w; return 0; } #include<stdio.h> int main()…...

Linux下基本指令(4)
Linux权限的概念 Linux下有两种用户:超级用户(root)、普通用户。 超级用户:可以再linux系统下做任何事情,不受限制 普通用户:在linux下做有限的事情。 超级用户的命令提示符是“#”,普通用户…...

vue 手写分页
【先看效果】 (1)内容小于2页 不展示页码 (2)1 < 内容页数< 限定展示页码 展示:页码、上下页;隐藏:首页、末页图标,上、下一区间码。即:(页数&#…...

Spring Boot项目接收前端参数的11种方式
大家好,我是。在前后端项目交互中,前端传递的数据可以通过HTTP请求发送到后端, 后端在Spring Boot中如何接收各种复杂的前端数据呢?这篇文章总结了11种在Spring Boot中接收前端数据的方式。 1 搭建项目 1.通过Spring Initializr…...
Springboot项目:使用MockMvc测试get和post接口(含单个和多个请求参数场景)
一、引入MockMvc依赖 使用MockMvc,必须要引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>二、具体演示…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...