<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Posts on Leanku</title>
    <link>https://blog.leanku.com/post/</link>
    <description>Recent content in Posts on Leanku</description>
    <image>
      <url>https://blog.leanku.com/papermod-cover.png</url>
      <link>https://blog.leanku.com/papermod-cover.png</link>
    </image>
    <generator>Hugo -- gohugo.io</generator>
    <lastBuildDate>Sat, 24 Jan 2026 00:01:01 +0800</lastBuildDate><atom:link href="https://blog.leanku.com/post/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>OpenClaw &#43;QQ机器人</title>
      <link>https://blog.leanku.com/post/ai/openclaw-&#43;qq%E6%9C%BA%E5%99%A8%E4%BA%BA/</link>
      <pubDate>Sat, 24 Jan 2026 00:01:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/ai/openclaw-&#43;qq%E6%9C%BA%E5%99%A8%E4%BA%BA/</guid>
      <description>OpenClaw +QQ机器人助手 OpenClaw 适用于任何操作系统的 AI 智能体 Gateway 网关，支持 WhatsApp、Telegram、Discord、iMessage 等。 发送消息，随时随地获取智能体响应。通过插件可添加 Mattermost 等更多渠道。
1. 搭建 OpenClaw 可参考官方文档 ，按需选择适合的安装方式。
如果服务器上安装了1Panel,可以直接从应用商店安装
2. 接入 QQ 1. 申请 QQ 机器人 打开 QQ 开放平台，注册登录，然后创建 QQ 机器人。地址： https://q.qq.com 创建完成后，进入机器人的开发管理页面，找到 AppID 和 AppSecret，复制保存好，等会要用。 还要把你云服务器的 公网 IP 添加到 IP 白名单里，然后保存。 在沙箱配置里给你的 QQ 账号（或者 QQ 群）添加访问机器人的权限： 2. 给 OpenClaw 绑定 QQ 机器人 安装 qqbot 插件 https://github.com/BytePioneer-AI/openclaw-china 远程登录到云服务器上，执行命令来安装 @openclaw-china/qqbot 插件。 openclaw plugins install @openclaw-china/qqbot 安装插件成功后,配置QQ 机器人参数，用之前保存的 id 和 secret ： openclaw config set channels.</description>
    </item>
    
    <item>
      <title>闻言 www.wenyanlu.cn</title>
      <link>https://blog.leanku.com/post/%E9%97%BB%E8%A8%80/</link>
      <pubDate>Thu, 01 Jan 2026 00:01:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/%E9%97%BB%E8%A8%80/</guid>
      <description>闻言 https://www.wenyanlu.cn
闻言｜字句成录，回响为闻。
一个以诗词、句子为核心的现代数字平台。
旨在通过每日一句的经典推荐，让更多诗词爱好者接触到隽永的中华文韵。
核心交互聚焦于首页正中的每日一句，如“高山仰止，景行行止。”（先秦《车舝》）。
诗句以古典意象卡片形式呈现，点击 “换一句” 即可随机切换，创造不经意的相遇。
如果你也喜欢或者有想法、建议、问题等
请邮件联系我： leanku@hotmail.com</description>
    </item>
    
    <item>
      <title>RAGFlow</title>
      <link>https://blog.leanku.com/post/ai/ragflow/</link>
      <pubDate>Tue, 28 Oct 2025 00:01:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/ai/ragflow/</guid>
      <description>RAGFlow 一、介绍 RAGFlow是一个完整的、开源的RAG（检索增强生成）系统。你可以把它看作一个已经搭建好的智能问答应用框架。
RAGFlow不是一个需要你从零编码的库，而是一个可以直接运行起来的服务。它内置了我们聊过的RAG的完整流程：上传文档 -&amp;gt; 自动解析 -&amp;gt; 切片 -&amp;gt; 调用Embedding模型生成向量 -&amp;gt; 存储 -&amp;gt; 检索 -&amp;gt; 调用大模型生成回答。
RAGFlow 官网
二、搭建一个智能问答系统 整体架构：
你的文档 (PDF/Word/PPT) ↓ [RAGFlow核心] ├─ 深度文档解析 → 保留表格/图片/格式 ├─ 智能分块 → 按语义切割文档 ├─ 向量化 → 调用Embedding模型 └─ 向量存储 → 存入数据库 ↓ 用户提问 → [检索引擎] → [你的微调模型] → 带引用的精准回答 2.1 部署RAGFlow 这里使用 Docker 方式 环境要求：
CPU ≥ 4 cores (x86); RAM ≥ 16 GB; Disk ≥ 50 GB; Docker ≥ 24.0.0 &amp;amp; Docker Compose ≥ v2.</description>
    </item>
    
    <item>
      <title>RAG</title>
      <link>https://blog.leanku.com/post/ai/rag/</link>
      <pubDate>Fri, 24 Oct 2025 00:01:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/ai/rag/</guid>
      <description>RAG技术 （检索增强生成） 引言：当大模型遇上知识库 想象一下，你正在参加一场开卷考试。你的面前有两样东西：一个记忆力超群但知识停留在去年的天才同学（这就是大语言模型），以及一个可以随时查阅的最新版百科全书（这就是外部知识库）。你让这位同学回答问题，他既可以凭借自己的记忆作答，也可以随时翻阅百科全书获取最新、最准确的信息。
这个场景，就是 RAG（检索增强生成）最形象的比喻。
它不是要取代大模型，而是为大模型装上了一个可以实时更新的&amp;quot;知识图书馆&amp;quot;。
一、什么是 RAG？ 1.1 官方定义 RAG 全称是 Retrieval-Augmented Generation，中文译为&amp;quot;检索增强生成&amp;quot;。它是一种将信息检索系统与大语言模型的生成能力相结合的技术架构。
核心思想很简单：在让大模型回答问题之前，先从一个知识库中检索出与问题最相关的信息，然后将这些信息作为&amp;quot;参考资料&amp;quot;连同原始问题一起交给模型，让它基于这些资料生成最终答案。
1.2 为什么要用 RAG？ 传统的大语言模型存在三个先天性缺陷：
缺陷 表现 后果 知识截止日期 模型训练完成后，新发生的事件一概不知 问&amp;quot;今天的天气&amp;quot;、&amp;ldquo;最近的新闻&amp;rdquo;，模型只能道歉 幻觉问题 模型会&amp;quot;自信地胡说八道&amp;quot; 在金融、医疗等严肃场景无法直接使用 缺乏专业深度 对企业内部知识、专业领域知识不了解 无法回答基于私域数据的专业问题 RAG 的出现，一次性解决了这三个问题：
知识实时更新：只要更新知识库，模型就能&amp;quot;知道&amp;quot;
答案可追溯：每个回答都能找到对应的参考资料
低成本私有化：无需训练模型，只需构建知识库
1.3 RAG 的三步工作流程 一个标准的 RAG 流程包含三个核心步骤：
用户提问：&amp;#34;去年的销售额是多少？&amp;#34; ↓ [第一步：检索] ↓ 在向量数据库中搜索 → 找到&amp;#34;2023年财报.pdf&amp;#34;中的相关段落 ↓ [第二步：增强] ↓ 构建新的提示词： &amp;#34;基于以下资料回答问题： 【资料】2023年公司财报显示，全年销售额为1.2亿元... 问题：去年的销售额是多少？&amp;#34; ↓ [第三步：生成] ↓ 大模型生成：&amp;#34;根据公司财报，2023年的销售额为1.2亿元。&amp;#34; 二、RAG 的核心技术组件 要深入理解 RAG，需要认识它的三个核心技术组件：
2.1 向量化与嵌入模型 是什么：将文本转化为计算机能够理解的数学向量（一组数字）。
为什么需要：计算机无法像人类一样理解文字的&amp;quot;含义&amp;quot;，但它擅长计算数字之间的&amp;quot;距离&amp;quot;。通过将文字转化为向量，我们可以用数学方式衡量两段文字的相似度。
像 OpenAI 的 text-embedding-3-small 模型，或者本地的 bge-large-zh 模型，都是常用的嵌入模型。</description>
    </item>
    
    <item>
      <title>模型微调</title>
      <link>https://blog.leanku.com/post/ai/%E6%A8%A1%E5%9E%8B%E5%BE%AE%E8%B0%83/</link>
      <pubDate>Fri, 24 Oct 2025 00:01:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/ai/%E6%A8%A1%E5%9E%8B%E5%BE%AE%E8%B0%83/</guid>
      <description>模型微调 一、模型微调到底是什么 简单来说，模型微调就是让一个已经博学多才的“通才”，通过针对性的“岗前培训”，变成精通某个领域的“专家”。
预训练模型（通才大厨）：就像一位精通全球菜系的米其林大厨，他掌握了所有的基础知识和烹饪技巧，但未必了解你餐厅的特色。 微调（岗前培训）：你想开一家川菜馆，于是让这位大厨用三个月时间，专门学习川菜的食材、调料和烹饪手法。 微调后的模型（川菜大师）：最终，他不仅保留了原有的厨艺基础，更能做出一手地道的麻婆豆腐，成为了川菜领域的专家 。 这个过程直接调整模型的“大脑”（参数），让学到的技能内化为模型自身的能力。相比于RAG（它更像是让大厨在做菜时随时翻阅菜谱），微调后的模型在推理时速度更快，且能深度掌握某种特定的风格或知识 。
二、 核心技术：LoRA——四两拨千斤的微调利器 你可能会担心，重新训练一个包含几十亿甚至上千亿参数的大模型，得需要多强大的计算资源？这正是LoRA（低秩自适应） 技术大显身手的地方。
它的核心思想非常巧妙，我们可以继续用“川菜大厨”的比喻来理解
全量微调：相当于让大厨忘掉过去的一些习惯，全身心地重新学习川菜的每一个步骤。效果最好，但成本极高，需要强大的算力支持。 LoRA微调：我们不动大厨已经固化的核心“厨艺”（预训练权重），而是给他一个轻量级的“川菜秘方贴纸”（低秩矩阵）。这张贴纸只记录了川菜的关键调整点，比如“多加花椒”、“牛油比例提升”。大厨在做川菜时，只需要在关键步骤上参考这张贴纸即可 。 这样做的好处是巨大的：
显存占用低：可训练的参数通常只有不到1%，让在消费级显卡（如RTX 4090）上微调大模型成为可能。
训练速度快：大幅缩短了训练时间。
模型性能高：在绝大多数任务上，效果可以媲美全量微调。
QLoRA 则是LoRA的进阶版，它先把基础模型“压缩”（量化）到4位精度，再应用LoRA，进一步降低了硬件门槛。
三、 具体如何实现 理解了原理，我们来看看如何上手。
你完全不需要从零开始写复杂的训练代码。这里有两条清晰的路径：
路径一：使用云端服务（最简单、快速上手） 这是最省心的方式，你只需要准备好数据，在云平台上点点鼠标，就能完成微调。例如华为云的ModelArts Studio，流程大致如下 ：
准备数据：整理好你的训练集（如客户问答对、特定风格的文本等）。
选择模型：在平台界面选择你想要微调的基础模型，例如盘古大模型。
配置任务：选择“微调”训练类型，并可以灵活选择“全量微调”或“LoRA微调” 。然后设置一些基本参数，如：
学习率：决定模型参数更新的幅度，通常设为很小的值如 2e-5 。
训练轮数：整个数据集被训练的遍数，通常设为 3 以避免过拟合。
数据批量大小：每次处理的数据量，根据你的资源情况设定。
启动训练：提交任务，等待训练完成。过程中可以观察损失值（Loss） 曲线，它应该呈下降趋势，代表模型在有效学习。
部署使用：训练完成后，平台会自动生成一个微调后的模型版本，你可以像调用普通API一样，通过PHP代码来使用这个专属模型。
路径二：使用本地开源工具（更灵活、适合动手实践） 如果你想在自己的电脑上体验整个过程，Ollama + Python是一个非常棒的组合，它让微调变得异常简单 。步骤如下：
1. 安装Ollama 参考另一篇 Ollama搭建本地
我们选择一个轻量级模型，普通电脑也能流畅运行
ollama pull llama2 2. 准备微调数据 微调的核心是数据。我们将创建一个非常简单的数据集，让模型学习用莎士比亚的风格回答问题。
2.1 创建项目目录 在合适的位置新建一个文件夹：
mkdir ollama-finetune-demo cd ollama-finetune-demo 2.2 创建Python虚拟环境</description>
    </item>
    
    <item>
      <title>Embedding：理解语义的基础</title>
      <link>https://blog.leanku.com/post/ai/embedding/</link>
      <pubDate>Wed, 22 Oct 2025 00:01:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/ai/embedding/</guid>
      <description>Embedding：理解语义的基础 引言：当计算机学会了&amp;quot;理解&amp;quot;含义 在上一篇文章中，我们讨论了大语言模型的工作原理。但有一个根本问题还没解决：计算机是如何&amp;quot;理解&amp;quot;词语含义的？
计算机只能处理数字，它不认识&amp;quot;猫&amp;quot;，不认识&amp;quot;爱情&amp;quot;，更不懂&amp;quot;苹果&amp;quot;和&amp;quot;橘子&amp;quot;的相似性。但今天的AI不仅能理解这些概念，还能进行语义推理。这一切的基石就是 Embedding（嵌入）。
一、什么是Embedding？ 1.1 从一个思想实验开始 想象你要向一个来自外星、不懂任何人类语言的外星人解释&amp;quot;苹果&amp;quot;这个词。你会怎么做？
你可以给他一个多维度的描述：
维度 描述 颜色 通常是红色或绿色 形状 圆形 大小 拳头大小 味道 甜或酸甜 口感 脆 用途 可以吃 &amp;hellip; &amp;hellip; 如果把这些维度变成数字，就得到一个向量：
苹果 = [红色: 0.9, 圆形: 0.8, 大小: 0.5, 甜度: 0.7, 脆度: 0.8, 可食用: 1.0, ...] 这就是Embedding的基本思想：用一个数字数组（向量）表示一个概念的含义。
1.2 正式定义 Embedding（嵌入） 是将离散的符号（词语、句子、图片等）映射到连续向量空间的技术。每个符号被表示为一个固定长度的实数向量。
关键特性：
语义相近的符号，向量距离也相近
向量之间可以进行数学运算
向量的维度（长度）通常在几十到几千之间
1.3 直观理解：语义空间地图 可以把Embedding想象成绘制了一张&amp;quot;语义空间地图&amp;quot;：
[国王] ↑ 男人 ↑ [苹果] ← 水果 → [橘子] [王后] ↑ / 女人 / ↑ / [女王] 在这张地图上：</description>
    </item>
    
    <item>
      <title>AI Agent</title>
      <link>https://blog.leanku.com/post/ai/agent/</link>
      <pubDate>Tue, 21 Oct 2025 00:01:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/ai/agent/</guid>
      <description>AI Agent：从&amp;quot;回答问题&amp;quot;到&amp;quot;主动行动&amp;quot;的智能体 引言：当AI从&amp;quot;思考者&amp;quot;变成&amp;quot;行动派&amp;quot; 到目前为止，我们讨论的所有AI应用都有一个共同点：被动响应。你问一个问题，模型给出一个回答。就像一位知识渊博但从不主动行动的学者。
而 AI Agent（智能体） 将彻底改变这个模式。它不再是单纯的&amp;quot;问答机器人&amp;quot;，而是一个能够自主理解目标、规划步骤、调用工具、执行行动的智能系统。
用一个形象的比喻来理解AI的进化：
阶段 比喻 能力 基础LLM 刚毕业的大学生 知识丰富，但只会回答问题 RAG增强 配备了图书馆的大学生 能查阅资料，回答更准确 微调模型 经过专业培训的专家 在特定领域更精通 AI Agent 项目经理 + 执行团队 能接收任务，规划执行，调用资源，交付成果 一、什么是AI Agent？ 1.1 核心定义 AI Agent（智能体） 是一个能够感知环境、自主决策、执行行动以达到特定目标的智能系统。它具备以下核心特征：
自主性：无需人工干预，自主运作
目标导向：所有行动都围绕达成目标
工具使用：能调用外部工具完成任务
记忆能力：记住历史，持续优化
规划能力：将复杂任务拆解为可执行的步骤
1.2 Agent vs 传统程序 vs LLM 对比维度 传统程序 大语言模型(LLM) AI Agent 工作方式 按固定逻辑执行 按输入生成输出 自主规划并执行 灵活性 低，只能做预设的事 中，能处理多种问题 高，能适应新任务 工具使用 内置固定功能 无（需外部配合） 主动调用各种工具 记忆能力 有状态但有限 会话级记忆 长期记忆+经验积累 目标理解 执行指令 理解问题 理解意图并拆解 1.</description>
    </item>
    
    <item>
      <title>理解大模型工作原理</title>
      <link>https://blog.leanku.com/post/ai/%E7%90%86%E8%A7%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86/</link>
      <pubDate>Tue, 21 Oct 2025 00:01:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/ai/%E7%90%86%E8%A7%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86/</guid>
      <description>理解大模型工作原理 引言：当计算机学会了&amp;quot;说话&amp;quot; 想象一下，你正在和一个&amp;quot;人&amp;quot;对话，他能理解你的问题，能写出优美的诗句，能解释复杂的科学概念，甚至能帮你写代码。但这个&amp;quot;人&amp;quot;其实是一个运行在服务器上的软件程序。它如何做到的？
这就是大语言模型（Large Language Model, LLM）创造的奇迹。在本文中，我将用一个PHP开发者的视角，带你深入理解这个&amp;quot;数字大脑&amp;quot;的工作原理。
一、大模型是什么？ 1.1 从一个形象的比喻开始 传统程序 vs 大模型
对比维度 传统程序 大语言模型 工作方式 按照程序员写的代码执行 根据海量数据&amp;quot;学习&amp;quot;出的规律工作 知识来源 程序员明确告诉它 从数万亿文本中自己&amp;quot;领悟&amp;quot; 灵活性 只能处理预设的场景 能应对从未见过的问题 类比 按照菜谱做菜的厨师 尝过百万道菜后自己创造新菜的大厨 1.2 从数字到智能：三个关键洞察 洞察一：词语可以用数字表示 就像我们可以用经纬度表示地球上的任何位置，我们也可以用一组数字（向量）表示一个词的含义：
&amp;#34;国王&amp;#34; = [0.8, 0.3, -0.2, 0.5, ...] &amp;#34;王后&amp;#34; = [0.7, 0.4, -0.1, 0.6, ...] &amp;#34;苹果&amp;#34; = [0.1, 0.9, -0.8, -0.3, ...] 洞察二：词语之间的关系可以用数学计算 经典的&amp;quot;国王 - 男人 + 女人 = 王后&amp;quot;实验表明，这些数字向量之间可以进行数学运算，而且结果符合语义！
洞察三：上下文决定含义 &amp;ldquo;苹果&amp;quot;在&amp;quot;苹果很好吃&amp;quot;和&amp;quot;苹果发布了新手机&amp;quot;中含义不同。大模型需要理解这种差异。
二、大模型的核心架构 2.1 从神经元到神经网络 单个神经元（生物类比）： 树突（接收信号） → 细胞体（处理信号） → 轴突（输出信号） 人工神经元（数学抽象）： 输入 × 权重 + 偏置 → 激活函数 → 输出 2.</description>
    </item>
    
    <item>
      <title>设计模式原则</title>
      <link>https://blog.leanku.com/post/design-pattern/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%8E%9F%E5%88%99/</link>
      <pubDate>Mon, 13 Oct 2025 21:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/design-pattern/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%8E%9F%E5%88%99/</guid>
      <description>设计模式原则 设计模式的原则是理解和使用设计模式的基石。这些原则是面向对象设计的核心指导思想，设计模式本身就是这些原则在特定场景下的具体体现。
最重要的设计原则是 SOLID 原则，此外还有一些其他关键原则。
一、 SOLID 原则 SOLID 原则是五个最常用、最经典的设计原则，由 Robert C. Martin 提出。
1. 单一职责原则 核心思想： 一个类应该只有一个引起变化的原因。 详细解释：一个类只负责一项职责或功能。如果一個类承担的功能过多，就等于把这些职责耦合在一起，一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。 比喻： 一家餐厅，厨师负责做饭，服务员负责点菜和上菜，清洁工负责打扫。如果他们职责混杂，效率就会低下。 违反示例： 一个 UserService 类，既负责用户信息的增删改查，又负责将用户数据导出为PDF报表，还负责发送邮件通知。 修正： 将 UserService 拆分为 UserService（用户业务逻辑）、UserReportGenerator（报表生成）和 EmailService（邮件服务）。 2. 开闭原则 核心思想： 软件实体（类、模块、函数等）应该对扩展开放，对修改关闭。 详细解释： 当需求发生变化时，我们应该通过添加新的代码来扩展功能，而不是修改已有的、已经工作正常的代码。这是最重要的原则，是很多设计模式的目标。 比喻： 一台电脑，你可以扩展USB设备（鼠标、键盘、硬盘），而无需为了支持新设备而拆开主机修改主板。 违反示例： 一个 AreaCalculator 类，有一个 calculate 方法，里面用 if-else 来判断是圆形还是矩形来计算面积。如果要增加三角形，就必须修改这个类的代码。 修正： 定义一个 Shape 接口，包含 calculateArea 方法。让 Circle 和 Rectangle 类实现这个接口。AreaCalculator 只需遍历 Shape 列表调用其方法即可。要新增三角形，只需创建 Triangle 类实现 Shape，无需修改任何现有类。 3. 里氏替换原则 核心思想： 所有引用基类的地方必须能透明地使用其子类的对象。 详细解释： 子类必须能够完全替代它们的父类，而不产生任何错误或意外的行为。也就是说，子类只能在保持原有行为的基础上进行扩展，而不能覆盖或改变父类的核心行为。 比喻： 你父亲会开车，你作为儿子继承了他，你也会开车（保持了父亲的行为），但你可能会开得更快或者还会修车（扩展），你绝不能把“开车”这个行为重定义为“游泳”。 违反示例： Rectangle 类有 setWidth 和 setHeight 方法。Square 类继承 Rectangle，并重写了 setWidth 和 setHeight，使其同时设置宽和高。那么，一个接收 Rectangle 参数并调整其宽高的函数，如果传入一个 Square 对象，就会得到错误的结果。 修正： 重新考虑继承关系，或者让 Rectangle 和 Square 都实现一个 Shape 接口，而不是使用继承。 4.</description>
    </item>
    
    <item>
      <title>MySQL 中主要的日志类型</title>
      <link>https://blog.leanku.com/post/database/mysql-%E4%B8%AD%E4%B8%BB%E8%A6%81%E7%9A%84%E6%97%A5%E5%BF%97%E7%B1%BB%E5%9E%8B/</link>
      <pubDate>Mon, 13 Oct 2025 20:30:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql-%E4%B8%AD%E4%B8%BB%E8%A6%81%E7%9A%84%E6%97%A5%E5%BF%97%E7%B1%BB%E5%9E%8B/</guid>
      <description>MySQL 中主要的日志类型 MySQL 提供了多种日志类型，每种都有其特定的目的和格式。理解这些日志对于数据库管理、性能调优、数据恢复和故障排查至关重要。
下面我将详细介绍 MySQL 中主要的日志类型及其格式
总结概览 日志类型 主要目的 格式 是否默认开启 错误日志 记录 MySQL 启动、运行、停止时的错误、警告和提示信息。 文本格式 是 二进制日志 记录所有更改数据的语句，用于主从复制和数据恢复。 STATEMENT, ROW, MIXED 否 (8.0默认开启) 通用查询日志 记录所有到达 MySQL 的客户端连接和执行的语句。 文本格式 / CSV 格式 否 慢查询日志 记录执行时间超过指定阈值的查询，用于性能优化。 文本格式 / CSV 格式 否 重做日志 InnoDB 特有的，用于保证事务的持久性和崩溃恢复。 物理格式（二进制） 是 回滚日志 InnoDB 特有的，用于保证事务的原子性和 MVCC。 逻辑格式 是 详细解析 1. 错误日志 这是 DBA 首先需要查看的日志，当数据库出现任何异常时，它通常是排查问题的起点。
内容：启动/关闭信息、错误信息、警告信息、在复制环境中从服务器线程的启动信息等。
格式：纯文本格式，易于阅读。
配置参数：
log_error：指定错误日志文件的位置。 示例内容：
2023-10-27T08:00:00.000000Z 0 \[Note\] Server started. 2023-10-27T08:01:23.456789Z 5 \[Warning\] Aborted connection 5 to db: &amp;#39;test&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; 2.</description>
    </item>
    
    <item>
      <title>Drone CICD自动化部署指南</title>
      <link>https://blog.leanku.com/post/cicd/drone-cicd%E8%87%AA%E5%8A%A8%E5%8C%96%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/</link>
      <pubDate>Sat, 09 Aug 2025 16:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/cicd/drone-cicd%E8%87%AA%E5%8A%A8%E5%8C%96%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/</guid>
      <description>本文详细介绍了 Drone 搭建CI/CD自动化部署的步骤，包括Drone安装、配置、实践...</description>
    </item>
    
    <item>
      <title>轻量级容器编排工具指南</title>
      <link>https://blog.leanku.com/post/cicd/%E8%BD%BB%E9%87%8F%E7%BA%A7%E5%AE%B9%E5%99%A8%E7%BC%96%E6%8E%92%E5%B7%A5%E5%85%B7%E6%8C%87%E5%8D%97/</link>
      <pubDate>Sat, 09 Aug 2025 16:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/cicd/%E8%BD%BB%E9%87%8F%E7%BA%A7%E5%AE%B9%E5%99%A8%E7%BC%96%E6%8E%92%E5%B7%A5%E5%85%B7%E6%8C%87%E5%8D%97/</guid>
      <description>轻量级容器编排工具指南 在 Docker 环境中，除了 K8s，还有多种轻量级方案可以实现服务自动重启、健康检查等功能，特别适合单机或中小规模部署。
一、简单方案 1.1 Docker 自身的重启策略（最基础方案） Docker Engine 内置了容器重启策略，可直接在启动容器时配置，实现容器退出后自动重启。
常用重启策略：
--restart always：无论容器因何种原因退出（包括正常退出），总是自动重启。 --restart on-failure[:max-retries]：仅在容器以非 0 状态码退出时重启，可选最大重试次数（如on-failure:3最多重启 3 次）。 --restart unless-stopped：除非手动执行docker stop，否则始终重启（包括 Docker daemon 重启时） 示例：
# 启动PHP容器，配置always重启策略 docker run -d \ --name php-app \ --restart always \ # 核心：容器挂掉后自动重启 -p 80:80 \ -v /path/to/php/code:/var/www/html \ php:8.2-apache 优势： 零依赖，直接使用 Docker 原生功能，适合单机部署。
局限： 仅能监控容器本身是否存活，无法检测应用内部故障（如 PHP-FPM 假死但容器仍运行）。
1.2 ocker Compose（适合多容器应用） 如果 项目依赖其他服务（如 MySQL、Redis），可使用docker-compose管理，通过配置restart参数实现自动重启，同时支持健康检查。
docker-compose.yml示例：
version: &amp;#39;3.8&amp;#39; services: php-app: image: php:8.2-apache restart: always # 容器退出后自动重启 ports: - &amp;#34;80:80&amp;#34; volumes: - .</description>
    </item>
    
    <item>
      <title>Kong&#43;Konga&#43;Consul</title>
      <link>https://blog.leanku.com/post/microservice/kong&#43;konga&#43;consul/</link>
      <pubDate>Fri, 01 Aug 2025 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/microservice/kong&#43;konga&#43;consul/</guid>
      <description>Kong+Konga+Consul 安装和使用 此处使用Docker安装方式
一、 安装Kong kong具体使用可参考另一篇文章：Kong API网关
为了确保 Kong、Konga 和 Consul 能够通信，Kong 和 Konga 也需要加入到同一个网络。如果你尚未创建网络，或者希望使用新的网络，可以创建一个：
docker network create kong-net 1.1 安装 PostgreSQL (Kong 的数据库) Kong 需要 PostgreSQL 来存储其配置数据
docker run -d --name kong-database \ --network=kong-net \ -p 5432:5432 \ -e &amp;#34;POSTGRES_USER=kong&amp;#34; \ -e &amp;#34;POSTGRES_DB=kong&amp;#34; \ -e &amp;#34;POSTGRES_PASSWORD=kong&amp;#34; \ postgres:13 &amp;ndash;network=kong-net: 确保数据库与 Kong、Consul 在同一网络。
-e 环境变量：设置数据库的用户名、数据库名和密码。
建议使用 PostgreSQL 9.6 或更高版本，这里使用了 13 版本。
1.2 初始化 Kong 数据库 运行一个临时容器来执行数据库迁移：
docker run --rm \ --network=kong-net \ -e &amp;#34;KONG_DATABASE=postgres&amp;#34; \ -e &amp;#34;KONG_PG_HOST=kong-database&amp;#34; \ -e &amp;#34;KONG_PG_USER=kong&amp;#34; \ -e &amp;#34;KONG_PG_PASSWORD=kong&amp;#34; \ kong:3.</description>
    </item>
    
    <item>
      <title>PHPUnit使用指南</title>
      <link>https://blog.leanku.com/post/phpunit%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</link>
      <pubDate>Mon, 30 Jun 2025 23:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/phpunit%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</guid>
      <description>PHPUnit 使用指南 一、介绍 PHPUnit 是 PHP 领域最流行的单元测试框架，它受到 JUnit 的启发，为 PHP 开发者提供了编写和运行单元测试的工具和方法。使用 PHPUnit 可以带来以下好处：
验证代码的正确性，确保函数和方法按预期工作 便于代码重构，修改后可以快速验证是否破坏了现有功能 帮助理解代码功能，测试用例本身就是一种文档 支持测试驱动开发 (TDD) 流程 二、安装 PHPUnit 1. 安装 PHPUnit（可以通过 composer require --dev phpunit/phpunit 安装） 2. 配置PhpStorm 运行 PHPUnit（Docker环境为例） 2.1. 配置 Docker 远程解释器 打开 PhpStorm，进入 File &amp;gt; Settings &amp;gt; Build, Execution, Deployment &amp;gt; Docker 在右侧选择 Docker for Windows（通常会自动检测） 点击 Apply 确认配置，确保连接成功（底部会显示 &amp;ldquo;Connection successful&amp;rdquo;） 进入 File &amp;gt; Settings &amp;gt; Languages &amp;amp; Frameworks &amp;gt; PHP 点击 CLI Interpreter 右侧的 &amp;hellip; 按钮，点击左上角 + 号，选择 From Docker, Vagrant, VM, WSL, Remote&amp;hellip; 选择 Docker 并找到你的 php 容器 选择容器中的 PHP 可执行文件路径（如 /usr/local/bin/php） 点击 OK 完成配置，PhpStorm 会自动检测 PHP 版本和扩展 2.</description>
    </item>
    
    <item>
      <title>wrk 使用指南</title>
      <link>https://blog.leanku.com/post/wrk-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</link>
      <pubDate>Mon, 30 Jun 2025 23:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/wrk-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</guid>
      <description>wrk 使用指南 一、介绍 wrk 是一款现代化的 HTTP 基准测试工具，使用 C 语言编写，基于事件通知机制（如 epoll, kqueue），能够产生巨大的负载。相比 ab(apache benchmark)，wrk 具有以下优势：
支持多线程 + 协程模式，能更好地利用多核 CPU
支持 LuaJIT 脚本扩展，可自定义请求生成和结果处理
性能更高，单机可轻松产生数万 QPS
提供更详细的统计信息（延迟分布等）
二、安装 wrk Linux 系统安装
# Ubuntu/Debian sudo apt install wrk -y # CentOS/RHEL sudo yum install wrk -y # 或从源码编译安装 git clone https://github.com/wg/wrk.git cd wrk make sudo cp wrk /usr/local/bin/ macos
brew install wrk 三、基础使用方法 1. 基本命令格式 wrk &amp;lt;选项&amp;gt; &amp;lt;测试URL&amp;gt; 2. 常用选项说明 选项 说明 示例值 -t 使用的线程数 12 (建议设置为CPU核心数的2-4倍) -c 保持打开的连接数 100 -d 测试持续时间 30s (30秒), 2m (2分钟) -s 指定Lua脚本 post.</description>
    </item>
    
    <item>
      <title>EFK技术栈解析及PHP应用实践</title>
      <link>https://blog.leanku.com/post/efk%E6%8A%80%E6%9C%AF%E6%A0%88%E8%A7%A3%E6%9E%90%E5%8F%8Aphp%E5%BA%94%E7%94%A8%E5%AE%9E%E8%B7%B5/</link>
      <pubDate>Sun, 22 Jun 2025 20:49:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/efk%E6%8A%80%E6%9C%AF%E6%A0%88%E8%A7%A3%E6%9E%90%E5%8F%8Aphp%E5%BA%94%E7%94%A8%E5%AE%9E%E8%B7%B5/</guid>
      <description>EFK 技术栈深度解析：从原理到 PHP 应用的全流程实践 日志系统是现代企业级应用不可或缺的基础设施，它如同软件系统的 &amp;ldquo;黑匣子&amp;rdquo;，记录着系统运行的每一个关键节点。在众多日志解决方案中，EFK 技术栈以其轻量级、高性能的特点，成为容器化环境和高并发场景下的首选方案。本文将从 EFK 的核心概念出发，详细阐述其安装配置流程，并结合 PHP 开发场景，展示如何将 EFK 集成到实际项目中。
一、EFK 技术栈核心概念与架构解析 EFK 是 Elasticsearch、Fluentd 和 Kibana 三个开源组件的组合缩写，作为 ELK 技术栈的优化变种，它将 Logstash 替换为更轻量级的 Fluentd，形成了更适合现代云原生环境的日志处理体系。
1.1 EFK 各组件功能定位 Elasticsearch：分布式日志存储与检索引擎
基于 Lucene 的分布式文档存储系统，支持 PB 级日志数据的存储与检索 采用倒排索引结构，实现毫秒级日志搜索响应 天生支持集群架构，通过分片和副本机制保证高可用性 提供 RESTful API 接口，方便与 PHP 等语言集成 Fluentd：高性能日志收集与处理管道
用 C 语言开发的轻量级日志收集器，内存占用仅为 Logstash 的 1/10 支持 &amp;ldquo;一次写入，多次输出&amp;rdquo; 的 Buffer 机制，确保日志不丢失 插件化架构支持 150 + 数据源，包括 PHP 应用、MySQL、Kafka 等 内置 JSON 格式标准化处理，解决多源日志格式不一致问题 Kibana：可视化日志分析与监控平台
为 Elasticsearch 提供图形化查询界面，支持 DSL 语句可视化构建 内置多种可视化组件（折线图、仪表盘、拓扑图等） 支持基于日志数据的实时告警规则配置 提供日志模式识别功能，自动发现异常日志模式 1.</description>
    </item>
    
    <item>
      <title>PHP8新特性：JIT</title>
      <link>https://blog.leanku.com/post/php8%E6%96%B0%E7%89%B9%E6%80%A7jit/</link>
      <pubDate>Sun, 22 Jun 2025 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php8%E6%96%B0%E7%89%B9%E6%80%A7jit/</guid>
      <description>PHP8新特性：JIT（Just-In-Time） 一、JIT（Just-In-Time）编译技术概述 1.1 什么是JIT编译 JIT（Just-In-Time）编译是一种动态编译技术，它在程序运行时将字节码或中间代码编译为机器码执行，而不是预先编译（AOT，Ahead-Of-Time）或纯粹解释执行。PHP 8.0首次引入了JIT编译器，这是PHP性能演进史上的重要里程碑。
1.2 PHP执行模式的演进 解释执行模式（PHP 5.x及之前）： 每次请求都需要解析、编译和执行 无任何形式的持久化缓存 OPCache缓存模式（PHP 5.5+）： 缓存预编译的opcode 减少重复编译开销 但仍需解释执行opcode JIT编译模式（PHP 8.0+）： 将热代码（频繁执行的代码）编译为机器码 直接执行机器码，绕过解释器 1.3 JIT带来的性能提升 根据官方基准测试，JIT在某些计算密集型工作负载上可带来：
数学运算：1.5-3倍提升 字符串处理：1.2-2倍提升 框架综合性能：10-30%提升 注意：JIT对I/O密集型应用（如纯数据库CRUD）提升有限
二、PHP JIT工作原理 2.1 PHP脚本执行流程 PHP源代码 ↓ Zend编译器 (生成opcode) ↓ OPCache (缓存opcode) ↓ Zend VM解释执行 ↓ JIT编译器 (追踪热代码) ↓ 生成机器码 ↓ 直接执行机器码 2.2 JIT编译流程 代码追踪： 监控执行过程中的热代码（频繁执行的代码路径） 默认阈值：执行次数超过3次触发JIT编译 编译优化： 寄存器分配 循环优化 死代码消除 内联函数调用 机器码生成： 针对当前CPU架构生成优化后的机器码 支持x86和ARM架构 执行切换： 后续执行直接跳转到机器码 绕过Zend虚拟机解释器 2.3 JIT与OPCache的关系 协同工作： OPCache是JIT的基础 JIT只编译OPCache中缓存的opcode 内存管理： JIT使用OPCache的共享内存存储机器码 opcache.</description>
    </item>
    
    <item>
      <title>PHP底层原理与性能优化深度解析</title>
      <link>https://blog.leanku.com/post/php%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86%E4%B8%8E%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90/</link>
      <pubDate>Sun, 22 Jun 2025 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86%E4%B8%8E%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90/</guid>
      <description>PHP底层原理与性能优化深度解析 一、PHP生命周期与SAPI PHP的生命周期是一个复杂但有序的过程，理解它对于性能优化至关重要。
1.1 PHP生命周期概述 PHP的生命周期可以概括为以下几个阶段：
模块初始化阶段 (MINIT)
只在PHP启动时执行一次 注册常量、类、资源类型等 所有扩展的MINIT方法被调用 请求初始化阶段 (RINIT)
每个请求开始时执行 初始化脚本运行环境 所有扩展的RINIT方法被调用 脚本执行阶段
解析、编译、执行PHP脚本 生成响应内容 请求关闭阶段 (RSHUTDOWN)
每个请求结束时执行 清理请求级资源 所有扩展的RSHUTDOWN方法被调用 模块关闭阶段 (MSHUTDOWN)
PHP关闭时执行一次 清理持久化资源 所有扩展的MSHUTDOWN方法被调用 1.2 SAPI (Server API) SAPI是PHP与外部环境交互的接口层，常见的SAPI类型包括：
Web服务器集成： Apache (mod_php) Nginx (PHP-FPM) IIS 命令行接口： CLI (Command Line Interface) CGI 嵌入式PHP： 嵌入到其他应用程序中 不同的SAPI实现会影响PHP的生命周期。例如：
在mod_php中，PHP作为Apache模块运行，生命周期与Apache进程绑定 在PHP-FPM中，PHP作为独立的FastCGI进程运行，可以独立管理进程池 二、OPCache原理与优化 2.1 PHP脚本执行流程 传统PHP脚本执行流程：
词法分析 (Lexing) - 将源代码转换为token流 语法分析 (Parsing) - 将token流转换为抽象语法树(AST) 编译 (Compilation) - 将AST转换为opcodes 执行 (Execution) - 执行opcodes 每次请求都需要重复这些步骤，造成大量CPU资源浪费。</description>
    </item>
    
    <item>
      <title>分布式锁详解</title>
      <link>https://blog.leanku.com/post/microservice/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E8%AF%A6%E8%A7%A3/</link>
      <pubDate>Wed, 11 Jun 2025 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/microservice/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E8%AF%A6%E8%A7%A3/</guid>
      <description>分布式锁详解 在高并发和分布式系统中，为保证资源的一致性和互斥访问，分布式锁是必不可少的技术手段。本文将系统地讲解分布式锁的概念、场景、实现原理、使用方式，并附 PHP 示例。
1. 什么是分布式锁 定义：
分布式锁（Distributed Lock）是用于在 多台机器或多个服务实例中控制共享资源访问的机制。它保证在同一时间，只有一个客户端可以操作某个资源，从而避免并发冲突。
特点：
互斥性：同一时间只有一个客户端持有锁。
可重入性（可选）：同一客户端可以重复获取锁。
可靠性：锁过期或客户端异常可自动释放，避免死锁。
可扩展性：适用于分布式系统和微服务架构。
2. 分布式锁的应用场景 分布式锁在企业场景非常常见，典型使用场景包括：
库存扣减
秒杀或抢购场景，防止库存超卖。 订单号生成
保证全局唯一订单号。 任务调度
多实例系统中，保证任务只被单实例执行。 缓存更新
防止缓存击穿时，多实例同时重建缓存。 支付或转账操作
防止重复扣款或资金异常。 3. 分布式锁的实现原理 3.1 数据库锁 原理：
利用数据库唯一索引或事务机制创建锁记录。 示例：
INSERT INTO locks(name, create_time) VALUES(&amp;#39;order_123&amp;#39;, NOW()); -- 成功表示获得锁，失败表示锁已被占用 优缺点：
优点：简单易用，直接使用现有数据库。
缺点：高并发性能较差，数据库可能成为瓶颈。
3.2 Redis 锁 原理：
利用 Redis 的 SETNX 或 SET key value NX PX 原子操作。
设置锁过期时间，防止死锁。
(RedLock红锁可以解决在 Redis ​主从复制或哨兵模式下，使用单实例 Redis 锁可能遇到的锁失效问题。)
释放锁：
需要验证当前客户端持有锁，防止误删他人锁。 优点：</description>
    </item>
    
    <item>
      <title>使用 MinIO 自建云存储</title>
      <link>https://blog.leanku.com/post/%E4%BD%BF%E7%94%A8-minio-%E8%87%AA%E5%BB%BA%E4%BA%91%E5%AD%98%E5%82%A8/</link>
      <pubDate>Mon, 19 May 2025 20:40:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/%E4%BD%BF%E7%94%A8-minio-%E8%87%AA%E5%BB%BA%E4%BA%91%E5%AD%98%E5%82%A8/</guid>
      <description>使用 MinIO 自建云存储 1. MinIO 是什么 定位：一款高性能、开源的 对象存储（Object Storage）系统，完全兼容 AWS S3 API。 核心目标：提供轻量级、易部署的私有云存储方案，适用于云原生和大数据场景。 开源协议：GNU AGPL v3（商业版提供企业级支持）。 核心特性 高性能: 速度优势：支持并行多线程上传/下载，单节点吞吐量可达 10-100 Gbps 低延迟: 采用 Golang 编写，优化内存管理，响应时间在毫秒级 S3 完全兼容 无缝迁移：所有 AWS S3 SDK、CLI 工具（如 awscli）可直接对接 MinIO。 API 支持：覆盖 Put/Get/Object、分片上传、生命周期管理等全部 S3 操作 分布式架构 纠删码（Erasure Code）：数据分片存储，允许节点故障自动恢复（如 4节点容忍2节点失效）。 多租户：支持为不同业务创建隔离的存储桶（Bucket）和访问策略。 轻量易部署 单二进制文件：无需复杂依赖，Docker/Kubernetes 一键部署。 资源占用低：单节点运行仅需 ~200MB 内存，适合边缘计算和 IoT 设备。 适用场景 私有云存储 替代方案：替代阿里云 OSS、AWS S3，实现数据自主可控。 用例：企业文档库、备份归档。 大数据与 AI 兼容性：直接对接 Hadoop HDFS、Spark、TensorFlow 的 S3 接口。 用例：训练数据存储、模型版本管理。 云原生应用 Kubernetes 集成：通过 CSI 驱动为容器提供持久化存储。 用例：微服务应用的文件共享。 边缘计算 轻量级：在树莓派等设备上运行，就近处理数据。 用例：物联网设备数据采集。 2.</description>
    </item>
    
    <item>
      <title>Git项目多远程仓库同步方法</title>
      <link>https://blog.leanku.com/post/git%E9%A1%B9%E7%9B%AE%E5%A4%9A%E8%BF%9C%E7%A8%8B%E4%BB%93%E5%BA%93%E5%90%8C%E6%AD%A5/</link>
      <pubDate>Sun, 18 May 2025 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/git%E9%A1%B9%E7%9B%AE%E5%A4%9A%E8%BF%9C%E7%A8%8B%E4%BB%93%E5%BA%93%E5%90%8C%E6%AD%A5/</guid>
      <description>Git项目多远程仓库同步方法 同一个 Git 项目可以同时推送到多个远程仓库（如 Gogs 和 Gitee）。
1. 添加 Gitee 作为新的远程仓库 git remote add gitee &amp;lt;Gitee仓库的URL&amp;gt; 2. 验证远程仓库设置 git remote -v 3. 推送到 Gitee git push gitee master # 推送 master 分支 # 或推送所有分支： git push --all gitee 4.（可选）设置默认同时推送到两个仓库 修改 .git/config 文件，在 [remote &amp;ldquo;origin&amp;rdquo;] 部分添加多个 push URL：
[remote &amp;#34;origin&amp;#34;] url = https://gogs.example.com/yourname/yourrepo.git fetch = +refs/heads/*:refs/remotes/origin/* pushurl = https://gogs.example.com/yourname/yourrepo.git pushurl = https://gitee.com/yourname/yourrepo.git 这样 git push 会同时推送到两个仓库。
5. （可选）从 Gitee 拉取更新 git pull gitee master 删除指定的远程仓库（如 gitee） git remote remove gitee 注意事项： 两个仓库的分支结构最好保持一致 如果两边都有新的提交，可能需要先合并再推送 大型项目首次推送到 Gitee 可能需要较长时间 这种方法可以让你保持代码在多个远程仓库同步，适用于需要备份或多平台协作的场景。</description>
    </item>
    
    <item>
      <title>基于 Gogs &#43; Jenkins &#43; Harbor &#43; Docker 的自动化部署方案</title>
      <link>https://blog.leanku.com/post/cicd/%E5%9F%BA%E4%BA%8E-gogs-&#43;-jenkins-&#43;-harbor-&#43;-docker-%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E9%83%A8%E7%BD%B2%E6%96%B9%E6%A1%88/</link>
      <pubDate>Sat, 17 May 2025 18:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/cicd/%E5%9F%BA%E4%BA%8E-gogs-&#43;-jenkins-&#43;-harbor-&#43;-docker-%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E9%83%A8%E7%BD%B2%E6%96%B9%E6%A1%88/</guid>
      <description>基于 Gogs + Jenkins + Harbor + Docker 的自动化部署方案 1. 系统架构总览 开发者提交代码 → Git仓库 → Jenkins触发构建 → Docker构建镜像 → 推送至Harbor → Kubernetes部署更新 → 监控反馈 2. 环境准备 2.1 硬件要求 最低配置：2核CPU/4GB内存/100GB存储 推荐配置：4核CPU/8GB内存/200GB SSD 3. 组件安装与配置 3.1 Gogs 安装 另外一篇Jenkins 使用
3.2 Jenkins 安装 另外一篇Gogs 使用
3.3 Harbor 安装 另外一篇Harbor 使用
4. 环境配置 下面以wordpress项目为例
wordpress/ ├── app/ # 项目代码 ├── docker # Docker 相关文件 | ├── Dockerfile | ├── entrypont.sh | └── nginx.conf | └── nginx-wordpress.</description>
    </item>
    
    <item>
      <title>K3s使用指南</title>
      <link>https://blog.leanku.com/post/cicd/k3s%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</link>
      <pubDate>Mon, 12 May 2025 21:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/cicd/k3s%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</guid>
      <description>K3s使用指南+Rancher 1. K3s 简介 K3s 是一个轻量级的 Kubernetes 发行版，由 Rancher Labs（现在是 SUSE 旗下）开发。 它完全兼容 Kubernetes API，但设计上更轻便、易安装，适合边缘计算、物联网设备、单节点或资源有限环境。 K3s 把 Kubernetes 的很多组件做了简化，比如内置了 containerd，默认启用 flannel 网络，去掉了复杂的插件，安装非常简单。 主要目标是让 Kubernetes 快速部署、低资源占用，并且更适合国内和小型集群使用。 2. K3s 对比 kubeadm 特性/方面 K3s kubeadm 定位 轻量级、开箱即用的 Kubernetes 发行版 官方工具，用于标准 Kubernetes 集群的快速部署和引导 安装复杂度 极简安装，单条命令搞定 需要多个步骤，配置复杂，适合有一定 Kubernetes 经验的用户 组件集成 集成了 containerd，默认内置 flannel 网络，默认关闭了部分复杂组件（如部分云插件、Helm等） 只负责初始化集群，组件和网络插件需要用户自行选择安装 资源占用 非常低，适合边缘设备、物联网、单机小集群 资源占用较大，适合生产多节点环境 多节点支持 支持多节点，但更适合轻量和小规模集群 原生支持多节点和大规模集群，灵活度高 适用场景 单机、开发测试、小型集群、资源受限环境 生产环境，多节点，企业级集群部署 网络插件 默认集成 Flannel，安装简单 用户需自行部署网络插件（Flannel、Calico、Weave等） 更新升级 版本更新简单，内置自动化升级工具 需要手动升级，过程复杂 集成工具和生态 内置 Traefik（可选关闭），轻量且默认功能有限 灵活，可按需安装 Ingress、Dashboard、Helm 等组件 社区和支持 Rancher 支持，社区活跃 CNCF 官方支持，社区广泛 官网文档 https://k3s.</description>
    </item>
    
    <item>
      <title>Kubernetes（k8s）单机环境部署 </title>
      <link>https://blog.leanku.com/post/cicd/kubernetesk8s%E5%8D%95%E6%9C%BA%E7%8E%AF%E5%A2%83%E9%83%A8%E7%BD%B2/</link>
      <pubDate>Sun, 11 May 2025 22:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/cicd/kubernetesk8s%E5%8D%95%E6%9C%BA%E7%8E%AF%E5%A2%83%E9%83%A8%E7%BD%B2/</guid>
      <description>Kubernetes（k8s）单机环境部署 1. Kubernetes (K8s) 简介 此文适合新手快速上手，涵盖安装、配置、基本使用 单机环境
2. 环境 系统要求
操作系统：Linux（Ubuntu/CentOS）或 macOS（开发环境） 内存：至少 2GB（推荐 4GB+） CPU：2 核+ 存储：20GB+ 可用空间 安装工具
Docker（K8s 依赖容器运行时） kubectl（K8s 命令行工具） Minikube（本地单节点 K8s，适合学习） 3. 前置配置 # 1.关闭 swap sudo swapoff -a sudo sed -i &amp;#39;/ swap / s/^\(.*\)$/#\1/g&amp;#39; /etc/fstab # 2.加载内核模块 sudo modprobe overlay sudo modprobe br_netfilter # 3.设置内核参数 cat &amp;lt;&amp;lt;EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 EOF sudo sysctl --system 4.</description>
    </item>
    
    <item>
      <title>使用Bark 实现IOS接收通知</title>
      <link>https://blog.leanku.com/post/bark-%E5%AE%9E%E7%8E%B0ios%E6%8E%A5%E6%94%B6%E9%80%9A%E7%9F%A5/</link>
      <pubDate>Sun, 11 May 2025 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/bark-%E5%AE%9E%E7%8E%B0ios%E6%8E%A5%E6%94%B6%E9%80%9A%E7%9F%A5/</guid>
      <description>Bark 实现IOS接收通知 1. Bark介绍 免费、轻量！简单调用接口即可给自己的iPhone发送推送。 依赖苹果APNs，及时、稳定、可靠 不会消耗设备的电量， 基于系统推送服务与推送扩展，APP本体并不需要运行。 隐私安全，可以通过一些方式确保包含作者本人在内的所有人都无法窃取你的隐私。 2. 安装 2.1 AppStore 下载Bark 允许通知权限 替换内容去请求给的地址即可接收通知，各参数可参考文档
2 也可自己部署服务端 bark-server 2.2 下载安装 bark-server # 下载二进制，不同系统注意更换版本 wget https://github.com/Finb/bark-server/releases/download/v2.2.0/bark-server_linux_amd64 chmod +x bark-server_linux_amd64 ./bark-server_linux_amd64 -addr 0.0.0.0:8080 -data ./bark-data 3. 使用 systemd服务单元文件来管理 bark-server 的运行 创建编辑一个服务单元文件
vim /etc/systemd/system/bark-server.service 在文件中添加以下内容：
[Unit] Description=Bark Server After=network.target [Service] ExecStart=/path/to/your/bark-server_linux_amd64 -addr 0.0.0.0:8080 -data /path/to/your/bark-data Restart=always User=your_username Group=your_groupname [Install] WantedBy=multi-user.target 把 /path/to/your/bark-server_linux_amd64 和 /path/to/your/bark-data 替换成实际的文件路径，把 your_username 和 your_groupname 替换成实际的用户名和用户组名。
执行systemctl命令
# 重新加载 systemd 管理器配置 sudo systemctl daemon-reload # 启动 bark-server 服务： sudo systemctl start bark-server # 设置服务开机自启： sudo systemctl enable bark-server # 查看服务状态： sudo systemctl status bark-server # 查看服务日志： sudo journalctl -u bark-server -f 启动成功后 打开iPhone上的Bark添加服务器地址，即可完成自部署</description>
    </item>
    
    <item>
      <title>Gogs 使用指南</title>
      <link>https://blog.leanku.com/post/gogs-%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Sun, 11 May 2025 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/gogs-%E4%BD%BF%E7%94%A8/</guid>
      <description>Gogs 使用 1. 什么是 Gogs? Gogs 是一款极易搭建的自助 Git 服务。 Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自助 Git 服务。使用 Go 语言开发使得 Gogs 能够通过独立的二进制分发，并且支持 Go 语言支持的 所有平台，包括 Linux、Mac OS X、Windows 以及 ARM 平台。 2. 安装 Linux-amd64系统为例 2.1 要求 数据库（选择以下一项） MySQL：版本 &amp;gt;= 5.7 PostgreSQL TiDB 或者 什么都不安装 直接使用 SQLite3 2.2 下载安装 # 下载二进制 wget https://github.com/gogs/gogs/releases/download/v0.13.2/gogs_0.13.2_linux_amd64.tar.gz tar -xzvf gogs_0.13.2_linux_amd64.tar.gz gogs cd gogs ./gogs web 2.3 使用 systemd服务单元文件来管理 创建编辑一个服务单元文件
vim /etc/systemd/system/gogs.service 在文件中添加以下内容：
[Unit] Description=Gogs Server After=network.target [Service] ExecStart=/path/gogs web Restart=always User=your_username Group=your_groupname [Install] WantedBy=multi-user.</description>
    </item>
    
    <item>
      <title>SSH 使用指南</title>
      <link>https://blog.leanku.com/post/ssh-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</link>
      <pubDate>Sun, 11 May 2025 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/ssh-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</guid>
      <description>SSH 使用指南：从基础到服务器密钥登录 什么是 SSH？ SSH (Secure Shell) 是一种加密的网络协议，用于在不安全的网络中安全地进行远程登录和其他网络服务。它通过加密技术保护通信安全，防止信息泄露和中间人攻击，是系统管理员和开发人员管理远程服务器的必备工具。
基本 SSH 连接 最基本的 SSH 连接命令格式如下：
ssh username@hostname 例如，要连接到 IP 为 192.168.1.100 的服务器，用户名为 admin：
ssh admin@192.168.1.100 首次连接时会提示验证服务器指纹：
The authenticity of host &amp;#39;192.168.1.100 (192.168.1.100)&amp;#39; can&amp;#39;t be established. ECDSA key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. Are you sure you want to continue connecting (yes/no)? 输入 yes 后，服务器指纹会被保存在本地 ~/.ssh/known_hosts 文件中，以后连接时会自动验证。
SSH 配置文件 SSH 客户端配置文件 ~/.ssh/config 可以简化连接命令。例如：
Host myserver HostName 192.168.1.100 User admin Port 2222 配置后，只需输入 ssh myserver 即可连接。</description>
    </item>
    
    <item>
      <title>Prometheus &#43; Grafana &#43; Alertmanager轻量级监控告警系统</title>
      <link>https://blog.leanku.com/post/prometheus-&#43;-grafana-&#43;-alertmanager%E8%BD%BB%E9%87%8F%E7%BA%A7%E7%9B%91%E6%8E%A7%E5%91%8A%E8%AD%A6%E7%B3%BB%E7%BB%9F/</link>
      <pubDate>Sun, 11 May 2025 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/prometheus-&#43;-grafana-&#43;-alertmanager%E8%BD%BB%E9%87%8F%E7%BA%A7%E7%9B%91%E6%8E%A7%E5%91%8A%E8%AD%A6%E7%B3%BB%E7%BB%9F/</guid>
      <description>Prometheus + Grafana + Alertmanager轻量级监控告警系统 一、工具简介与官网 工具 作用 官网文档地址 Prometheus 指标采集、存储与告警规则管理 prometheus.io/docs Node Exporter 暴露服务器硬件/OS指标 github.com/prometheus/node_exporter Alertmanager 告警聚合与通知发送 prometheus.io/docs/alerting Grafana 数据可视化与仪表盘 grafana.com/docs 二、安装与配置 1. Prometheus 安装 1.1 下载与解压 wget https://github.com/prometheus/prometheus/releases/download/v2.51.0/prometheus-2.51.0.linux-amd64.tar.gz tar xvf prometheus-2.51.0.linux-amd64.tar.gz cd prometheus-2.51.0.linux-amd64 1.2 配置监控目标 编辑 prometheus.yml：
global: scrape\_interval: 15s evaluation\_interval: 15s scrape\_configs: \- job\_name: &amp;#34;prometheus&amp;#34; \# 监控自身 static\_configs: \- targets: \[&amp;#34;localhost:9090&amp;#34;\] \- job\_name: &amp;#34;node&amp;#34; \# 监控服务器 static\_configs: \- targets: \[&amp;#34;&amp;lt;NODE\_IP&amp;gt;:9100&amp;#34;\] \# 替换为Node Exporter的IP 1.3 启动 Prometheus ./prometheus \--config.</description>
    </item>
    
    <item>
      <title>Git创建不继承内容的新分支</title>
      <link>https://blog.leanku.com/post/git-filter-branch-%E6%B8%85%E7%90%86%E8%AF%AF%E6%8F%90%E4%BA%A4%E5%A4%A7%E6%96%87%E4%BB%B6/</link>
      <pubDate>Sat, 10 May 2025 19:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/git-filter-branch-%E6%B8%85%E7%90%86%E8%AF%AF%E6%8F%90%E4%BA%A4%E5%A4%A7%E6%96%87%E4%BB%B6/</guid>
      <description>git filter-branch 清理误提交大文件 问题概述： 在当前项目中放有大文件（超过100M）package/grpc.tar.gz,进行了git add,commit 并push, push过程中出现了错误如：
remote: error: File package/grpc.tar.gz is 973.06 MB; this exceeds GitHub&#39;s file size limit of 100.00 MB 这个问题会导致后面的提交以及push出错
git filter-branch 用 git filter-branch 删除历史中所有的 grpc.tar.gz
git filter-branch --force --index-filter \ &amp;#34;git rm --cached --ignore-unmatch package/grpc.tar.gz&amp;#34; \ --prune-empty -- lite-AlmaLinux 💡 说明：这个命令会清理当前分支里所有 commit 中的 package/grpc.tar.gz
清理垃圾对象并压缩仓库大小
git reflog expire --expire=now --all git gc --prune=now --aggressive 然后重新 push（第一次 push 分支）
git push --set-upstream origin lite-AlmaLinux 防止此类问题 优化 .</description>
    </item>
    
    <item>
      <title>Jenkins 使用 </title>
      <link>https://blog.leanku.com/post/cicd/jenkins-%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Fri, 09 May 2025 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/cicd/jenkins-%E4%BD%BF%E7%94%A8/</guid>
      <description>Jenkins 使用 1. 安装Jenkins sudo wget -O /etc/yum.repos.d/jenkins.repo \ https://pkg.jenkins.io/redhat/jenkins.repo sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io-2023.key sudo yum upgrade # Add required dependencies for the jenkins package sudo yum install fontconfig java-21-openjdk sudo yum install jenkins 2. 启动 Jenkins sudo systemctl enable jenkins sudo systemctl start jenkins # 检查状态 sudo systemctl status jenkins 正常输出应显示 active (running)。
开放防火墙（如需） # 开放 8080 端口（Jenkins 默认端口） sudo firewall-cmd --permanent --add-port=8080/tcp sudo firewall-cmd --reload 3. 配置Jenkins 3.1 访问 Jenkins 并完成初始化 在浏览器访问：http://&amp;lt;服务器IP&amp;gt;:8080 获取初始管理员密码： sudo cat /var/lib/jenkins/secrets/initialAdminPassword 复制输出的密码粘贴到网页。 安装推荐插件：选择默认插件集（包括Git、Pipeline等常用工具）。 3.</description>
    </item>
    
    <item>
      <title>Harbor  使用 </title>
      <link>https://blog.leanku.com/post/harbor-%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Thu, 08 May 2025 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/harbor-%E4%BD%BF%E7%94%A8/</guid>
      <description>Harbor 使用 1. 安装Harbor 此处使用官方离线安装包
1. 下载解压 # 安装编译依赖 # 安装 Docker sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io sudo systemctl enable --now docker # 安装 Docker Compose 页面下载的话注意版本比如 验证系统架构uname -m输出x86_64 sudo curl -L &amp;#34;https://github.com/docker/compose/releases/download/v2.23.3/docker-compose-$(uname -s)-$(uname -m)&amp;#34; -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose # 下载Harbor并解压 (我用的离线安装包包含所有依赖镜像) wget https://github.com/goharbor/harbor/releases/download/v2.12.3/harbor-offline-installer-v2.12.3.tgz tar -xzvf harbor-offline-installer-v2.12.3.tgz cd harbor 2. 生成自签名证书（IP方式） 如果使用http则不需要设置
sudo mkdir -p /etc/harbor/ssl sudo chmod 755 /etc/harbor/ssl sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/harbor/ssl/your_ip.</description>
    </item>
    
    <item>
      <title>Kubernetes学习指北</title>
      <link>https://blog.leanku.com/post/devops/kubernetes%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8C%97/</link>
      <pubDate>Thu, 01 May 2025 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/devops/kubernetes%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8C%97/</guid>
      <description>Kubernetes学习指北 一、 大纲 1. 了解基础概念 概念 说明 Pod 最小的调度单位，一个 Pod 可以包含一个或多个容器 Node Kubernetes 集群的工作节点 Deployment 管理 Pod 的副本和升级策略 Service 用于 Pod 间通信和对外暴露 ConfigMap / Secret 配置和敏感信息管理 Volume 数据卷，用于持久化数据 Namespace 命名空间，多租户环境的逻辑隔离 Ingress 对外 HTTP/HTTPS 流量管理 kube-apiserver、kube-scheduler、kube-controller-manager Master 组件，负责调度、管理集群 2. 核心组件及职责 （必须的核心组件） kube-apiserver （API 服务器） 作用： 集群的 大脑入口 负责 接收请求（kubectl、Dashboard、其他服务），然后转给 etcd 或控制器 所有组件（scheduler、controller、kubelet）都通过它通信。 像是办事大厅，所有人（开发、运维、调度器）都必须来这里递交申请。 kube-scheduler （调度器） * 作用： 负责 给 Pod 找宿主机。 根据 资源情况（CPU、内存）、约束（亲和性、污点）、策略 来决定 Pod 放在哪个 Node 上。 * 像是一个 派单员，根据司机（Node）的空闲情况，把订单（Pod）分配给合适的人。 kube-controller-manager （控制器管理器） * 作用： 内部包含很多 控制器（controller），比如： Deployment Controller：保证副本数量正确 Node Controller：监控节点状态。 Endpoint Controller：维护 Service → Pod 的映射。 核心任务是：对比实际状态和期望状态，不断修正。 * 像是一个 巡检员，不停检查「理想状态」和「现实情况」是不是一致，如果发现差错，就赶紧修正。 kubelet （节点代理） 作用： 跑在每个 Node 上的 代理。 负责和 kube-apiserver 交互，接收“要运行哪些 Pod”。 调用底层 容器运行时（containerd、CRI-O、Docker） 来真正启动容器。 还会 汇报 Pod 和 Node 的运行状态。 * 像是 工地上的施工队长，接到上级（apiserver）的命令，就去调度工人（containerd）建房子（Pod）。 etcd 作用： 分布式键值存储，保存集群的所有状态（Pod、Service、配置等） * 像是 工地上的施工队长，接到上级（apiserver）的命令，就去调度工人（containerd）建房子（Pod） 容器运行时（Container Runtime，如 containerd、CRI-O、DockerShim） 作用： kubelet 本身不会直接运行容器，它要依赖运行时。 真正负责创建和运行容器的底层引擎。 常见的有 containerd（最主流，K8s 默认推荐） CRI-O（轻量化，专门为 K8s 服务） Docker（以前常用，但现在 K8s 不直接依赖它了，而是通过 containerd） * 比喻：工人，真正搬砖盖房子（运行容器）。 3.</description>
    </item>
    
    <item>
      <title>Kubernetes学习指北之Kubernetes kubectl</title>
      <link>https://blog.leanku.com/post/devops/kubernetes%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8C%97%E4%B9%8Bkubernetes-kubectl/</link>
      <pubDate>Thu, 01 May 2025 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/devops/kubernetes%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8C%97%E4%B9%8Bkubernetes-kubectl/</guid>
      <description>Kubernetes学习指北之Kubernetes kubectl 一、 kubectl 介绍 kubectl 是 Kubernetes 官方提供的命令行工具，用于与 Kubernetes 集群交互。
它可以管理资源对象（Pods、Deployments、Services 等）、调试问题、查看日志、扩缩容、发布更新等。
本质上，它通过 Kubernetes API 与集群通信。
组件关系示意：
kubectl &amp;lt;---&amp;gt; kube-apiserver &amp;lt;---&amp;gt; etcd / kubelet / controller-manager / scheduler 二、安装与配置 1. 安装（Linux）： curl -LO &amp;#34;https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl&amp;#34; chmod +x kubectl sudo mv kubectl /usr/local/bin/ kubectl version --client 2. 配置 kubeconfig 默认路径：~/.kube/config 查看当前配置： kubectl config view kubectl config current-context 切换 namespace： kubectl config set-context --current --namespace=demo 三、基础命令 1. 查看集群信息 kubectl cluster-info # 控制面信息 kubectl version # 客户端 &amp;amp; 服务端版本 kubectl api-resources # 列出可用资源 kubectl get namespaces # 查看命名空间 2.</description>
    </item>
    
    <item>
      <title>Kubernetes学习指北之Kubernetes YAML</title>
      <link>https://blog.leanku.com/post/devops/kubernetes%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8C%97%E4%B9%8Bkubernetes-yaml/</link>
      <pubDate>Thu, 01 May 2025 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/devops/kubernetes%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8C%97%E4%B9%8Bkubernetes-yaml/</guid>
      <description>Kubernetes学习指北之Kubernetes YAML 一、 Kubernetes YAML 的基本结构 Kubernetes 资源对象通常是 YAML 文件。每个 YAML 对象至少包含三个字段：
apiVersion: v1 # API 版本，不同资源使用的版本不同 kind: Pod # 资源类型，如 Pod、Deployment、Service、Secret、ConfigMap metadata: # 元数据 name: my-pod namespace: default spec: # 具体配置 containers: - name: nginx image: nginx:1.25 二、常用字段详解 1. apiVersion 指定资源的 API 版本。 常见值： v1：Pod、Service、ConfigMap、Secret apps/v1：Deployment、StatefulSet、DaemonSet batch/v1：Job、CronJob 2. kind 资源类型 常见类型： Pod：最小的调度单位 Deployment：Pod 的管理控制器，可以做副本管理和滚动升级 Service：服务发现与负载均衡 ConfigMap / Secret：配置或敏感信息管理 Namespace：隔离资源的逻辑空间 3. metadata 资源的名字、标签、注解等。 常见字段： metadata: name: my-app namespace: default labels: app: my-app annotations: description: &amp;#34;Demo app&amp;#34; 4.</description>
    </item>
    
    <item>
      <title>Kubernetes学习指北之单节点集群（Master）</title>
      <link>https://blog.leanku.com/post/devops/kubernetes%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8C%97%E4%B9%8B%E5%8D%95%E8%8A%82%E7%82%B9%E9%9B%86%E7%BE%A4master/</link>
      <pubDate>Thu, 01 May 2025 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/devops/kubernetes%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8C%97%E4%B9%8B%E5%8D%95%E8%8A%82%E7%82%B9%E9%9B%86%E7%BE%A4master/</guid>
      <description>Kubernetes学习指北之单节点集群（Master） 一、 单节点集群（Single Node Cluster）说明 学习和开发利器，操作简单
特点 Master 节点和 Worker 节点在同一台机器上 kube-apiserver、kube-scheduler、kube-controller-manager、kubelet 都在同一台机器 Pod 也在同一台机器上运行 资源有限：所有容器共享同一台机器的 CPU、内存和存储 高可用性低：Master 节点宕机，整个集群不可用 网络简单：只需一个节点，Pod 网络配置相对简单 适用场景 学习和测试 Kubernetes 核心概念 开发环境部署微服务 练习 kubectl 命令、Deployment、Service 等 优点 配置简单，一条命令就能搭建
资源占用低，不需要多台虚拟机
部署快速，便于练手
缺点 不适合生产环境
没有高可用性
无法模拟真实多节点调度
二、 准备环境和工具 这里我使用的CentOS7 做一些初始化 # 切换 root sudo -i # 关闭防火墙（实验环境） systemctl stop firewalld systemctl disable firewalld # 关闭 selinux setenforce 0 sed -i &amp;#39;s/^SELINUX=enforcing$/SELINUX=disabled/&amp;#39; /etc/selinux/config # 关闭 swap swapoff -a sed -i &amp;#39;/swap/d&amp;#39; /etc/fstab # 调整内核参数（K8s 网络需要） cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/sysctl.</description>
    </item>
    
    <item>
      <title>Kubernetes学习指北之多节点集群（Multi Node Cluster）</title>
      <link>https://blog.leanku.com/post/devops/kubernetes%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8C%97%E4%B9%8B%E5%A4%9A%E8%8A%82%E7%82%B9%E9%9B%86%E7%BE%A4multi-node-cluster/</link>
      <pubDate>Thu, 01 May 2025 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/devops/kubernetes%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8C%97%E4%B9%8B%E5%A4%9A%E8%8A%82%E7%82%B9%E9%9B%86%E7%BE%A4multi-node-cluster/</guid>
      <description>Kubernetes学习指北之多节点集群（Multi Node Cluster） 一、 多节点集群（Multi Node Cluster）说明 真实生产环境的缩影，可以模拟调度、高可用、跨节点通信
特点 Master 节点负责管理集群
多个 Worker 节点运行实际应用 Pod
Master 负责调度、管理和监控
高可用性可扩展
可以增加 Worker 节点提升容量
Master 可做 HA（高可用）部署
真实调度场景
Kubernetes 会根据资源和策略，将 Pod 调度到不同节点 网络复杂
Pod 网络跨节点，需要 CNI 插件（Flannel、Calico 等）支持 适用场景 生产环境部署微服务
测试调度策略、Pod 分布、Service 负载均衡
实战演练集群管理和高可用
优点 模拟真实生产环境
可以横向扩展容器数量
Master 故障可配置高可用
缺点 配置复杂，需要多台虚拟机或服务器
网络和存储管理比单节点复杂
资源占用高
二、 准备环境和工具 这里使用centos7环境 说明
sudo -i 建议用root账号操作
每台节点都需要执行的操作，包括 master 和 worker：系统初始化、安装和配置容器运行时（containerd）、镜像源替换等操作
这里不再赘述，参照另一篇：Kubernetes学习指北之单节点集群
三、节点准备 在每台节点上安装：
# 安装 kubeadm、kubelet、kubectl yum install -y kubelet kubeadm kubectl # 启动 kubelet systemctl enable --now kubelet # 关闭 swap（K8s 要求） swapoff -a sed -i &amp;#39;/swap/d&amp;#39; /etc/fstab # 配置 sysctl cat &amp;lt;&amp;lt;EOF | sudo tee /etc/sysctl.</description>
    </item>
    
    <item>
      <title>GitHub 项目版本管理规范</title>
      <link>https://blog.leanku.com/post/github-%E9%A1%B9%E7%9B%AE%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86%E8%A7%84%E8%8C%83/</link>
      <pubDate>Fri, 11 Apr 2025 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/github-%E9%A1%B9%E7%9B%AE%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86%E8%A7%84%E8%8C%83/</guid>
      <description>GitHub 项目版本管理规范 Git 标签（Tags）和 发布（Releases） 在 GitHub 项目中定义和管理版本，通常结合 Git 标签（Tags）、发布（Releases） 和 语义化版本（SemVer） 来实现。以下是具体方法和最佳实践：
1. 使用 Git 标签（Tags）定义版本 （1）创建版本标签 # 创建轻量标签 git tag v1.0.0 # 创建附注标签（推荐，包含提交信息和签名） git tag -a v1.0.0 -m &amp;#34;Release version 1.0.0&amp;#34; # 推送标签到 GitHub git push origin v1.0.0 （2）语义化版本（SemVer） 版本号格式：MAJOR.MINOR.PATCH
MAJOR：不兼容的 API 变更 MINOR：向后兼容的功能新增 PATCH：向后兼容的问题修复 示例：
v1.0.0：初始稳定版本 v1.2.3：第 1 个大版本，第 2 次功能更新，第 3 次补丁 2. 通过 GitHub Releases 管理版本 （1）手动创建 Release 进入 GitHub 仓库 → Releases → Draft a new release</description>
    </item>
    
    <item>
      <title>PHP 实现 Redis 高并发解决方案</title>
      <link>https://blog.leanku.com/post/php-%E5%AE%9E%E7%8E%B0-redis-%E9%AB%98%E5%B9%B6%E5%8F%91%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/</link>
      <pubDate>Fri, 28 Mar 2025 22:33:45 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php-%E5%AE%9E%E7%8E%B0-redis-%E9%AB%98%E5%B9%B6%E5%8F%91%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/</guid>
      <description>PHP 实现 Redis 高并发解决方案 使用 PHP 实现 Redis 在缓存加速、分布式锁和队列场景中的应用。
首先确保已安装 PHP Redis 扩展
一、缓存加速实现 1. 基本缓存操作 &amp;lt;?php $redis = new Redis(); $redis-&amp;gt;connect(&amp;#39;127.0.0.1&amp;#39;, 6379); // 设置缓存 function setCache($key, $value, $expire = 3600) { global $redis; $serialized = serialize($value); return $redis-&amp;gt;setex($key, $expire, $serialized); } // 获取缓存 function getCache($key) { global $redis; $serialized = $redis-&amp;gt;get($key); return $serialized ? unserialize($serialized) : false; } // 删除缓存 function deleteCache($key) { global $redis; return $redis-&amp;gt;del($key); } // 示例：用户数据缓存 function getUser($userId) { $cacheKey = &amp;#34;user:{$userId}&amp;#34;; $user = getCache($cacheKey); if ($user === false) { // 模拟数据库查询 $user = [ &amp;#39;id&amp;#39; =&amp;gt; $userId, &amp;#39;name&amp;#39; =&amp;gt; &amp;#39;User &amp;#39; .</description>
    </item>
    
    <item>
      <title>Mysql窗口函数 </title>
      <link>https://blog.leanku.com/post/database/mysql%E7%AA%97%E5%8F%A3%E5%87%BD%E6%95%B0/</link>
      <pubDate>Thu, 20 Feb 2025 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql%E7%AA%97%E5%8F%A3%E5%87%BD%E6%95%B0/</guid>
      <description>Mysql窗口函数 一、什么是窗口函数？ 窗口函数是一种在查询结果的&amp;quot;窗口&amp;quot;上执行计算的函数，它不会像常规聚合函数那样将多行合并为一行，而是为每一行返回一个值，同时保持原始行数不变。
基本语法 &amp;lt;窗口函数&amp;gt;(&amp;lt;参数&amp;gt;) OVER ( [PARTITION BY &amp;lt;分区表达式&amp;gt;] [ORDER BY &amp;lt;排序表达式&amp;gt; [ASC | DESC]] [ROWS/RANGE &amp;lt;窗口范围&amp;gt;] ) ‌&amp;lt;窗口函数&amp;gt;‌：可以是聚合函数（如SUM、AVG）或专用函数（如ROW_NUMBER、RANK）。‌‌ ‌OVER()‌：必需子句，定义窗口框架。‌‌ ‌PARTITION BY‌：可选，用于分组数据；若省略，窗口覆盖整个结果集。 ‌ORDER BY‌：可选，指定窗口内行的排序顺序。‌‌ ‌窗口范围‌：可选，默认ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。‌‌ 二、 准备测试数据 -- 创建销售数据表 CREATE TABLE sales ( sale_id INT PRIMARY KEY, salesperson VARCHAR(50), region VARCHAR(50), sale_date DATE, amount DECIMAL(10,2) ); INSERT INTO sales VALUES (1, &amp;#39;张三&amp;#39;, &amp;#39;北京&amp;#39;, &amp;#39;2023-01-15&amp;#39;, 5000), (2, &amp;#39;李四&amp;#39;, &amp;#39;上海&amp;#39;, &amp;#39;2023-01-16&amp;#39;, 8000), (3, &amp;#39;王五&amp;#39;, &amp;#39;北京&amp;#39;, &amp;#39;2023-01-17&amp;#39;, 6000), (4, &amp;#39;张三&amp;#39;, &amp;#39;北京&amp;#39;, &amp;#39;2023-02-01&amp;#39;, 7000), (5, &amp;#39;李四&amp;#39;, &amp;#39;上海&amp;#39;, &amp;#39;2023-02-02&amp;#39;, 9000), (6, &amp;#39;赵六&amp;#39;, &amp;#39;广州&amp;#39;, &amp;#39;2023-02-03&amp;#39;, 4000), (7, &amp;#39;王五&amp;#39;, &amp;#39;北京&amp;#39;, &amp;#39;2023-02-04&amp;#39;, 5500), (8, &amp;#39;张三&amp;#39;, &amp;#39;北京&amp;#39;, &amp;#39;2023-03-01&amp;#39;, 8500); -- 创建员工薪资表 CREATE TABLE employee_salary ( emp_id INT, name VARCHAR(50), department VARCHAR(50), salary DECIMAL(10,2), hire_date DATE ); INSERT INTO employee_salary VALUES (1, &amp;#39;张三&amp;#39;, &amp;#39;技术部&amp;#39;, 15000, &amp;#39;2020-01-15&amp;#39;), (2, &amp;#39;李四&amp;#39;, &amp;#39;技术部&amp;#39;, 12000, &amp;#39;2021-03-20&amp;#39;), (3, &amp;#39;王五&amp;#39;, &amp;#39;销售部&amp;#39;, 8000, &amp;#39;2022-06-10&amp;#39;), (4, &amp;#39;赵六&amp;#39;, &amp;#39;销售部&amp;#39;, 7500, &amp;#39;2022-08-05&amp;#39;), (5, &amp;#39;钱七&amp;#39;, &amp;#39;技术部&amp;#39;, 13000, &amp;#39;2020-11-30&amp;#39;), (6, &amp;#39;孙八&amp;#39;, &amp;#39;人事部&amp;#39;, 9000, &amp;#39;2021-09-15&amp;#39;), (7, &amp;#39;周九&amp;#39;, &amp;#39;技术部&amp;#39;, 16000, &amp;#39;2019-05-20&amp;#39;); 1.</description>
    </item>
    
    <item>
      <title>MyCat实现Mysql分库分表</title>
      <link>https://blog.leanku.com/post/database/mycat%E5%AE%9E%E7%8E%B0mysql%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8/</link>
      <pubDate>Tue, 18 Feb 2025 20:33:45 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mycat%E5%AE%9E%E7%8E%B0mysql%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8/</guid>
      <description>Mysql分库分表和主从复制 MyCat 实现分库分表 MySQL 的分库分表解决方案通常依赖于中间件来实现水平扩展。常见的中间件有以下几种
MyCat ShardingSphere TDDL (Taobao Distributed Data Layer) Cobar Vitess MyCat 是一款开源的数据库中间件，支持 MySQL 数据库的分库分表功能。
使用 MyCat 实现分库分表的过程包括多个步骤，涉及配置 MyCat 和数据库的分片策略，路由规则等。下面通过一个实际案例来详细解释 MyCat 的实现原理、方式和步骤。
案例背景 假设你有一个电商系统，包含一个 orders 表，记录用户的订单信息。随着数据量的增长，单一数据库难以满足性能需求，因此需要进行 分库分表。
实现原理 MyCat 是一种数据库中间件，支持分库分表。它的原理是通过代理 MySQL 连接，将 SQL 请求转发到实际的数据库实例上。MyCat 会根据预定义的路由规则（如分片策略）来决定将查询请求路由到哪个数据库或表。
MyCat 的 分库分表原理如下：
分库：将数据按照某种规则分配到多个数据库实例中。例如，按用户的 ID 来分库。
分表：将一个大表拆分成多个小表，避免单表的数据过大导致查询性能下降。例如，可以按时间范围或数据量来分表。
实现方式 MyCat 的实现方式主要通过 配置分片规则 来实现分库分表。配置内容包括：
数据源配置：定义数据库实例。 分片规则配置：指定哪些字段用于分片，如何分片（按范围、按哈希等）。 路由规则配置：根据 SQL 查询的条件来路由请求到不同的数据库或表。 实现步骤 安装并启动 MyCat
下载 MyCat 安装包并解压。 配置 MyCat 启动脚本，启动 MyCat。 cd MyCat ./bin/start.sh 配置数据源 在 MyCat 的配置文件 conf/context.</description>
    </item>
    
    <item>
      <title>Linux grep命令</title>
      <link>https://blog.leanku.com/post/linux-grep%E5%91%BD%E4%BB%A4/</link>
      <pubDate>Mon, 17 Feb 2025 22:33:45 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/linux-grep%E5%91%BD%E4%BB%A4/</guid>
      <description>Linux grep命令 全拼:Global search REgular expression and Print out the line.
作用:文本搜索工具，根据用户指定的“模式（过滤条件)”对目标文本逐行进行匹配检查，打印匹配到的行.
模式:由正则表达式的元字符及文本字符所编写出的过滤条件﹔
grep的语法格式：
grep -option（参数） ‘word’（关键词） file（文本文件）；
grep常用参数： –color=auto 或者 –color：表示对匹配到的文本着色显示
-i：在搜索的时候忽略大小写
-n：显示结果所在行号
-c：统计匹配到的行数，注意，是匹配到的总行数，不是匹配到的次数
-o：只显示符合条件的字符串，但是不整行显示，每个符合条件的字符串单独显示一行
-v：输出不带关键字的行（反向查询，反向匹配）
-w：匹配整个单词，如果是字符串中包含这个单词，则不作匹配
-Ax：在输出的时候包含结果所在行之后的指定行数，这里指之后的x行，A：after
-Bx：在输出的时候包含结果所在行之前的指定行数，这里指之前的x行，B：before
-Cx：在输出的时候包含结果所在行之前和之后的指定行数，这里指之前和之后的x行，C：context
-e：实现多个选项的匹配，逻辑or关系
-q：静默模式，不输出任何信息，当我们只关心有没有匹配到，却不关心匹配到什么内容时，我们可以使用此命令，然后，使用”echo $?”查看是否匹配到，0表示匹配到，1表示没有匹配到。
-P：表示使用兼容perl的正则引擎。
-E：使用扩展正则表达式，而不是基本正则表达式，在使用”-E”选项时，相当于使用egrep。
示例 # 从test.txt文本文件中搜索包含”L”字符的行 grep &amp;#34;L&amp;#34; test.txt # 输出以 I 开头的行(不区分大小写) grep &amp;#34;^i&amp;#34; test.txt -i -n -o # 可以使用”--color”选项，高亮显示行中的关键字 grep &amp;#34;L&amp;#34; test.txt -i -n --color # -B”选项，显示符合条件的行之前的行，&amp;#34;B&amp;#34;有before之意 grep &amp;#34;L&amp;#34; test.txt -i -n --color -B2 # &amp;#34;-A&amp;#34;有After之意，&amp;#34;-A&amp;#34;代表显示符合条件的行的同时，还要显示之后的行，&amp;#34;-A3&amp;#34;表示同时显示符合条件的行之后的3行。 grep &amp;#34;L&amp;#34; test.</description>
    </item>
    
    <item>
      <title>Linux sed命令</title>
      <link>https://blog.leanku.com/post/linux-sed%E5%91%BD%E4%BB%A4/</link>
      <pubDate>Mon, 17 Feb 2025 22:33:45 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/linux-sed%E5%91%BD%E4%BB%A4/</guid>
      <description>Linux sed命令 全拼:Stream EDitor（流编辑器）
Linux sed 命令是利用脚本来处理文本文件，sed 可依照脚本的指令来处理、编辑文本文件。Sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。
sed 的运行模式 当处理数据时，Sed 从输入源一次读入一行，并将它保存到所谓的模式空间pattern space中。所有 Sed 的变换都发生在模式空间。变换都是由命令行上或外部 Sed 脚本文件提供的单字母命令来描述的。大多数 Sed 命令都可以由一个地址或一个地址范围作为前导来限制它们的作用范围。
sed的相关选项 -n, &amp;ndash;quiet, &amp;ndash;silent 取消自动打印模式空间
-e 脚本, &amp;ndash;expression=脚本 添加“脚本”到程序的运行列表
-f 脚本文件, &amp;ndash;file=脚本文件 添加“脚本文件”到程序的运行列表
&amp;ndash;follow-symlinks 直接修改文件时跟随软链接
-i[扩展名], &amp;ndash;in-place[=扩展名] 直接修改文件(如果指定扩展名就备份文件)
-l N, &amp;ndash;line-length=N 指定“l”命令的换行期望长度
&amp;ndash;posix 关闭所有 GNU 扩展
-r, &amp;ndash;regexp-extended 在脚本中使用扩展正则表达式
-s, &amp;ndash;separate 将输入文件视为各个独立的文件而不是一个长的连续输入
-u, &amp;ndash;unbuffered 从输入文件读取最少的数据，更频繁的刷新输出
&amp;ndash;help 打印帮助并退出
&amp;ndash;version 输出版本信息并退出
-a ∶新增， a 的后面可以接字串，而这些字串会在新的一行出现(目前的下一行)～
-c ∶取代， c 的后面可以接字串，这些字串可以取代 n1,n2 之间的行！
-d ∶删除，因为是删除啊，所以 d 后面通常不接任何咚咚；</description>
    </item>
    
    <item>
      <title>Linux 进程管理命令</title>
      <link>https://blog.leanku.com/post/linux-%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4/</link>
      <pubDate>Mon, 17 Feb 2025 22:33:45 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/linux-%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E5%91%BD%E4%BB%A4/</guid>
      <description>Linux ps命令 ps 命令是 Process Status 的缩写，是一个命令行实用程序，用于显示或查看与Linux系统中运行的进程相关的信息。
命令原理：ps 是通过读取虚拟文件：/proc 拿到进程数据的，不需要给 ps 设置任何的权限就可以运行。
在Linux中，每个进程都有多个ID来关联它，包括：
Process ID (PID)，即进程ID
这是标识进程的任意数字。每个进程都有一个唯一的ID，但是在进程退出并且父进程检索了退出状态之后，进程ID将被释放，供新进程重用。
Parent Process ID (PPID)，即父进程ID
如果父进程在子进程退出之前退出，则子进程的PPID将更改为另一个进程。
Process Group ID (PGID)
这是进程组leader的PID。如果PID == PGID，则此进程是进程组领导。
Session ID (SID)
这是会话领导者的PID。如果PID == SID，则此进程为会话领导进程。
会话和进程组只是将一些相关的进程作为一个单元来对待的方法。一个进程组的所有成员总是属于同一个会话，但是一个会话可以有多个进程组。
通常，shell将是会话领导者，该shell执行的每个管道将是一个进程组。这是为了在shell退出时很容易杀死它的子进程。
grep -option（参数） ‘word’（关键词） file（文本文件）；
ps命令选项： 简单筛选
a ：选择所有进程（BSD-Style）。
-A ：选择所有进程，与 -e 等同（标准格式）。
-a ：选择除 session 领导者和没有与终端关联的进程之外的所有进程。
-d ：选择除了 session leader 的所有进程。
&amp;ndash;deselect ：选择除满足指定条件之外的所有进程，即反选，与 -N 等同。
-e ：选择所有进程，与 -A 等同。
-N ：与 &amp;ndash;deselect 等同。</description>
    </item>
    
    <item>
      <title>视频内容处理工具分享之 VideoLingo</title>
      <link>https://blog.leanku.com/post/tools/%E8%A7%86%E9%A2%91%E5%86%85%E5%AE%B9%E5%A4%84%E7%90%86%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB%E4%B9%8B-videolingo/</link>
      <pubDate>Sat, 11 Jan 2025 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/tools/%E8%A7%86%E9%A2%91%E5%86%85%E5%AE%B9%E5%A4%84%E7%90%86%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB%E4%B9%8B-videolingo/</guid>
      <description>视频内容处理工具分享之 VideoLingo VideoLingo 是目前处理视频技术内容最强的开源工具之一。它的核心优势在于不仅仅是“语音转文字”，它还会利用 AI（如 DeepSeek 或 GPT）对内容进行 NLP 断句（让文字像书一样好读）并生成总结。
一、安装方式： 1. 最简单“一键整合包”（适合 Windows 用户） 如果你不想折腾 Python 环境，可以寻找社区维护的一键整合包（如 GitHub 上的 VideoLingo-OneClick 项目）。
下载：从网盘或 GitHub Releases 下载解压包。
启动：双击 启动软件.exe 或 一键启动.bat。
配置：它会弹出一个网页界面。在左侧填入你的 LLM API Key（支持 DeepSeek、OpenAI 等，技术总结必须用到大模型）。
2. 标准安装 如果你想体验最新功能，建议通过源码安装：
1. 准备环境 安装 Python 3.10（必须是这个版本）。
安装 FFmpeg（参考上一个回答）。
如果你有 NVIDIA 显卡，建议安装 CUDA Toolkit 12.6 以获得加速。
2. 源码下载与安装 在终端（Terminal/CMD）中执行： # 1. 克隆项目 git clone https://github.com/Huanshere/VideoLingo.git cd VideoLingo # 2. 安装依赖（需要 python=3.10 建议使用 conda) conda create -n videolingo python=3.</description>
    </item>
    
    <item>
      <title>视频下载工具分享之 yt-dlp</title>
      <link>https://blog.leanku.com/post/tools/%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB%E4%B9%8B-yt-dlp/</link>
      <pubDate>Fri, 10 Jan 2025 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/tools/%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB%E4%B9%8B-yt-dlp/</guid>
      <description>视频下载工具分享之 yt-dlp yt-dlp 是一个功能强大的开源命令行视频下载工具，它本身不需要像常规软件那样运行安装程序。
一、安装方式： 1. Windows 用户（最简单方法） 下载 exe 文件：前往 yt-dlp GitHub 释放页，找到并下载 yt-dlp.exe。
创建文件夹：建议在 C 盘或 D 盘根目录创建一个文件夹（如 D:\ytdlp），将下载好的 .exe 放进去。
安装 FFmpeg (重要依赖)：为了能下载高画质视频并自动合并音视频，你必须下载 FFmpeg。
在同一目录下放入 ffmpeg.exe。 添加到 PATH (可选但建议)：将该文件夹路径添加到系统的“环境变量”中，这样你就可以在任何地方的终端直接输入 yt-dlp 使用它了。
2. macOS 用户 推荐使用 Homebrew 快速安装：
打开终端（Terminal），输入： brew install yt-dlp ffmpeg 3. Linux 用户 大多数发行版可以直接通过包管理器安装：
Ubuntu/Debian: sudo apt install yt-dlp
Arch Linux: sudo pacman -S yt-dlp 或者直接下载二进制文件：
sudo wget https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -O /usr/local/bin/yt-dlp sudo chmod a+rx /usr/local/bin/yt-dlp 4.</description>
    </item>
    
    <item>
      <title>关于rabbitmq的一些问题</title>
      <link>https://blog.leanku.com/post/queue/%E5%85%B3%E4%BA%8Erabbitmq%E7%9A%84%E4%B8%80%E4%BA%9B%E9%97%AE%E9%A2%98/</link>
      <pubDate>Sun, 13 Oct 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/queue/%E5%85%B3%E4%BA%8Erabbitmq%E7%9A%84%E4%B8%80%E4%BA%9B%E9%97%AE%E9%A2%98/</guid>
      <description>关于rabbitmq的一些问题 一、RabbitMQ的完整工作流程 RabbitMQ 的核心是生产者将消息发送到交换机，交换机根据类型和路由键将消息路由到队列，消费者再从队列中获取消息。
核心组件：
Producer（生产者）： 发送消息的应用程序。
Consumer（消费者）： 接收消息的应用程序。
Message（消息）： 包含有效载荷（数据）和标签（元数据，如路由键）。
Exchange（交换机）： 接收生产者发送的消息，并根据特定规则（交换机类型、绑定、路由键）将消息路由到一个或多个队列。
Queue（队列）： 存储消息的缓冲区，等待消费者消费。
Binding（绑定）： 连接交换机和队列的规则。
完整流程：
建立连接：
生产者/消费者与 RabbitMQ Broker 建立一个 TCP 连接。
在连接上创建一个 Channel（信道），Channel 是轻量级的连接，避免了频繁创建/销毁 TCP 开开销。
生产者发送消息：
生产者将消息发送到指定的 Exchange。
发送消息时，必须指定一个 Routing Key（路由键）。
交换机路由消息：
Exchange 接收到消息后，根据自身的 类型 和 Binding 规则，决定将消息投递到哪些队列。
主要的交换机类型：
Direct： 精确匹配 Routing Key。消息只会被投递到 Binding Key 与 Routing Key 完全一致 的队列。
Fanout： 广播模式。将消息投递到所有绑定到该 Exchange 的队列，忽略 Routing Key。
Topic： 模式匹配。使用通配符（* 匹配一个词，# 匹配零个或多个词）来匹配 Routing Key 和 Binding Key。</description>
    </item>
    
    <item>
      <title>Ollama</title>
      <link>https://blog.leanku.com/post/ai/ollama%E6%9C%AC%E5%9C%B0%E9%83%A8%E7%BD%B2/</link>
      <pubDate>Sun, 01 Sep 2024 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/ai/ollama%E6%9C%AC%E5%9C%B0%E9%83%A8%E7%BD%B2/</guid>
      <description>Ollama 简介 介绍 Ollama 是一个开源的大型语言模型（LLM）平台，旨在让用户能够轻松地在本地运行、管理和与大型语言模型进行交互。 Ollama 提供了一个简单的方式来加载和使用各种预训练的语言模型，支持文本生成、翻译、代码编写、问答等多种自然语言处理任务。 Ollama 的特点在于它不仅仅提供了现成的模型和工具集，还提供了方便的界面和 API，使得从文本生成、对话系统到语义分析等任务都能快速实现 安装要求 Ollama 支持多种操作系统，包括 macOS、Windows、Linux 以及通过 Docker 容器运行。 CPU：多核处理器（推荐 4 核或以上） GPU：如果你计划运行大型模型或进行微调，推荐使用具有较高计算能力的 GPU（如 NVIDIA 的 CUDA 支持） 内存：至少 8GB RAM，运行较大模型时推荐 16GB 或更高。 存储：需要足够的硬盘空间来存储预训练模型，通常需要 10GB 至数百 GB 的空间，具体取决于模型的大小。 软件要求：确保系统上安装了最新版本的 Python（如果打算使用 Python SDK）。 下载安装ollama https://ollama.com/download 下载 下载完成后进行安装 运行模型 https://ollama.com/search 查找模型 下载模型 如 ollama run deepseek-r1 使用docker安装UI页面 docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v D:\open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main 进入UI页面，注册本地账号，开始使用
访问 http://localhost:3000/ Ollama API 可参考文档</description>
    </item>
    
    <item>
      <title>关于分布式</title>
      <link>https://blog.leanku.com/post/microservice/%E5%85%B3%E4%BA%8E%E5%88%86%E5%B8%83%E5%BC%8F/</link>
      <pubDate>Tue, 11 Jun 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/microservice/%E5%85%B3%E4%BA%8E%E5%88%86%E5%B8%83%E5%BC%8F/</guid>
      <description>关于分布式 一、什么是分布式？ 一个系统，各组件分别部署在不同服务器。彼此通过网络通信和协调的系统。
可以指多个不同组件分布在网络上互相协作 也可以一个组件的多个副本组成集群，互相协作如同一个组件，比如数据存储服务中心为了数据不丢失而采取的多个服务备份冗余 分布式最早出现的目的首先是解决单点问题，避免单点故障，然后解决了性能问题 二、分布式和微服务的区别？ 微服务并不一定是分布式系统（微服务中多个服务不一定部署在不同服务器，单机部署情况则不算是分布式） 分布式一定不是微服务 （分布式祖耀侧重服务的部署方式，微服务则是针对应用的一种服务拆分的架构） 三、分布式CAP原则 在设计一个分布式项目的时候会遇到三个特性：
一致性（Consistency）：所有节点数据实时同步，读取始终返回最新值 可用性（Availability）：每个请求必须得到响应（无论数据是否最新），高可用 分区容错（Partition Tolerance）：分布式最基本也是必需要有的特性，系统在遇到某个节点或网络分区故障时，仍然能够对外提供服务 三者无法同时满足，最多只能实现其中两个，网络分区发生时，必须牺牲C或A
‌CP（牺牲可用性）‌：如ZooKeeper，确保数据强一致性但可能拒绝请求 ‌AP（牺牲一致性）‌：如Eureka，保证服务可用但允许数据短暂不一致 三、 BASE理论 BASE理论是分布式系统设计原则，BASE 是指基本可用（Basically Available）、软状态（ Soft State）、最终一致性（ Eventual Consistency），核心思想是即使无法做到强一致性（CAP 的一致性就是强一致性），但应用可以采用适合的方式达到最终一致性。
基本可用（Basically Available）：分布式系统，在出现故障的时候，允许损失部分可用性。类似服务降级 软状态（Soft State）：允许系统存在中间状态，而该中间状态不会影响系统整体可用性。这里的中间状态就是 CAP 理论中的数据不一致。 最终一致性（Eventual Consistency）：系统中的所有数据副本经过一定时间后，最终能够达到一致的状态。 四、分布式事务及解决方案 分布式事务 本地事务依赖数据库本身提供的事务特性来实现， 但是在分布式环境下，可能会出现需要远程调用，比如：
begin transaction； //1.本地数据库操作：张三减少金额 //2.远程调用：让李四增加金额 commit transation; 张三和李四的账户不在一个数据库中甚至不在一个应用系统里，实现转账事务需要通过远程调用，由于网络问题就会导致分布式事务问题。
分布式事务解决方案 2PC
2PC 即两阶段提交协议，是将整个事务流程分为两个阶段，准备阶段（Prepare phase）、提交阶段（commit phase），2 是指两个阶段，P 是指准备阶段，C 是指提交阶段。偏向数据库
TCC TCC 是 Try、Conﬁrm、Cancel 三个词语的缩写，TCC 要求每个分支事务实现三个操作：预处理 Try、确认 Conﬁrm、撤销 Cancel。Try 操作做业务检查及资源预留，Conﬁrm 做业务确认操作，Cancel 实现一个与 Try 相反的操作即回滚操作。TM 首先发起所有的分支事务的 Try 操作，任何一个分支事务的Try操作执行失败，TM 将会发起所有分支事务的 Cancel 操作，若 Try 操作全部成功，TM 将会发起所有分支事务的 Conﬁrm 操作，其中 Conﬁrm/Cancel 操作若执行失败，TM 会进行重试。偏向代码</description>
    </item>
    
    <item>
      <title>Mysql 简易安装</title>
      <link>https://blog.leanku.com/post/database/mysql-%E7%AE%80%E6%98%93%E5%AE%89%E8%A3%85/</link>
      <pubDate>Sat, 11 May 2024 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql-%E7%AE%80%E6%98%93%E5%AE%89%E8%A3%85/</guid>
      <description>Mysql 简易安装 安装Mysql8.0(centos8为例)， 可参考 MySQL官方文档 # CentOS el8下载 MySQL YUM 仓库（替换为最新版本） wget https://dev.mysql.com/get/mysql80-community-release-el8-6.noarch.rpm # el9 使用sudo yum install mysql84-community-release-el9-x86_64.noarch.rpm sudo rpm -Uvh mysql80-community-release-el*.rpm sudo yum makecache # 安装 MySQL 社区版服务器 # el9 的话sudo yum install mysql84-community-release-el9-x86_64.noarch.rpm sudo yum install -y mysql-community-server # 可以通过手动编辑/etc/yum.repos.d/mysql-community.repo文件来选择发布系列。 # **install时如果出现GPG 密钥问题** # sudo curl -o /etc/pki/rpm-gpg/RPM-GPG-KEY-mysql-2023 https://repo.mysql.com/RPM-GPG-KEY-mysql-2023 # sudo chmod 644 /etc/pki/rpm-gpg/RPM-GPG-KEY-mysql-2023 # sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-mysql-2023 # 重新执行 yum install -y mysql-community-server # 启动 MySQL 服务 sudo systemctl start mysqld sudo systemctl enable mysqld sudo systemctl status mysqld #MySQL 首次启动会生成一个临时 root 密码： sudo grep &amp;#39;temporary password&amp;#39; /var/log/mysqld.</description>
    </item>
    
    <item>
      <title>Mysql中的事务及隔离级别 </title>
      <link>https://blog.leanku.com/post/database/mysql%E4%B8%AD%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%8F%8A%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB-/</link>
      <pubDate>Tue, 23 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql%E4%B8%AD%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%8F%8A%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB-/</guid>
      <description>MySQL事务与隔离级别深度解析 一、 事务基础概念 1. 什么是事务 事务(Transaction)是数据库操作的最小工作单元，是作为单个逻辑工作单元执行的一系列操作。事务具有以下四个关键特性(ACID)：
原子性(Atomicity)：事务中的所有操作要么全部完成，要么全部不完成
一致性(Consistency)：事务执行前后，数据库从一个一致状态变到另一个一致状态
隔离性(Isolation)：多个事务并发执行时，一个事务的执行不应影响其他事务
持久性(Durability)：事务一旦提交，其结果就是永久性的
2. MySQL中的事务控制语句 START TRANSACTION; -- 或 BEGIN -- 执行SQL操作 COMMIT; -- 提交事务 ROLLBACK; -- 回滚事务 二、事务隔离级别详解 1. 四种标准隔离级别 MySQL支持四种事务隔离级别，控制不同事务之间的可见性：
隔离级别 脏读 不可重复读 幻读 说明 READ UNCOMMITTED（读未提交） 可能 可能 可能 最低隔离级别 READ COMMITTED（读已提交） 不可能 可能 可能 大多数数据库默认级别 REPEATABLE READ（可重复读） 不可能 不可能 可能 MySQL默认级别 SERIALIZABLE（序列化） 不可能 不可能 不可能 最高隔离级别 2. 并发问题说明 脏读(Dirty Read)：读取到其他事务未提交的数据
不可重复读(Non-repeatable Read)：同一事务内多次读取同一数据结果不同
幻读(Phantom Read)：同一事务内多次查询返回不同的行集合
3. 隔离级别设置与查看 -- 设置当前会话隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 设置全局隔离级别 SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- 查看当前隔离级别 SELECT @@transaction_isolation; 三、各隔离级别实现机制 1.</description>
    </item>
    
    <item>
      <title>Mysql中的回表</title>
      <link>https://blog.leanku.com/post/database/mysql%E4%B8%AD%E7%9A%84%E5%9B%9E%E8%A1%A8/</link>
      <pubDate>Tue, 23 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql%E4%B8%AD%E7%9A%84%E5%9B%9E%E8%A1%A8/</guid>
      <description>MYSQL中的回（Back to Table）表说明 一、 基本概念 回表是指当使用非聚簇索引（二级索引）进行查询时，首先在索引中查找到所需数据的主键值，然后再根据这个主键值回到主键索引（聚簇索引）中查找完整数据行的过程。
二、核心原理 聚簇索引 vs 非聚簇索引 -- 创建测试表 CREATE TABLE user_info ( id INT PRIMARY KEY, -- 主键，聚簇索引 name VARCHAR(50), email VARCHAR(100), age INT, created_at DATETIME, INDEX idx_email (email), -- 非聚簇索引（二级索引） INDEX idx_name_age (name, age) -- 复合非聚簇索引 ); 索引结构对比 聚簇索引（主键索引）结构： 索引节点 -&amp;gt; 叶子节点包含完整数据行 [id:1] -&amp;gt; [id:1, name:&amp;#39;张三&amp;#39;, email:&amp;#39;zhang@xx.com&amp;#39;, age:25, ...] [id:2] -&amp;gt; [id:2, name:&amp;#39;李四&amp;#39;, email:&amp;#39;li@xx.com&amp;#39;, age:30, ...] 非聚簇索引（二级索引）结构： 索引节点 -&amp;gt; 叶子节点只包含索引列 + 主键值 [email:&amp;#39;li@xx.com&amp;#39;] -&amp;gt; [主键id:2] [email:&amp;#39;zhang@xx.</description>
    </item>
    
    <item>
      <title>Mysql中的锁</title>
      <link>https://blog.leanku.com/post/database/mysql%E4%B8%AD%E7%9A%84%E9%94%81/</link>
      <pubDate>Tue, 23 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql%E4%B8%AD%E7%9A%84%E9%94%81/</guid>
      <description>MYSQL中的锁 一、 MySQL锁概述 MySQL锁机制是数据库管理系统实现并发控制的核心技术，它通过在共享资源上实施访问限制，确保数据的一致性和完整性。作为PHP高级开发者，深入理解MySQL锁机制对于构建高性能、高并发的Web应用至关重要。
二、 MySQL锁分类体系 1. 按锁的粒度划分 1. 表级锁 特点
开销小，加锁快 锁定整个表 并发度低 使用场景 -- 显式加表锁 LOCK TABLES users READ; -- 共享锁 LOCK TABLES users WRITE; -- 排他锁 -- 操作完成后释放 UNLOCK TABLES; 注意事项：
MyISAM引擎默认使用表锁 在InnoDB上应谨慎使用，会严重影响并发 2. 行级锁 特点
开销大，加锁慢 只锁定需要的行 并发度高 使用场景 -- 共享锁(S锁) SELECT * FROM accounts WHERE id = 1 LOCK IN SHARE MODE; -- MySQL 8.0+推荐语法 SELECT * FROM accounts WHERE id = 1 FOR SHARE; -- 排他锁(X锁) SELECT * FROM accounts WHERE id = 1 FOR UPDATE; 注意事项：</description>
    </item>
    
    <item>
      <title>MySQL分库分表（无中间件）</title>
      <link>https://blog.leanku.com/post/database/mysql-%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8%E6%97%A0%E4%B8%AD%E9%97%B4%E4%BB%B6/</link>
      <pubDate>Tue, 23 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql-%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8%E6%97%A0%E4%B8%AD%E9%97%B4%E4%BB%B6/</guid>
      <description>MySQL分库分表（无中间件） 一、 分库分表方案设计 1. 垂直拆分 (按业务模块) -- 原始单体数据库 CREATE DATABASE ecommerce; USE ecommerce; -- 垂直拆分后的数据库 -- 用户库 CREATE DATABASE user_center; USE user_center; CREATE TABLE users ( user_id BIGINT PRIMARY KEY, username VARCHAR(50) UNIQUE, email VARCHAR(100) UNIQUE, password VARCHAR(100), mobile VARCHAR(20), status TINYINT DEFAULT 1, created_at DATETIME, updated_at DATETIME ); CREATE TABLE user_profiles ( user_id BIGINT PRIMARY KEY, real_name VARCHAR(50), avatar VARCHAR(200), gender TINYINT, birthday DATE, bio TEXT ); CREATE TABLE user_address ( address_id BIGINT PRIMARY KEY, user_id BIGINT, province VARCHAR(50), city VARCHAR(50), district VARCHAR(50), detail VARCHAR(200), is_default TINYINT DEFAULT 0, INDEX idx_user_id (user_id) ); -- 订单库 CREATE DATABASE order_center; USE order_center; CREATE TABLE orders ( order_id BIGINT PRIMARY KEY, user_id BIGINT, total_amount DECIMAL(10,2), status TINYINT, payment_status TINYINT, created_at DATETIME, paid_at DATETIME ); CREATE TABLE order_items ( item_id BIGINT PRIMARY KEY, order_id BIGINT, product_id BIGINT, product_name VARCHAR(100), price DECIMAL(10,2), quantity INT, INDEX idx_order_id (order_id) ); -- 商品库 CREATE DATABASE product_center; USE product_center; CREATE TABLE products ( product_id BIGINT PRIMARY KEY, name VARCHAR(100), category_id INT, price DECIMAL(10,2), stock INT, status TINYINT, created_at DATETIME ); CREATE TABLE categories ( category_id INT PRIMARY KEY, name VARCHAR(50), parent_id INT ); 2.</description>
    </item>
    
    <item>
      <title>MySQL索引类型</title>
      <link>https://blog.leanku.com/post/database/mysql%E7%B4%A2%E5%BC%95%E7%B1%BB%E5%9E%8B/</link>
      <pubDate>Tue, 23 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql%E7%B4%A2%E5%BC%95%E7%B1%BB%E5%9E%8B/</guid>
      <description>MySQL索引类型 索引是帮助MySQL高效获取数据的数据结构，类似于书籍的目录，可以大大加快查询速度。
一、索引类型 1. B-Tree 索引（最常用） 特点 默认的索引类型 适用于全键值、键值范围或键值前缀查找 支持排序和分组 创建语法 -- 单列索引 CREATE INDEX idx_name ON table_name(column_name); -- 多列复合索引 CREATE INDEX idx_name ON table_name(col1, col2, col3); -- 创建表时指定 CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(50), email VARCHAR(100), age INT, INDEX idx_name (name), INDEX idx_email_age (email, age) ); 适用查询类型 -- 全值匹配 SELECT * FROM users WHERE name = &amp;#39;John&amp;#39;; -- 前缀匹配（最左前缀） SELECT * FROM users WHERE name LIKE &amp;#39;Joh%&amp;#39;; -- 范围查询 SELECT * FROM users WHERE age BETWEEN 20 AND 30; -- 精确匹配左列 + 范围匹配右列 SELECT * FROM users WHERE email = &amp;#39;john@example.</description>
    </item>
    
    <item>
      <title>rabbitmq工作原理</title>
      <link>https://blog.leanku.com/post/queue/rabbitmq%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86/</link>
      <pubDate>Tue, 23 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/queue/rabbitmq%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86/</guid>
      <description>rabbitmq工作原理 AMQP协议 AMQP是一个提供统一消息服务的应用层标准协议，基于此协议的客户端与消息中间件可传递消息，并不受客户端/中间件不同产品，不同开发语言等条件的限制。 AMQP协议是一种二进制协议，提供客户端应用与消息中间件之间异步、安全、高效地交互。 AMQP作为中间层服务，把消息生产和消费分割出来，当消息生产者出现异常，不影响消费者对消息的消费，当消费者异常时，生产者生产的消息可以存放到服务的内存或者磁盘，不以影响到消息的消费，同时，消息也可以基于路由的规则可以投递到指定的消费者消费。 AMQP基于模块化通过Exchange和Message Queue两个组件组合实现消息路由分发 生产者和消费者 生产者是生产消息的主体，消费者是消费消息的主体 数据集成与系统解耦、异步处理与事件驱动、流量削峰、事务消息与分布式事务的最终一致等 生产者生产一条消息丢给消息代理，消息代理根据投递规则将消息传送到消费者手上 交换机 交换机就像是消息代理的路由器，负责拿到一个消息之后，根据确定的规则（路由键）将他路由给一个或零个队列、交换机具备多种路由模式。 基于消息生产者和路由规则可以将消息投递到指定的Message Queue，交换机收到生产者投递的消息，基于路由规则及队列绑定关系匹配到投递对应的交换机或者队列进行分发，交换机不存储消息，只做转发 直连交换机：根据路由键完全匹配的投递到对应的队列。 扇形交换机：无视路由键，将消息进行拷贝，并路由到给绑定到它身上的所有队列，提供了一个广播的效果 主题交换机： 根据路由键按模式匹配的投递到对应的队列 交换机也具备自己的属性，可以定义自己的名字，是否持久化等选项 队列 消息的暂存地，至少有一个消费者订阅了队列的话，消息会立即发送给这些订阅的消费者。但是如果消息到达了无人的订阅队列，消息会在队列中等待，等待有了消费者便进行分发 Exchange和Message Queue之间存在绑定关系，消息到了Exchange后基于路由策略可以将消息投递到已绑定且符合路由策略的Message Queue。 消息队列会将消息存储到内存或者磁盘中，并将这些消息按照一定顺序转发给一个或多个消费者，每个消息队列都是独立隔离的，相互不影响。 消息队列具有不同的属性：私有，共享，持久化，临时，客户端定义或者服务端定义等，可以基于实际需求选择对应的类型 消息 消息是信息的载体，也是MAQP协议的一个实体，消息包含以下两部分 载荷：就是真正的信息，是你想要传输的任何内容，该部分内容对消息代理来说是透明的 元消息：包含路由键、内容类型、编码、是否持久化等等消息属性，会被消息代理所解析，消息代理根据消息的属性对这条消息进行投递，存储等。这部分被消息代理所关心，而消费者对其是不关心的 信道 网络信道，是建立在Connection连接之上的一种轻量级的连接。几乎所有的操作都在Chanel中进行，Channel是进行消息读写的通道，客户端可以建立对各Channel，每个Channel代表一个会话任务 如果把Connection比作一条光纤电缆的话，那么Channel信道就比作成光纤电缆中的其中一束光纤。一个Connection上可以创建任意数量的Channel。 大部分的业务操作是在Channel这个接口中完成的 队列声明 queueDeclare 交换机的声明 ExchangeDeclare 队列的绑定 queueBind 发布消息 basicPublish 消费消息 basicConsume Rabbitmq 工作模式 一、简单模式
生产者发送消息到队列，消费者进行消费，没有交换机 二、工作模式 一个生产者发送消息到队列中，队列分配消息给不同的队列，队列接收到消息进行消费
三、订阅模式 每个队列的消息都是一样的，生产者把消息发送给交换机，交换机把消息发送给消息绑定的队列，让消费者消费
四、路由模式 根据路由键发送到不同的消息队列中
五、主题模式 根据路由键分类，发送到不同的消息队列中</description>
    </item>
    
    <item>
      <title>RabbitMQ详解</title>
      <link>https://blog.leanku.com/post/queue/rabbitmq%E8%AF%A6%E8%A7%A3/</link>
      <pubDate>Tue, 23 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/queue/rabbitmq%E8%AF%A6%E8%A7%A3/</guid>
      <description>RabbitMQ详解 1. 五种工作模式 1.1 简单模式 生产者p发送消息到队列，消费者c消费消息。（无交换机消息直接进入队列）
p-&amp;gt;queue-&amp;gt;c 1.2 工作模式 一个生产者p发送消息到队列，队列将消息分配给多个消费者c1,c2。（实现负载均衡，适合集群异步处理，典型场景：发送邮件、短信等） p-&amp;gt;queue|-&amp;gt;c1 |-&amp;gt;c2
1.3 订阅模式，每个队列的消息都是一样的 使用广播类型的交换机e, 生产者p把消息发送到交换机e，交换机e把消息发送到和交换机绑定的队列c4、c5(每个消费者接收相同的消息。典型应用场景：天气订阅，微博订阅等)
|-&amp;gt;c4 p-&amp;gt;e-&amp;gt;| |-&amp;gt;c5 1.4 路由模式 使用Direct类型的交换机，生产者p发送消息到交换机e，交换机E根据路由键（如error发送到c1）匹配队列，消息仅发送到匹配的队列（与订阅模式的区别：按条件筛选发送）
|-&amp;gt;error-&amp;gt;c1 p-&amp;gt;e| |-&amp;gt;info-&amp;gt;c2 1.5 主题模式 使用Topic类型的交换机，路由模式的升级版，支持通配符匹配路由,匹配更灵活（#代表匹配一个或多个单词，*代表匹配一个）
|log.*-&amp;gt;c4 p-&amp;gt; | |log.#-&amp;gt;c5 2. 消息持久化 当RabbitMQ重启以后，未消费的消息可以在服务重启后继续消费，不会丢失。
3. 应答机制 ACK 两种方式
自动确认：消费者接收消息后，立即ACK然后再处理业务逻辑，加入业务逻辑出现异常，消息也会被确认 手动确认：消费者接收消息后，消息状态被设置为unack,由业务逻辑指定ACK的位置，假如没有手动ACK，则mq中的消息不会减少，会重复消费 4. 死信队列 DLX全程Dead-Letter-Exchange，也可以称为私信交换机，就是当一个队列中的消息变成死信以后，会被重新发送到另一个交换机，这个交换机就是DLX，而绑定DLX的队列就是死信队列。 变为死信的一般情况：
消息被拒绝 消息过期 队列达到最大长度 使用死信队列只需要定义队列的时候设置x-dead-letter-exchange参数指定交换机就可以了，x-message-ttl参数设置消息存活时间，x-dead-letter-routing-key参数设置路由键
5. 延时队列 延时队列就是当消息发送以后，并不想让消费者立即拿到消费，而是等待特定时间之后才能拿到消息来消费。
延时功能可以通过设置过期时间+死信队列来实现
6. 集群模式 允许消费者和生产者在RabbitMQ节点崩溃的情况下继续运行 允许通过添加更多的节点来扩展消息通信的吞吐量 RabbitMQ会始终记录以下四种类型的内部元数据 队列元数据-队列的名称和他们的属性（是否持久化，是否自动删除） 交换器元数据-交换器的类型、名称和属性 绑定元数据-一张简单的表格展示了如何将消息路由到队列 v-host元数据-为vhost内的队列、交换器和绑定提供命名空间和安全属性 RabbitMQ集群的3个模式
主备模式：从节点相当于主节点的链接，所有从节点收到的请求，真实转向的都是从节点。一般在并发和数据不是特别多的情况下使用，当从节点挂掉后会从备份节点中选择一个节点出来作主节点对外提供服务。 镜像模式：将需要消费的队列变为镜像队列，存在于多个节点，这样就可以实现RabbitMQ的HA高可用。作用就是消息实体会主动在镜像节点之间实现同步，任何一个节点宕机都没关系，保证100%数据不丢失，在实际工作中用的最多的。并且实现集群非常的简单，一般物联网大厂都会构建这种镜像集群模式。 异地多活模式：用来实现异地的数据复制，使用多活模式需要借助federation插件来实现集群间或节点间的消息复制，广泛应用于众多互联网公司 7. 负载均衡 HAProxy是一个使用C语言编写的自由及开放源代码软件，其提供高可用性、负载均衡、以及基于TCP和HTTP的应用程序代理 特别适用于那些负载特大的web站点，完全可以支持数以万计的并发连接，同时可以保护web服务器不被暴露到网络上 </description>
    </item>
    
    <item>
      <title>Redis分布式锁</title>
      <link>https://blog.leanku.com/post/redis/redis%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/</link>
      <pubDate>Tue, 23 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/redis/redis%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/</guid>
      <description>Redis分布式锁 一、 Redis锁基础概念 1. 为什么需要Redis锁 Redis锁是一种基于内存数据库Redis实现的分布式锁机制，主要解决分布式系统中的资源竞争问题。相比数据库锁，Redis锁具有以下优势
高性能：基于内存操作，响应速度快 原子性保证：Redis单线程模型天然支持原子操作 分布式支持：可跨多台服务器使用 丰富的数据结构：支持多种锁实现方式 2. 基本实现原理 最简单的Redis锁实现方式：
SET resource_name my_random_value NX PX 30000 NX：仅当key不存在时设置 PX：设置过期时间(毫秒) my_random_value：唯一标识，用于安全释放锁 二、Redis锁的实现方式 1. SETNX实现（基本方式） 实现步骤：
尝试获取锁：SETNX lock_key 1 获取成功则设置过期时间：EXPIRE lock_key 30 执行业务逻辑 释放锁：DEL lock_key 问题： 非原子操作，SETNX和EXPIRE之间可能崩溃导致死锁
2. SET扩展参数实现（推荐） Redis 2.6.12+版本支持扩展参数，可原子性完成设置
SET lock_key unique_value NX PX 30000 PHP实现示例：
$redis = new Redis(); $redis-&amp;gt;connect(&amp;#39;127.0.0.1&amp;#39;, 6379); $lockKey = &amp;#39;order_lock_123&amp;#39;; $uniqueId = uniqid(); $expire = 30000; // 30秒 // 尝试获取锁 $acquired = $redis-&amp;gt;set($lockKey, $uniqueId, [&amp;#39;NX&amp;#39;, &amp;#39;PX&amp;#39; =&amp;gt; $expire]); if ($acquired) { try { // 执行业务逻辑 processOrder(); } finally { // 使用Lua脚本保证原子性释放 $script = &amp;#34; if redis.</description>
    </item>
    
    <item>
      <title>Redis高可用</title>
      <link>https://blog.leanku.com/post/redis/redis%E9%AB%98%E5%8F%AF%E7%94%A8/</link>
      <pubDate>Tue, 23 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/redis/redis%E9%AB%98%E5%8F%AF%E7%94%A8/</guid>
      <description>Redis高可用 1. 事务机制和IO多路复用 1.1 事务 1.1.1 事务特点 事务提交前，先检查命令语法是否正确 提交后的命令一定会执行 有命令报错，也会执行完 不能回滚 1.1.2 命令 multi，告诉Redis服务器开启一个事务。只是开启而不是执行。 exec, 告诉Redis开始执行事务 discard，告诉Redis取消事务 watch，监视某一个键值对，它的作用是在事务执行之前如果监视的键值被修改，事务会被取消 1.2 IO多路复用 redis 是单线程，单线程只能在一个CPU内核上执行，假如是4核的，只会占用一个，其它三个不参与。 worker线程串行 read读-&amp;gt;计算-&amp;gt;write返回
在Redis6.0加入了io-threads， 主线程worker只进行计算，并行读取
io-threads 4
io-threads-do-reads yes
2. 持久化和过期淘汰策略 2.1 持久化 Redis是存储在内存中的， 服务器重启数据会丢失。持久化方案可以保存数据到磁盘文件，可以恢复到内存中。Redis提供的持久化方案有：
rdb：生成某一时刻的快照，保存到二进制文件中 优点： 容灾性好，方便备份 性能最大化，fork出一个子进程来操作，对主进程没有影响 数据较多时，相对于aof启动效率更高 缺点： 会造成数据丢失 aof：实时记录每一条写命令，追加到文件中，打开可以看到具体的操作记录 同步策略：appendfsync everysec(默认),每秒同步一次 always，每次操作后都要同步一次 no,由操作系统调度进行同步 重写策略： 手动触发，执行bgrewiteaof命令 自动触发：auto-rewrite-percentage 100, auto-rewrite-min-size 64mb 优点 数据安全，不会造成数据的丢失 缺点 比rdb重启效率低；运行效率比rdb低 混合模式：上面两种方式的结合 触发方式有两种：
手动触发： save命令，会让Redis处于阻塞的状态，直到rdb持久化完成，线上环境谨慎使用 bgsave命令,它会fork出一个子进程（有短暂阻塞），用来执行持久化，主进程继续响应客户端请求 自动触发： 配置文件修改（save n m），在n秒内,有m个key发生变化就会触发，执行命令最总执行的是bgsave 2.2 过期键删除策略 Redis设置key时，都会设置一个过期时间，Redis同时使用了两种过期删除策略，惰性过期和定时过期</description>
    </item>
    
    <item>
      <title>分布式session</title>
      <link>https://blog.leanku.com/post/%E5%88%86%E5%B8%83%E5%BC%8Fsession/</link>
      <pubDate>Sun, 21 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/%E5%88%86%E5%B8%83%E5%BC%8Fsession/</guid>
      <description>分布式session 在单体服务器的年代，Session 直接保存在服务器中，是没有问题的，而且实现起来很容易。
但是随着分布式架构的流行，单个服务器已经不能满足系统的需要了，通常都会把系统部署在多台服务器上，通过负载均衡把请求分发到其中的一台服务器上；
那么很有可能第一次请求访问的 A 服务器，创建了 Session ，但是第二次访问到了 B 服务器，这时就会出现取不到 Session 的情况；
于是，分布式架构中，Session 共享就成了一个很大的问题。
解决方案 1. session同步
思路：多个web-server之间相互同步session，这样每个web-server之间都包含全部的session 优点：web-server支持的功能，应用程序不需要修改代码 不足： 1.session的同步需要数据传输，占内网带宽，有时延。 2.所有web-server都包含所有session数据，数据量受内存限制，无法水平扩展。 3.主从架构固有的保证一致性会牺牲可用性的特定，但进行主从同步时，登陆的请求将被阻塞，显然不符合用户实际需求。 2. 客户端存储法
思路：服务端存储所有用户的session，内存占用较大，可以将session存储到浏览器cookie中 优点：服务端不需要存储 缺点： 1.每次http请求都携带session，占外网带宽 2.数据存储在端上，并在网络传输，存在泄漏、篡改、窃取等安全隐患 3.session存储的数据大小受cookie限制 “端存储”的方案虽然不常用，但确实是一种思路。 3. 反向代理hash一致性
思路：使用 Nginx （或其他复杂均衡软硬件）中的 IP 绑定策略，同一个 IP 只能在指定的同一个机器访问，但是这样做失去了负载均衡的意义，当挂掉一台服务器的时候，会影响一批用户的使用，风险很大； 反向代理层做逻辑处理 方案一：ip进行hash 反向代理层使用用户ip来做hash，以保证同一个ip的请求落在同一个web-server上. 方案二：含有业务属性的字段hash 反向代理使用http协议中的某些业务属性来做hash，例如sid，city_id，user_id等，能够更加灵活的实施hash策略，以保证同一个浏览器用户的请求落在同一个web-server（即不同的user_id对应不同的web-server）. 总结：让专业的软件做专业的事情，反向代理就负责转发，尽量不要引入应用层业务属性，除非不得不这么做（例如，有时候多机房多活需要按照业务属性路由到不同机房的web-server）。 4. 后端统一集中存储（主流方案）
思路：将session存储在web-server后端的存储层，数据库或者缓存 优点： 1.没有安全隐患 2.可以水平扩展，数据库/缓存水平切分即可，可以存储较多的session。 3.web-server重启或者扩容都不会有session丢失 不足：增加了一次网络调用，并且需要修改应用代码。 对于db存储还是cache，个人推荐后者：session读取的频率会很高，数据库压力会比较大。 如果有session高可用需求，cache可以做高可用，但大部分情况下session可以丢失，一般也不需要考虑高可用。 </description>
    </item>
    
    <item>
      <title>NGINX负载均衡</title>
      <link>https://blog.leanku.com/post/nginx%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/</link>
      <pubDate>Sat, 20 Apr 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/nginx%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/</guid>
      <description>NGINX负载均衡 Nginx是一个强大的开源Web服务器和反向代理服务器，它支持正向代理和反向代理功能。 正向代理 正向代理是客户端访问代理服务器去访问目标服务器，并且对目标服务器隐藏了客户端的真实信息（IP等信息）
正向代理的主要用途包括：
访问被限制的资源：当某些资源受到网络限制或访问限制时，可以使用正向代理绕过这些限制来获取资源。 提高访问速度：代理服务器可以缓存经常请求的资源，从而提高客户端访问资源的速度。 突破防火墙：正向代理可以帮助绕过企业或国家防火墙的限制，访问被封锁的网站或资源。 反向代理 反向代理是指代理服务器接收客户端的请求，然后反向代理将客户端的请求分发给一个或多个目标服务器，最后将响应返回给客户端，对于客户端隐藏了真实的服务端信息
反向代理的主要用途包括：
负载均衡：反向代理可以根据一定的算法将请求均匀地分发给后端的多台服务器，从而实现负载均衡，提高系统的并发处理能力和稳定性。 缓存静态资源：反向代理可以缓存经常请求的静态资源，减少后端服务器的负载，提高网站的访问速度。 安全性和可靠性：反向代理可以作为防火墙和安全设备，提供安全认证、访问控制、DDoS攻击防护等功能。 Nginx配置文件 #user nobody; 是用来指定 Nginx 进程运行的用户和用户组的配置项。 在 Linux 系统中，各个进程需要以某个用户的身份来运行，以限制权限并提高安全性 worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 8080; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } 第一部分 全局块worker_processes:</description>
    </item>
    
    <item>
      <title>Redis主从复制</title>
      <link>https://blog.leanku.com/post/redis/redis%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/</link>
      <pubDate>Wed, 20 Mar 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/redis/redis%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/</guid>
      <description>Redis主从复制 一、什么是Redis主从复制 1. 从复制的架构： Redis Replication是一种 master-slave 模式的复制机制，这种机制使得 slave 节点可以成为与 master 节点完全相同的副本，可以采用一主多从或者级联结构。
主从复制的配置要点：
配从库不配主，从库配置：slaveof 主库IP 主库端口 查看redis的配置信息：info replication 2. Redis为什么需要主从复制？ 使用Redis主从复制的原因主要是单台Redis节点存在以下的局限性：
Redis虽然读写的速度都很快，单节点的Redis能够支撑QPS大概在5w左右，如果上千万的用户访问，Redis就承载不了，成为了高并发的瓶颈。 单节点的Redis不能保证高可用，当Redis因为某些原因意外宕机时，会导致缓存不可用 CPU的利用率上，单台Redis实例只能利用单个核心，这单个核心在面临海量数据的存取和管理工作时压力会非常大。 3. 主从复制的好处： 数据冗余：主从复制实现了数据的热备份，是持久化之外的一种数据冗余方式。 故障恢复：如果master宕掉了，使用哨兵模式，可以提升一个 slave 作为新的 master，进而实现故障转移，实现高可用 负载均衡：可以轻易地实现横向扩展，实现读写分离，一个 master 用于写，多个 slave 用于分摊读的压力，从而实现高并发； 4. 主从复制的缺点： 由于所有的写操作都是先在Master上操作，然后同步更新到Slave上，所以从Master同步到Slave服务器有一定的延迟，当系统很繁忙的时候，延迟问题会更加严重，Slave机器数量的增加也会使这个问题更加严重
二、主从复制的原理 从总体上来说，Redis主从复制的策略就是：当主从服务器刚建立连接的时候，进行全量同步；全量复制结束后，进行增量复制。当然，如果有需要，slave 在任何时候都可以发起全量同步。
1、主从全量复制的流程： Redis全量复制一般发生在Slave初始化阶段，这时Slave需要将Master上的所有数据都复制一份，具体步骤如下：
slave服务器连接到master服务器，便开始进行数据同步，发送psync命令（Redis2.8之前是sync命令） master服务器收到psync命令之后，开始执行bgsave命令生成RDB快照文件并使用缓存区记录此后执行的所有写命令 如果master收到了多个slave并发连接请求，它只会进行一次持久化，而不是每个连接都执行一次，然后再把这一份持久化的数据发送给多个并发连接的slave。 如果RDB复制时间超过60秒（repl-timeout），那么slave服务器就会认为复制失败，可以适当调节大这个参数 master服务器bgsave执行完之后，就会向所有Slava服务器发送快照文件，并在发送期间继续在缓冲区内记录被执行的写命令 client-output-buffer-limit slave 256MB 64MB 60，如果在复制期间，内存缓冲区持续消耗超过64MB，或者一次性超过256MB，那么停止复制，复制失败 slave服务器收到RDB快照文件后，会将接收到的数据写入磁盘，然后清空所有旧数据，在从本地磁盘载入收到的快照到内存中，同时基于旧的数据版本对外提供服务。 master服务器发送完RDB快照文件之后，便开始向slave服务器发送缓冲区中的写命令 slave服务器完成对快照的载入，开始接收命令请求，并执行来自主服务器缓冲区的写命令； 如果slave node开启了AOF，那么会立即执行BGREWRITEAOF，重写AOF 2、增量复制： Redis的增量复制是指在初始化的全量复制并开始正常工作之后，master服务器将发生的写操作同步到slave服务器的过程，增量复制的过程主要是master服务器每执行一个写命令就会向slave服务器发送相同的写命令，slave服务器接收并执行收到的写命令。
3、断点续传： 什么是断点续传：
当master-slave网络连接断掉后，slave重新连接master时，会触发全量复制，但是从2.8版本开始，slave与master能够在网络连接断开重连后，只从中断处继续进行复制，而不必重新同步，这就是所谓的断点续传。
断电续传这个新特性使用psync命令，旧的实现中使用sync命令。Redis2.8版本可以检测出它所连接的服务器是否支持PSYNC命令，不支持的话使用SYNC命令。master服务器收到slave发送的psync命令后，会根据自身的情况做出对应的处理，可能是FULLRESYNC runid offset触发全量复制，也可能是CONTINUE触发增量复制 命令格式：psync runid offset 工作原理：</description>
    </item>
    
    <item>
      <title>Linux常用命令</title>
      <link>https://blog.leanku.com/post/linux%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/</link>
      <pubDate>Mon, 18 Mar 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/linux%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/</guid>
      <description>Linux基本简介 Linux 是一个基于Linux 内核的开源类Unix 操作系统，Linus Torvalds于 1991 年 9 月 17 日首次发布的操作系统内核。Linux 通常打包为Linux 发行版。 Linux文件系统 Linux一切皆文件 只有一个顶级目录，不像windows分C盘、D盘、E盘 Linux 含义 windows /bin 所有用户可用的基本命令存放的位置 windows没有固定的命令存放目录 /sbin 需要管理员权限才能使用的命令 /boot linux系统启动的时候需要加载和使用的文件 /dev 外设连接linux后，对应的文件存放的位置 类似Windows中的U盘，光盘的符号文件。 /etc 存放系统或者安装的程序的配置文件,注册服务等 类似windows中的注册表， /home 家目录，linux中每新建一个用户，会自动在home中为该用户分配一个文件夹 类似windows中的&amp;quot;我的文档&amp;quot;，每个用户有自己的目录。 /root root账户的家目录，仅供root账户使用 类似windows中的Administrator账户的&amp;quot;我的文档&amp;quot; /lib linux的命令和系统启动，需要使用一些公共的依赖，放在lib中，类似我们开发的代码执行需要引入的jdk的jar /usr 很多系统软件的默认安装路径 类似windows中的C盘下的Program Files目录。 /var 系统和程序运行产生的日志文件和缓存文件放在这里 Linux常用命令 命令格式 ：命令 [-选项] [参数]
例 ： ls -la /etc 文件管理 命令 解释 参数 示例 ls 列出目录的内容 -a 显示所有文件，包括隐藏文件; -l详细信息显示; -d 查看目录属性 ls -la cd 切换工作目录 cd .</description>
    </item>
    
    <item>
      <title>​MySQL优化常用方法</title>
      <link>https://blog.leanku.com/post/database/mysql%E4%BC%98%E5%8C%96%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95/</link>
      <pubDate>Sun, 17 Mar 2024 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql%E4%BC%98%E5%8C%96%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95/</guid>
      <description>​MySQL优化常用方法 1. EXPLAIN EXPLAIN 查看SQL执行计划
主要字段说明：
type列，连接类型。一个好的SQL语句至少要达到range级别。杜绝出现all级别。 key列，使用到的索引名。如果没有选择索引，值是NULL。可以采取强制索引方式。 key_len列，索引长度。 rows列，扫描行数。该值是个预估值。 extra列，详细说明。注意，常见的不太友好的值，如下：Using filesort，Using temporary。 2. SQL语句中IN包含的值不应过多 MySQL对于IN做了相应的优化，即将IN中的常量全部存储在一个数组里面，而且这个数组是排好序的。但是如果数值较多，产生的消耗也是比较大的。再例如：select id from t where num in(1,2,3) 对于连续的数值，能用between就不要用in了；再或者使用连接来替换。
3. SELECT语句务必指明字段名称 SELECT*增加很多不必要的消耗（CPU、IO、内存、网络带宽）；增加了使用覆盖索引的可能性；当表结构发生改变时，前断也需要更新。所以要求直接在select后面接上字段名。
4. 当只需要一条数据的时候，使用limit 1 这是为了使EXPLAIN中type列达到const类型
5. 如果排序字段没有用到索引，就尽量少排序 6. 如果限制条件中其他字段没有索引，尽量少用or or两边的字段中，如果有一个不是索引字段，而其他条件也不是索引字段，会造成该查询不走索引的情况。很多时候使用union all或者是union（必要的时候）的方式来代替“or”会得到更好的效果。
7. 尽量用union all代替union nion和union all的差异主要是前者需要将结果集合并后再进行唯一性过滤操作，这就会涉及到排序，增加大量的CPU运算，加大资源消耗及延迟。当然，union all的前提条件是两个结果集没有重复数据。
8. 不使用ORDER BY RAND() select id from dynamic order by rand() limit 1000;
上面的SQL语句，可优化为：
select id from dynamic t1 join (select rand() * (select max(id) from dynamic) as nid) t2 on t1.</description>
    </item>
    
    <item>
      <title>PHP中的设计模式</title>
      <link>https://blog.leanku.com/post/php%E4%B8%AD%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/</link>
      <pubDate>Fri, 15 Mar 2024 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php%E4%B8%AD%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/</guid>
      <description>PHP中的设计模式 介绍 设计模式：提供了一种广泛的可重用的方式来解决我们日常编程中常常遇见的问题。设计模式并不一定就是一个类库或者第三方框架，它们更多的表现为一种思想并且广泛地应用在系统中。它们也表现为一种模式或者模板，可以在多个不同的场景下用于解决问题。设计模式可以用于加速开发，并且将很多大的想法或者设计以一种简单地方式实现。当然，虽然设计模式在开发中很有作用，但是千万要避免在不适当的场景误用它们。 分类 按照目的分，目前常见的设计模式主要有23种，根据使用目标的不同可以分为以下三大类： 创建设计模式（Creational Patterns）(5种)：用于创建对象时的设计模式。更具体一点，初始化对象流程的设计模式。当程序日益复杂时，需要更加灵活地创建对象，同时减少创建时的依赖。而创建设计模式就是解决此问题的一类设计模式。 单例模式【Singleton】 工厂模式【Factory】 抽象工厂模式【AbstractFactory】 建造者模式【Builder】 原型模式【Prototype】 结构设计模式（Structural Patterns）(7种)：用于继承和接口时的设计模式。结构设计模式用于新类的函数方法设计，减少不必要的类定义，减少代码的冗余。 适配器模式【Adapter】 桥接模式【Bridge】 合成模式【Composite】 装饰器模式【Decorator】 门面模式【Facade】 代理模式【Proxy】 享元模式【Flyweight】 行为模式（Behavioral Patterns）(11种)：用于方法实现以及对应算法的设计模式，同时也是最复杂的设计模式。行为设计模式不仅仅用于定义类的函数行为，同时也用于不同类之间的协议、通信。 策略模式【Strategy】 模板方法模式【TemplateMethod】 观察者模式【Observer】 迭代器模式【Iterator】 责任链模式【ResponsibilityChain】 命令模式【Command】 备忘录模式【Memento】 状态模式【State】 访问者模式【Visitor】 中介者模式【Mediator】 解释器模式【Interpreter】 按照范围分为：类的设计模式，以及对象设计模式 类的设计模式(Class patterns)：用于类的具体实现的设计模式。包含了如何设计和定义类，以及父类和子类的设计模式。
对象设计模式(Object patterns): 用于对象的设计模式。与类的设计模式不同，对象设计模式主要用于运行期对象的状态改变、动态行为变更等。
设计模式原则 设计模式六大原则
开放封闭原则：一个软件实体如类、模块和函数应该对扩展开放，对修改关闭。 里氏替换原则：所有引用基类的地方必须能透明地使用其子类的对象. 依赖倒置原则：高层模块不应该依赖低层模块，二者都应该依赖其抽象；抽象不应该依赖细节；细节应该依赖抽象。 单一职责原则：不要存在多于一个导致类变更的原因。通俗的说，即一个类只负责一项职责。 接口隔离原则：客户端不应该依赖它不需要的接口；一个类对另一个类的依赖应该建立在最小的接口上。 迪米特法则：一个对象应该对其他对象保持最少的了解。 设计模式实现 1. Singleton(单例模式) 单例模式是最常见的模式之一，在Web应用的开发中，常常用于允许在运行时为某个特定的类创建仅有一个可访问的实例。
&amp;lt;?php final class Mysql { /** * * @var self[该属性用来保存实例] */ private static $instance; /** * * @var mixed */ public $mix; /** * Return self instance[创建一个用来实例化对象的方法] * * @return self */ public static function getInstance() { if (!</description>
    </item>
    
    <item>
      <title>Redis持久化及过期删除策略</title>
      <link>https://blog.leanku.com/post/redis/redis%E6%8C%81%E4%B9%85%E5%8C%96%E5%8F%8A%E8%BF%87%E6%9C%9F%E5%88%A0%E9%99%A4%E7%AD%96%E7%95%A5/</link>
      <pubDate>Wed, 13 Mar 2024 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/redis/redis%E6%8C%81%E4%B9%85%E5%8C%96%E5%8F%8A%E8%BF%87%E6%9C%9F%E5%88%A0%E9%99%A4%E7%AD%96%E7%95%A5/</guid>
      <description>Redis持久化及过期删除策略 Redis 持久化之RDB和AOF RDB 详解 快照（snapshotting，RDB） RDB 是 Redis 默认的持久化方案。在指定的时间间隔内，执行指定次数的写操作，则会将内存中的数据写入到磁盘中。即在指定目录下生成一个dump.rdb文件。Redis 重启会通过加载dump.rdb文件恢复数据
从配置文件了解RDB 打开 redis.conf 文件，找到 SNAPSHOTTING 对应内容
RDB核心规则配置（重点）
save &amp;lt;seconds&amp;gt; &amp;lt;changes&amp;gt; #save &amp;#34;&amp;#34; save 900 1 save 300 10 save 60 10000 说明：save &amp;lt;指定时间间隔&amp;gt; &amp;lt;执行指定次数更新操作&amp;gt;，满足条件就将内存中的数据同步到硬盘中。官方出厂配置默认是 900秒内有1个更改，300秒内有10个更改以及60秒内有10000个更改，则将内存中的数据快照写入磁盘。 若不想用RDB方案，可以把 save “” 的注释打开，下面三个注释。
指定本地数据库文件名，一般采用默认的 dump.rdb dbfilename dump.rdb
指定本地数据库存放目录，一般也用默认配置 dir ./
默认开启数据压缩 rdbcompression yes
解说：配置存储至本地数据库时是否压缩数据，默认为yes。Redis采用LZF压缩方式，但占用了一点CPU的时间。若关闭该选项，但会导致数据库文件变的巨大。建议开启。
触发RDB快照
在指定的时间间隔内，执行指定次数的写操作 执行save（阻塞， 只管保存快照，其他的等待） 或者是bgsave （异步）命令 执行flushall 命令，清空数据库所有数据，意义不大。 执行shutdown 命令，保证服务器正常关闭且不丢失任何数据，意义…也不大。 注意： save备份过程：save备份是同步的，如果备份的数据量过大的话，服务器会暂停几百毫秒甚至是1秒
bgsave备份过程：bgsave备份会单独创建一个子进程，将备份的数据写入一个临时文件
RDB数据还原 找到备份临时文件的指令是 config get dir 指令执行成功以后将备份临时文件的目录拷贝到Redis的安装目录下 然后重新启动Redis服务就成功还原数据了</description>
    </item>
    
    <item>
      <title>Redis中的Lua</title>
      <link>https://blog.leanku.com/post/redis/redis%E4%B8%AD%E7%9A%84lua/</link>
      <pubDate>Tue, 12 Mar 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/redis/redis%E4%B8%AD%E7%9A%84lua/</guid>
      <description>Redis中的Lua 一. Redis中的Lua脚本的作用 Redis中的Lua脚本主要解决复杂操作的原子性和性能优化两大核心问题。它允许你在Redis服务器端直接执行自定义的逻辑，而不是把数据拉到客户端处理后再写回去。
核心作用 1. 保证原子性操作 Redis执行Lua脚本时，脚本中的所有命令会作为一个整体被执行，中间不会被其他命令插入。这完美解决了多命令组合操作时的并发安全问题。
经典场景： 实现分布式锁、库存扣减、限流计数器等。比如秒杀场景下，检查库存、扣减库存、记录订单这三个操作必须原子执行，用Lua脚本就能确保数据一致性。
2. 减少网络开销 将多个Redis命令合并到一个Lua脚本中，原本需要多次网络请求的操作变成一次请求完成。数据在Redis服务器本地处理，避免了大量数据在客户端和服务器之间来回传输。
3.扩展Redis指令集 你可以用Lua实现Redis原生不支持的复杂业务逻辑。比如自定义数据结构操作、复杂条件判断、循环处理等，让Redis变成一个具备计算能力的&amp;quot;小数据库&amp;quot;。
4. 提高代码复用率 脚本可以被缓存到Redis服务器，客户端通过SHA1摘要重复调用，无需每次都发送完整的脚本代码。多个应用可以共享同一套脚本逻辑
总结 Redis Lua脚本让你能把多个操作打包成一个原子性的、在服务器本地执行的任务，既保证了数据一致性，又提升了性能。特别适合秒杀、分布式锁、计数器、复杂条件更新等需要&amp;quot;读-改-写&amp;quot;原子操作的场景。
二、Lua安装 windows下载地址 ：https://luabinaries.sourceforge.net/
三 、 Lua在Redis中最常用、最经典的几个应用场景 1. 在Redis中操作Lua脚本的常用命令 命令 作用 一句话解释 EVAL 执行给定的Lua脚本 直接把脚本和参数传给Redis运行一次。 SCRIPT LOAD 将脚本缓存到Redis 把脚本存到Redis里，会返回一个SHA1值作为“脚本ID”。 EVALSHA 根据SHA1值执行缓存的脚本 拿着“脚本ID”去执行之前存好的脚本，省流量，效率更高。 SCRIPT EXISTS 检查脚本是否已缓存 看看某个“脚本ID”对应的脚本还在不在Redis里。 SCRIPT KILL 终止正在运行的脚本 如果脚本执行太久卡住了，可以用这个命令尝试杀掉它。 SCRIPT FLUSH 清空所有缓存的脚本 一键清除Redis里缓存的所有脚本，操作要小心\-1。 2. 五大经典应用场景 分布式锁 这是Lua脚本在Redis中最经典的应用。获取锁和释放锁的多个步骤必须是一个原子操作，否则会出现并发问题。 获取锁：使用 SET NX PX 命令，一步到位地尝试设置一个带过期时间的键，保证只有一个客户端能拿到锁-8。 释放锁：释放锁时，需要先检查当前持有锁的客户端是否就是自己（通过一个唯一值比如UUID判断），然后再删除锁。这两个动作必须通过Lua脚本一起执行，才能避免误删别人的锁-2-8。 -- 安全的释放锁脚本 -- KEYS[1]: 锁的名称 -- ARGV[1]: 客户端的唯一标识 if redis.</description>
    </item>
    
    <item>
      <title>Redis分布式</title>
      <link>https://blog.leanku.com/post/redis/redis%E5%88%86%E5%B8%83%E5%BC%8F/</link>
      <pubDate>Tue, 12 Mar 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/redis/redis%E5%88%86%E5%B8%83%E5%BC%8F/</guid>
      <description>Redis分布式 一、 Redis分布式概述 1. 什么是Redis分布式 Redis分布式是指将Redis数据分布到多个Redis节点上，通过集群方式提供更高性能、更大容量和更好可用性的解决方案。
1.2 为什么需要Redis分布式 数据量增长：单机内存容量有限
高并发需求：单机性能瓶颈
高可用性：避免单点故障
可扩展性：支持业务动态扩容
1.3 Redis分布式方案对比 方案 优点 缺点 使用场景 主从复制 部署简单，读写分离 写操作单点，故障需手动切换 读多写少，数据备份 Redis Sentinel 自动故障转移，高可用 配置复杂，扩容不便 生产环境高可用 Redis Cluster 数据分片，自动故障转移 客户端兼容性要求，迁移复杂 大数据量，高并发 二、 Redis分布式方案搭建 2.1 主从复制搭建 配置文件示例
主节点 (master.conf):
port 6379 daemonize yes pidfile /var/run/redis_6379.pid logfile &amp;#34;/var/log/redis_6379.log&amp;#34; 从节点 (slave.conf):
port 6380 daemonize yes pidfile /var/run/redis_6380.pid logfile &amp;#34;/var/log/redis_6380.log&amp;#34; slaveof 127.0.0.1 6379 启动命令
# 启动主节点 redis-server master.conf # 启动从节点 redis-server slave.conf 2.2 Redis Sentinel搭建 Sentinel配置文件</description>
    </item>
    
    <item>
      <title>Mysql主从复制原理及保证数据一致性</title>
      <link>https://blog.leanku.com/post/database/mysql%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E5%8E%9F%E7%90%86%E5%8F%8A%E4%BF%9D%E8%AF%81%E6%95%B0%E6%8D%AE%E4%B8%80%E8%87%B4%E6%80%A7/</link>
      <pubDate>Tue, 12 Mar 2024 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E5%8E%9F%E7%90%86%E5%8F%8A%E4%BF%9D%E8%AF%81%E6%95%B0%E6%8D%AE%E4%B8%80%E8%87%B4%E6%80%A7/</guid>
      <description>Mysql主从复制原理及保证数据一致性 提升数据库的并发能力 提在实际工作中，我们常常将Redis作为缓存与MySQL来配合使用，当有请求的时候，首先会从缓存中进行查找，如果存在就直接取出，如果不存在再访问数据库。这样就提升了读取的效率，也减少了对后端数据库的访问压力。
此外，对于一般数据库应用而言，都是读多写少的，当数据库读取数据压力较大时，我们可以从成本较小的方案开始优化，可以首先考虑优化SQL和索引，其次就是缓存策略，最后才是主从架构。
主从复制的作用 读写分离。 在读多写少的情况下，可以采用读写分离，主库当做写库，然后根据实际需要，选择使用多个读库，分散读的压力，提高并发性。 数据备份。 主从复制其实就相当于一种热备份的机制。 实现高可用。 数据备份其实就是一种冗余机制，当主服务器出现故障是时，可以切换到从服务器上，提高服务器可用性。 主从复制原理 实际上主从同步的原理就是基于binlog进行数据同步的。在主从复制过程中，会基于3个线程来操作，一个主库线程，两个从库线程。 二进制日志转储线程是一个主库线程。 当从库线程连接的时候，主库可以将二进制日志发送给从库，当主库读取事件的时候，会在Binlog上加锁，读取完成之后，再将锁释放掉。 从库I/O线程会连接到主库，向主库发送请求更新Binlog。 这时从库的I/O线程就可以读取到主库的二进制日志转储线程发送的Binlog更新部分，并且拷贝到本地的中继日志。 从库SQL线程会读取从库中的中继日志，并且执行日志中的事件，将从库中的数据与主库保持同步。 总结起来就是三步：
步骤1：Master将写操作记录到二进制日志（binlog），这些记录叫做二进制日志事件（binary log events）；
步骤2：Slave 将 Master 的 binary log events拷贝到它的中继日志（relay log）；
步骤3：Slave重做中继日志中的事件，将改变应用到自己的数据库中。
搭建 TODO 此处省略，待补充
如何解决数据一致性问题 进行主从同步的内容是二进制日志，它是一个文件，在进行网络传输的过程中就一定会存在主从延迟，这样就可能造成用户在从库上读取的数据不是最新的数据，也就是主从同步中的数据不一致性问题。
方案一、异步复制 异步模式就是客户端提交COMMIT之后不需要等从库返回任何结果，而是直接将结果返回给客户端，这样做的好处是不会影响主库写的效率。 但这样可能会存在主库宕机，而Binlog还没有同步到从库的情况，也就是此时的主库和从库数据不一致。 这时候从从库中选择一个作为新主，那么新主则可能缺少原来主服务器中已提交的事务。所以，这种复制模式下的数据一致性是最弱的。 方案二、半同步复制 半同步复制的原理是在客户端提交COMMIT之后不直接将结果返回给客户端，而是等待至少有一个从库接收到了Binlog，并且写入到中继日志中，再返回给客户端。 这样做的好处是提高了数据的一致性，当然相比于异步复制来说，至少多增加了一个网络连接的延迟，降低了主库写的效率。 在MySQL5.7版本中还增加了一个参数，可以对应答的从库数量进行设置，默认为1，也就是说只要有1个从库进行了响应，就可以返回给客户端。如果将这个参数调大，可以提升数据一致性的强度，但也会增加主库等待从库响应的时间。 方案三、组复制 异步复制和半同步复制都无法最终保证数据的一致性问题，半同步复制是通过判断从库响应的个数来决定是否返回给客户端，虽然数据一致性相比于异步复制有提升，但仍然无法满足对数据一致性要求高的场景。 组复制技术MGR很好地弥补了这两种复制模式的不足，它是MySQL在5.7.17版本中推出的一种新的数据复制技术，是基于Paxos协议的状态机复制。 原文链接：</description>
    </item>
    
    <item>
      <title>PHP面向对象</title>
      <link>https://blog.leanku.com/post/php%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/</link>
      <pubDate>Mon, 11 Mar 2024 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/</guid>
      <description>PHP面向对象 面向对象程序设计实际上就是对现实世界的对象进行建模操作。面向对象程序设计的特征主要可以概括为封装、继承和多态
特性 封装 指将对象的属性和方法封装在一起，使得外部无法直接访问和修改对象的内部状态。通过使用访问控制修饰符（public、private、protected）来限制属性和方法的访问权限，从而实现封装 例如，计算机的主机是由内存条、硬盘、风扇等部件组成，生产厂家把这些部件用一个外壳封装起来组成主机，用户在使用该主机时，无需关心其内部的组成及工作原理 继承 指可以创建一个新的类，该类继承了父类的属性和方法，并且可以添加自己的属性和方法。通过继承，可以避免重复编写相似的代码，并且可以实现代码的重用。 例如，已经描述了汽车模型这个类的属性和行为，如果需要描述一个小轿车类，只需让小轿车类继承汽车模型类，然后再描述小轿车类特有的属性和行为，而不必再重复描述一些在汽车模型类中已有的属性和行为 多态 程序中的多态是指一种行为对应着多种不同的实现。指可以使用一个父类类型的变量来引用不同子类类型的对象，从而实现对不同对象的统一操作。多态可以使得代码更加灵活，具有更好的可扩展性和可维护性。 例如，在一般类中说明了一种求几何图形面积的行为，这种行为不具有具体含义，因为它并没有确定具体几何图形；在特殊类（如三角形、正方形、梯形）中都继承了一般类的求面积的行为，可以根据具体的几何图形重新定义求面积行为。 在 PHP 中，多态可以通过实现接口（interface）和使用抽象类（abstract class）来实现。 类与对象 在PHP中把具有相同属性和行为的对象看成同一类，把属于某个类的实例称为某个类的对象。例如学生小千与小锋是两个不同的对象，两者有共同的属性（如学号、成绩等），也有相同的行为（如选课、显示成绩等），因此两者同属于学生类
类 − 定义了一件事物的抽象特点。类的定义包含了数据的形式以及对数据的操作。 对象 − 是类的实例。 成员变量 − 定义在类内部的变量。该变量的值对外是不可见的，但是可以通过成员函数访问，在类被实例化为对象后，该变量即可成为对象的属性。 成员函数 − 定义在类的内部，可用于访问对象的数据。 继承 − 继承性是子类自动共享父类数据结构和方法的机制，这是类之间的一种关系。在定义和实现一个类的时候，可以在一个已经存在的类的基础之上来进行，把这个已经存在的类所定义的内容作为自己的内容，并加入若干新的内容。 父类 − 一个类被其他类继承，可将该类称为父类，或基类，或超类。 子类 − 一个类继承其他类称为子类，也可称为派生类。 多态 − 多态性是指相同的函数或方法可作用于多种类型的对象上并获得不同的结果。不同的对象，收到同一消息可以产生不同的结果，这种现象称为多态性。 重载 − 简单说，就是函数或者方法有同样的名称，但是参数列表不相同的情形，这样的同名不同参数的函数或者方法之间，互相称之为重载函数或者方法。 抽象性 − 抽象性是指将具有一致的数据结构（属性）和行为（操作）的对象抽象成类。一个类就是这样一种抽象，它反映了与应用有关的重要性质，而忽略其他一些无关内容。任何类的划分都是主观的，但必须与具体的应用有关。 封装 − 封装是指将现实世界中存在的某个客体的属性与行为绑定在一起，并放置在一个逻辑单元内。 构造函数 − 主要用来在创建对象时初始化对象， 即为对象成员变量赋初始值，总与new运算符一起使用在创建对象的语句中。 析构函数 − 析构函数(destructor) 与构造函数相反，当对象结束其生命周期时（例如对象所在的函数已调用完毕），系统自动执行析构函数。析构函数往往用来做&amp;quot;清理善后&amp;quot; 的工作（例如在建立对象时用new开辟了一片内存空间，应在退出前在析构函数中用delete释放）。 类定义 类使用 class 关键字后加上类名定义。 类名后的一对大括号({})内可以定义变量和方法。 类的变量使用 var 来声明, 变量也可以初始化值。 函数定义类似 PHP 函数的定义，但函数只能通过该类及其实例化的对象访问。 &amp;lt;?</description>
    </item>
    
    <item>
      <title>PHP魔术方法</title>
      <link>https://blog.leanku.com/post/php%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95/</link>
      <pubDate>Sun, 10 Mar 2024 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95/</guid>
      <description>PHP魔术方法 魔术方法是一种特殊的方法，当对对象执行某些操作时会覆盖 PHP 的默认操作。
PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods)，这些方法在PHP中充当了举足轻重的作用。
__construct()，类的构造函数。
PHP 允许开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法，所以非常适合在使用对象之前做一些初始化工作。 __destruct()，类的析构函数。 析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。 __call()，在对象中调用一个不可访问方法时调用。 __callStatic()，用静态方式中调用一个不可访问方法时调用 __get()，获得一个类的成员变量时调用。 读取不可访问（protected 或 private）或不存在的属性的值时，__get() 会被调用 __set()，设置一个类的成员变量时调用。 在给不可访问（protected 或 private）或不存在的属性赋值时，__set() 会被调用。 __isset()，当对不可访问属性调用isset()或empty()时调用。 当对不可访问（protected 或 private）或不存在的属性调用 isset() 或 empty() 时，__isset() 会被调用。 __unset()，当对不可访问属性调用unset()时被调用。 当对不可访问（protected 或 private）或不存在的属性调用 unset() 时，__unset() 会被调用。 __sleep()，执行serialize()时，先会调用这个函数。 __sleep() 方法常用于提交未提交的数据，或类似的清理操作。 __wakeup()，执行unserialize()时，先会调用这个函数。 __wakeup() 经常用在反序列化操作中，例如重新建立数据库连接，或执行其它初始化操作。 __toString()，类被当成字符串时的回应方法 __invoke()，调用函数的方式调用一个对象时的回应方法 __set_state()，调用var_export()导出类时，此静态方法会被调用。 __clone()，当对象复制完成时调用 __autoload()，尝试加载未定义的类 __debugInfo()，打印所需调试信息 参考文章： PHP: 魔术方法 - Manual</description>
    </item>
    
    <item>
      <title>MySQL主从复制</title>
      <link>https://blog.leanku.com/post/database/mysql%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/</link>
      <pubDate>Tue, 20 Feb 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/</guid>
      <description>MySQL 分库分表 + 主从复制 一、主从复制 1. 环境说明 1个master节点，2个slave节点
mysql-master mysql-slave1 mysql-slave2 此处使用docker启动多个 MySQL 容器,为每个容器挂载配置文件
docker run -d --name mysql-master -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 mysql:8.0 docker run -d --name mysql-slave1 -e MYSQL_ROOT_PASSWORD=root -p 3307:3306 mysql:8.0 docker run -d --name mysql-slave2 -e MYSQL_ROOT_PASSWORD=root -p 3308:3306 mysql:8.0 创建配置文件目录
mkdir -p ~/mysql/master ~/mysql/slave1 ~/mysql/slave2 2. 修改配置 master的 my.cnf （~/mysql/master/my.cnf）
[mysqld] server-id=1 log_bin=mysql-bin binlog_format=ROW gtid_mode=ON enforce_gtid_consistency=ON log_slave_updates=ON slave1 的 my.cnf（~/mysql/slave1/my.cnf）
[mysqld] server-id=2 relay_log_recovery=ON read_only=ON super_read_only=ON gtid_mode=ON enforce_gtid_consistency=ON log_slave_updates=ON slave2 的 my.</description>
    </item>
    
    <item>
      <title>Mysql的一些常见题 </title>
      <link>https://blog.leanku.com/post/database/mysql%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B8%B8%E8%A7%81%E9%A2%98-/</link>
      <pubDate>Tue, 20 Feb 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B8%B8%E8%A7%81%E9%A2%98-/</guid>
      <description>Mysql的一些常见题 请写出数据类型(int char varchar datetime text)的意思；请问 varchar 和 char有什么区别？
Int 整数char 定长字符 Varchar 变长字符 Datetime 日期时间型Text 文本型 Varchar与char的区别 char是固定长度的字符类型，分配多少空间，就占用多长空间。Varchar是可变长度的字符类型，内容有多大就占用多大的空间，能有效节省空间。由于varchar类型是可变的，所以在数据长度改变的时，服务器要进行额外的操作，所以效率比char类型低。
MyISAM和 InnoDB 的基本区别？索引结构如何实现？
A、MyISAM类型不支持事务，表锁，易产生碎片，要经常优化，读写速度较快，适合用于频繁查询的应用；
B、InnoDB类型支持事务，行锁，有崩溃恢复能力，读写速度比MyISAM慢，适合于插入和更新操作比较多的应用，空间占用大，不支持全文索引等。创建索引：alert table tablename add index 索引名 (字段名)
什么是事务？及其特性？
答：事务：是一系列的数据库操作，是数据库应用的基本逻辑单位。
事务特性：A、原子性：即不可分割性，事务要么全部被执行，要么就全部不被执行。B、一致性或可串性。事务的执行使得数据库从一种正确状态转换成另一种正确状态C、隔离性。在事务正确提交之前，不允许把该事务对数据的任何改变提供给任何其他事务，D、持久性。事务正确提交后，其结果将永久保存在数据库中，即使在事务提交后有了其他故障，事务的处理结果也会得到保存。
或者这样理解：事务就是被绑定在一起作为一个逻辑工作单元的SQL语句分组，如果任何一个语句操作失败那么整个操作就被失败，以后操作就会回滚到操作前状态，或者是上有个节点。为了确保要么执行，要么不执行，就可以使用事务。要将有组语句作为事务考虑，就需要通过ACID测试，即原子性，一致性，隔离性和持久性。
什么是锁？
答：数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时，在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据，破坏数据库的一致性。
加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前，先向系统发出请求，对其加锁。加锁后事务就对该数据对象有了一定的控制，在该事务释放锁之前，其他的事务不能对此数据对象进行更新操作。
基本锁类型：锁包括行级锁和表级锁
索引的作用？和它的优点缺点是什么？
索引就一种特殊的查询表，数据库的搜索引擎可以利用它加速对数据的检索。它很类似与现实生活中书的目录，不需要查询整本书内容就可以找到想要的数据。索引可以是唯一的，创建索引允许指定单个列或者是多个列。缺点是它减慢了数据录入的速度，同时也增加了数据库的尺寸大小。
怎么防止sql注入？
1）过滤掉一些常见的数据库操作关键字：select,insert,update,delete,and,*等，或者通过系统函数：addslashes(需要被过滤的内容)来进行过滤。
2）在PHP配置文件中
Register_globals=off;设置为关闭状态 //作用将注册全局变量关闭。
比如：接收POST表单的值使用$_POST[&amp;lsquo;user&amp;rsquo;],如果将register_globals=on;直接使用$user可以接收表单的值。
3）SQL语句书写的时候尽量不要省略小引号(tab键上面那个)和单引号
4）提高数据库命名技巧，对于一些重要的字段根据程序的特点命名，取不易被猜到的
5）对于常用的方法加以封装，避免直接暴漏SQL语句
6）开启PHP安全模式
Safe_mode=on;
7）打开magic_quotes_gpc来防止SQL注入
Magic_quotes_gpc=off;默认是关闭的，它打开后将自动把用户提交的sql语句的查询进行转换，把&amp;rsquo;转为&#39;，这对防止sql注入有重大作用。
因此开启：magic_quotes_gpc=on;
8）控制错误信息
关闭错误提示信息，将错误信息写到系统日志。
9）使用mysqli或pdo预处理。
数据库优化策略？
合理的表设计。
依据三范式，设计表. ​ 三范式：1.原子性，每个字段都是不可在分的。
在1方式的基础上，表中每一列必须有唯一性，其他字段依赖主键。
在2方式的基础上，表中的每一列只与主键直接相关，而不是间接相关。
选择合适的字段。 I.尽量使用TYPEINT、SMALLINT、MEDIUM_INT代替INT的使用，一般索引，并且是字段递增，可以考虑设置为UNSIGNED.
​ II.使用枚举代替字符串类型。
​ III.将少null的使用，null很难优化，并且还占用额外的空间。</description>
    </item>
    
    <item>
      <title>PHP常见题</title>
      <link>https://blog.leanku.com/post/php%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/</link>
      <pubDate>Tue, 20 Feb 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/</guid>
      <description>PHP常见题 什么事面向对象？主要特征是什么？
面向对象是程序的一种设计方式，它利于提高程序的重用性，使程序结构更加清晰。主要特征：封装、继承、多态。
SESSION 与 COOKIE的区别是什么，请从协议，产生的原因与作用说明?
A、http无状态协议，不能区分用户是否是从同一个网站上来的，同一个用户请求不同的页面不能看做是同一个用户。B、SESSION存储在服务器端，COOKIE保存在客户端。Session比较安全，cookie用某些手段可以修改，不安全。Session依赖于cookie进行传递。禁用cookie后，session不能正常使用。Session的缺点：保存在服务器端，每次读取都从服务器进行读取，对服务器有资源消耗。Session保存在服务器端的文件或数据库中，默认保存在文件中，文件路径由php配置文件的session.save_path指定。Session文件是公有的。
HTTP 状态中302、403、 500代码含义？
一二三四五原则:（即一：消息系列；二：成功系列；三：重定向系列；四：请求错误系列；五：服务器端错误系列。）
302:临时转移成功，请求的内容已转移到新位置
403:禁止访问
500:服务器内部错误 401：代表未授权。
请写出数据类型(int char varchar datetime text)的意思；请问 varchar 和 char有什么区别？
Int 整数char 定长字符 Varchar 变长字符 Datetime 日期时间型Text 文本型 Varchar与char的区别 char是固定长度的字符类型，分配多少空间，就占用多长空间。Varchar是可变长度的字符类型，内容有多大就占用多大的空间，能有效节省空间。由于varchar类型是可变的，所以在数据长度改变的时，服务器要进行额外的操作，所以效率比char类型低。
MyISAM和 InnoDB 的基本区别？索引结构如何实现？
A、MyISAM类型不支持事务，表锁，易产生碎片，要经常优化，读写速度较快，适合用于频繁查询的应用；
B、InnoDB类型支持事务，行锁，有崩溃恢复能力，读写速度比MyISAM慢，适合于插入和更新操作比较多的应用，空间占用大，不支持全文索引等。创建索引：alert table tablename add index 索引名 (字段名)
isset() 和 empty() 区别
isset判断变量是否存在，可以传入多个变量，若其中一个变量不存在则返回假；empty判断变量是否为空为假，只可传一个变量，如果为空为假则返回真。
请说明 PHP 中传值与传引用的区别。什么时候传值什么时候传引用？
按值传递：函数范围内对值的任何改变在函数外部都会被忽略按引用传递：函数范围内对值的任何改变在函数外部也能反映出这些修改优缺点：按值传递时，php必须复制值。特别是对于大型的字符串和对象来说，这将会是一个代价很大的操作。按引用传递则不需要复制值，对于性能提高很有好处。
在PHP中error_reporting这个函数有什么作用？
设置PHP的报错级别并返回当前级别。
现在编程中经常采取MVC三层结构，请问MVC分别指哪三层，有什么优点？
MVC三层分别指：业务模型、视图、控制器，由控制器层调用模型处理数据，然后将数据映射到视图层进行显示，优点是：①可以实现代码的重用性，避免产生代码冗余；②M和V的实现代码分离，从而使同一个程序可以使用不同的表现形式
在程序的开发中，如何提高程序的运行效率？
A、优化SQL语句，查询语句中尽量不使用select *，用哪个字段查哪个字段；少用子查询可用表连接代替；少用模糊查询；
B、数据表中创建索引；
C、对程序中经常用到的数据生成缓存。
语句include和require的区别是什么?为避免多次包含同一文件，可用什么语句代替它们?
区别：在失败的时候：include产生一个warning，而require产生直接产生错误中断require在运行前载入include在运行时载入代替：require_once,include_once
简述php的垃圾收集机制。
php中的变量存储在变量容器zval中，zval中除了存储变量类型和值外，还有is_ref和refcount字段。refcount表示指向变量的元素个数，is_ref表示变量是否有别名。如果refcount为0时，就回收该变量容器。如果一个zval的refcount减1之后大于0，它就会进入垃圾缓冲区。当缓冲区达到最大值后，回收算法会循环遍历zval，判断其是否为垃圾，并进行释放处理。
什么是 CSRF 攻击 ？XSS 攻击？如何防范？</description>
    </item>
    
    <item>
      <title>Redis的一些常见题 </title>
      <link>https://blog.leanku.com/post/redis/redis%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B8%B8%E8%A7%81%E9%A2%98-/</link>
      <pubDate>Tue, 20 Feb 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/redis/redis%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B8%B8%E8%A7%81%E9%A2%98-/</guid>
      <description>Redis的一些常见题 redis数据类型及应用场景 见 Redis的五种数据类型及使用场景
redis持久化及过期策略 见 Redis持久化及过期删除策略
redis 常见问题及解决方案
缓存雪崩：同一时间大量缓存失效，导致请求直接查询数据库，数据库内存和CPU压力增加甚至宕机
解决：
热点数据永不过期或者分布到不同实例，降低单机故障问题
缓存时间添加随机数，防止大量缓存同时失效 做二级缓存或者双缓存，A为原始缓存 短时效，B为备份缓存 ，长期有效。更新时候双写缓存
缓存穿透：缓存和数据库都没有数据，大量请求下，所有请求直接击穿到数据库，导致宕机。
解决：
布隆过滤器:长度为m的位向量或者位列表组成（仅包含0或1位值的列表）
使用多个不用的hash函数，产生多个索引值，填充对应多个位置的值为1
布隆过滤器可以检查值是 “可能在集合中” 还是 “绝对不在集合中”
可能误判但是基础过滤效率高
极端情况，当布隆过滤器没有空闲位置的时候每次查询返回true
空缓存（短时效）
业务层参数过滤
缓存击穿：数据库中有数据，但是缓存突然失效之后发生大量请求导致数据库压力增加甚至打垮宕机
解决： 热点数据永不过期
互斥锁：获取锁之后不管成功还是失败都要释放锁
Redis主从复制原理 Redis 在复制时底层采用的是 psync 命令完成的数据主从同步，同步主要分为：全量复制和增量复制两种
全量复制：顾名思义也就是一次性把主节点数据全部发送给从节点，所以这种情况下，当数据量比较大时，会对主节点和网络造成很大的开销。 部分复制：用于处理主从复制时因网络中断等原因造成数据丢失的场景。当从节点再次和主节点连接时，主节点会补发丢失的数据。因为是补发，所以在发送的数据量一定是小于全量的数据。
详细见 Redis的一些常见题 Redis缓存和数据库数据一致性问题：
读数据 尝试查询缓存，存在缓存则直接返回数据 缓存不存在时则查询数据库，并保存到缓存（合适设置过期时间），返回数据 写数据 先更新缓存再更新数据库 或者 先删除缓存再更新数据库 先更新数据库再更新缓存 或者 先更新数据库再删除缓存 使用删除还是更新？ 这里无非是删除还是更新Redis，直接删除的方式比较简单，在下一次查询时会生成缓存（更推荐）；更新缓存则相较复杂 先操作Redis还是先操作数据库？ 先操作数据库 （推荐） 流程:先更新数据库，再删除缓存 问题：比如线程1执行写操作（修改数据库-&amp;gt;删除缓存），线程2执行读操作（查询缓存-&amp;gt;旧数据），就会出现旧数据返回，或者删除缓存失败也会返回旧数据 先操作缓存 流程：修改操作先删除缓存再修改数据库 问题： 比如线程1去执行写操作： （删除缓存-&amp;gt;更新数据库）同时有线程2执行读操作（查询缓存（未查到缓存）-&amp;gt;查数据库-&amp;gt;保存到缓存）因为数据库更新有可能网络延迟等问题，这里保存到缓存的数据就是旧的数据，只有再过期之后才会读到新数据 解决方案： （延迟双删）在数据库更新之后再进行一次缓存删除（加适当延迟，比如延迟500ms），这时再有查询过来也会查询到数据库并保存到缓存。但是线程2在这个删除缓存500ms内请求仍然可能会出现一次获取到旧数据 （推荐方式） </description>
    </item>
    
    <item>
      <title>ShardingSphere 使用指南</title>
      <link>https://blog.leanku.com/post/database/shardingsphere-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</link>
      <pubDate>Tue, 20 Feb 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/database/shardingsphere-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</guid>
      <description>ShardingSphere 使用指南 一、介绍 Apache ShardingSphere 是一个开源的 分布式数据库中间件生态，支持 分库分表、读写分离、数据加密、影子库 等功能。它的定位是 数据库增强计算层，让你在不修改（或少量修改）应用代码的情况下，实现复杂的数据分片与治理。
核心组件：
ShardingSphere-JDBC：客户端 SDK，直接在应用中引入。 ShardingSphere-Proxy：中间件代理层，应用通过 MySQL 协议访问，无需修改业务代码。 ShardingSphere-Sidecar：面向 K8s 的云原生数据库 Mesh。 二、适用场景 分库分表：数据量过大，单表行数超过 1千万～1亿，单库容量超限时。
读写分离：主库写、从库读，提升查询性能。
柔性事务：分布式场景下保证一致性（支持 Seata、XA）。
数据加密：对敏感字段（手机号、身份证号）自动加密存储，解密查询。
影子库：A/B 测试或灰度发布。
三、 配置方式 以 ShardingSphere-Proxy 为例（最常用于 PHP 项目）。
3.1 部署 Proxy wget https://downloads.apache.org/shardingsphere/5.4.2/apache-shardingsphere-5.4.2-shardingsphere-proxy-bin.tar.gz tar -zxvf apache-shardingsphere-5.4.2-shardingsphere-proxy-bin.tar.gz cd apache-shardingsphere-5.4.2-shardingsphere-proxy-bin 配置文件路径：
conf/server.yaml # 全局配置（身份认证、元数据） conf/config-sharding.yaml # 分库分表配置 3.2 示例配置（分库分表 + 读写分离） server.yaml （全局配置） authentication: users: root: password: root123 # 设置登录 ShardingSphere-Proxy 的账号和密码 authorizedSchemas: ds_sharding # 指定该用户可访问的逻辑库（schema） props: sql-show: true # 开启 SQL 打印，方便调试时查看 Proxy 最终路由后的真实 SQL config-sharding.</description>
    </item>
    
    <item>
      <title>Logstash</title>
      <link>https://blog.leanku.com/post/logstash/</link>
      <pubDate>Tue, 20 Feb 2024 17:01:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/logstash/</guid>
      <description>Logstash ALogstash 介绍 Logstash 是一个开源的日志收集、处理和转发工具，通常与 Elasticsearch 和 Kibana 一起组成 Elastic Stack，用于集中式日志管理和数据分析。它支持多种数据源、数据处理及输出目标，常用于日志的收集和处理。
1. 安装 Logstash Logstash 支持多种操作系统，安装方式可以使用包管理工具、压缩包或 Docker。
a. 通过 apt 安装（以 Ubuntu 为例） 首先，添加 Elastic 的 APT 仓库：
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add - sudo sh -c &amp;#39;echo &amp;#34;deb https://artifacts.elastic.co/packages/7.x/apt stable main&amp;#34; &amp;gt; /etc/apt/sources.list.d/elastic-7.x.list&amp;#39; 然后，更新 APT 仓库并安装 Logstash：
udo apt-get update sudo apt-get install logstash b. 使用 .tar.gz 包安装
可以从官网（https://www.elastic.co/downloads/logstash）下载压缩包，解压并安装。
tar -xvzf logstash-7.x.x.tar.gz cd logstash-7.x.x 2. 配置 Logstash Logstash 的配置文件通常由 3 个部分组成：输入（input）、过滤器（filter） 和 输出（output）。</description>
    </item>
    
    <item>
      <title>PHP常用函数整理</title>
      <link>https://blog.leanku.com/post/php%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0%E6%95%B4%E7%90%86/</link>
      <pubDate>Sun, 18 Feb 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0%E6%95%B4%E7%90%86/</guid>
      <description>PHP常用函数整理 字符串 strlen() 获取字符串长度。（一个汉字长度为3个字符，一个英文字母长度为1个字符）
strpos() 在字符串内查找一个字符或一段指定的文本，返回第一次出现的位置或者false
stripos() 同上，但不区分大小写
strrpos() 同上上，返回最后一次出现的位置或false
strripos() 同上，但不区分大小写
explode() 字符串打散为数组
implode() 数组拼接成字符串
strtoupper() 把字符串转换为大写
strtolower() 把字符串转换为大写
ucfirst() 把单词的首字母转换成大写
lcfirst() 把单词的首字母转换为小写
ucwords() 把字符串中每个单词的首字母转换为大写
str_replace 子字符串替换
str_ireplace str_replace 的忽略大小写版本
strrev 反转字符串
trim 去除字符串首尾处的空白字符（或者其他字符）
rtrim 删除字符串末端的空白字符（或者其他字符）
substr 截取字符串的一部分，返回字符串的子串
substr 截取字符串的一部分（中文，需要安装扩展mbstring），返回字符串的子串
更多请参考官方文档
数组 array() 创建数组
count() 返回数组中元素的数量 sizeof() 同样效果
array_push() 将一个或多个单元压入数组的末尾（入栈）
array_pop() 弹出数组最后一个单元（出栈）
array_unshift() 在数组开头插入一个或多个单元
array_shift() 将数组开头的单元移出数组
shuffle() 打乱数组
reset — 将数组的内部指针指向第一个单元
end — 将数组的内部指针指向最后一个单元
current — 返回数组中的当前值
list — 把数组中的值赋给一组变量</description>
    </item>
    
    <item>
      <title>一些PHP基础的简单整理</title>
      <link>https://blog.leanku.com/post/%E4%B8%80%E4%BA%9Bphp%E5%9F%BA%E7%A1%80%E7%9A%84%E7%AE%80%E5%8D%95%E6%95%B4%E7%90%86/</link>
      <pubDate>Sun, 18 Feb 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/%E4%B8%80%E4%BA%9Bphp%E5%9F%BA%E7%A1%80%E7%9A%84%E7%AE%80%E5%8D%95%E6%95%B4%E7%90%86/</guid>
      <description>一些PHP基础的简单整理 常量 关于常量定义 &amp;lt;?php $a = 1; define(&amp;#34;AAA&amp;#34;.$a,&amp;#34;AAA&amp;#34;); echo constant(&amp;#34;AAA&amp;#34;.$a); define() 在运行时定义一个常量。
constant() 返回一个常量的值。当你不知道常量名，却需要获取常量的值时，constant() 就很有用了。也就是说，常量名储存在一个变量里，或者由函数返回时。
const不能在条件语句中定义常量。 const用于类成员变量的定义，define()不可用于类成员变量的定义，可用于全局变量。
const可在类中使用，define不能。
常量和变量的区别
常量前面没有且不能有$符号 常量可以不用理会变量的作用域，在任何地方定义和使用 常量一旦定义就不能重新定义或取消定义 常量的值只能是标量（字符串、整数、浮点数、布尔值），支持数组 获取所有常量
get_defined_constants()
get_defined_constants(true)
get_defined_constants(true)[&amp;lsquo;user&amp;rsquo;]
魔术常量：它的值随着它在代码中的位置改变而变化
LINE 文件中的当前行号 FILE 文件的完整路径和文件名，包含根目录 DIR 文件所在目录 FUNCTION 该函数被定义时的名字，区分大小写 CLASS 该类被定义时的名字，区分大小写 NAMESPANCE 命名空间 METHOD 命名空间类名方法名 TRAIT 当前使用的trait的名字 包含文件 include和require的区别 include和require除了错误处理的方式不同，其他方面都是相同的。
require生成一个致命错误（E_COMPILE_ERROR），在错误发生后脚本停止运行
include生成一个警告（E_WARNING）,在错误发生后脚本继续运行 面向对象(OO) 概念
面向对象是一种编程思想和方法，它将程序中的数据和操作数据的方法封装在一起，形成“对象”，并通过对象之间的交互和消息传递来完成程序的功能。 面向对象编程（OOP）强调数据的封装、继承、多态和动态绑定等特性，使得程序具有更好的可扩展性、可维护性和可重用性。 OOP特性
封装：指将对象的属性和方法封装在一起，使得外部无法直接访问和修改对象的内部状态。通过使用访问控制修饰符（public、private、protected）来限制属性和方法的访问权限，从而实现封装 继承：指可以创建一个新的类该类继承（extends）了父类的属性和方法，并且可以添加自己的属性和方法。通过继承，可以避免重复编写相似的代码，并且可以实现代码的复用。 多态：指可以使用一个父类类型的变量来引用不同子类类型的对象，从而实现对不同对象统一操作。多态可以使得代码更加灵活，具有更好的可扩展性和可维护性。在PHP中多态可通过实现接口（interface）和使用抽象类（abstract class）来实现。 类的访问控制
public（公有）：公有的类成员可以在任何地方被调用。 protected（受保护）：受保护的类成员可以被其自身以及其子类和父类访问。 private（私有）：私有的类成员只能被其定义所在的类访问 构造方法 __construct
构造方法是一种特殊的方法，在创建一个新对象时，它会被自动调用 他可以用来 初始化 对象的属性或执行其他必要的操作 没有返回值 析构函数 __destruct</description>
    </item>
    
    <item>
      <title>对进程、线程和协程的理解</title>
      <link>https://blog.leanku.com/post/%E8%BF%9B%E7%A8%8B%E7%BA%BF%E7%A8%8B%E5%92%8C%E5%8D%8F%E7%A8%8B/</link>
      <pubDate>Sun, 18 Feb 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/%E8%BF%9B%E7%A8%8B%E7%BA%BF%E7%A8%8B%E5%92%8C%E5%8D%8F%E7%A8%8B/</guid>
      <description>对进程、线程和协程的理解 一、 进程 先来了解一下操作系统的进程：
操作系统对正在运行程序的抽象，这个就是进程（process）。 比如运行一个 web 浏览器，一个 text 文本，都是运行的一个一个进程。
有的人说：进程是程序运行资源的集合。进程是系统资源分配的最小单位等等。
从静态的角度来说，进程确实是运行程序的各种资源集合。
如果你进一步思考，进程里的各种资源都有哪些呢？
内存管理相关
文件系统
调度相关
信号处理
内核栈
进程各种状态
进程运行时统计信息
进程标识
等等。
可以看出，进程中的资源是相当多的。
从 Linux 操作系统对进程的定义也可以看出。
多进程：操作系统有多个程序运行，那么就有多个进程
二、 线程 《操作系统设计与实现》里说：
在传统操作系统中，每个进程中只存在一个地址空间和一个控制流（thread）。
然后，有些情况下，需要在相同地址空间中有多个控制流并行的运行，就像他们是单独的进程一样（只是他们共享相同的地址空间）。
这些控制流通常被称为线程（thread），有时也称为轻量级进程（lightweight process）。
尽管线程必须在进程中执行，但是线程和进程是可以分别对待处理的两个概念。进程用来集合资源，而线程是 CPU 调度的实体。
线程给进程模型增加的是，允许在同一个进程环境中有多个执行流，这些执行流在很大程度上相对独立。
也即是说，在进程中，程序执行的最小单位（执行流）是线程，可以把线程看作是进程里的一条执行流。
一个进程里可以有一条或多条线程。
为什么会有多线程 在一个应用程序执行过程中，应用程序里可能会有多种事件执行。
而有些事件执行一段时间后可能会被阻塞。如果把应用程序执行事件分解成多个并行运行的线程，即可以让程序设计变得简单，如果有阻塞的，
可以把这部分让出行换其他线程执行。
还有一个原因是：
线程比进程更轻量级。所以线程比进程更加容易创建，销毁。
第三个跟第一个有点关系，是关于性能的，若多线程都是 CPU 密集型的，那么不能获取性能上增强。如果有大量计算和大量 I/O 处理，那么
多线程就可以获取性能上的优势，因为允许多线程重叠执行。
多线程的缺点：
对于多线程来说，进程中的资源是共享的，所以会产生资源竞争。 当进程中的一个线程崩溃了，会导致这个进程里的其他线程也崩溃。所以有时多进程程序更好，一个进程崩溃不会导致其他进程也崩溃。 三、 进程和线程的区别 从上面进程和线程介绍知道，线程是程序执行流的最小单位，进程是操作系统分配资源的单位。
进程与进程之间关系：
进程与进程之间是相互独立的。
线程与进程关系：
线程是进程里的执行流，进程里的线程可以是一个，也可以是多个。
所有线程共享进程里一些资源，比如代码，数据，地址空间，信号处理，打开文件，全局变量等。
同时，线程也有自己的寄存器，程序计数器，堆栈，线程状态等
四、协程 协程是建立在线程之上，一般是语言级别的 ”多线程“ 模型，比线程更加的轻量级。有的叫它微线程。它是完全运行在用户态里。
协程是在线程之上在进行抽象，它需要线程来承载运行。一个线程可以有多个协程。
协程的优点：</description>
    </item>
    
    <item>
      <title>PHP的 FPM 和 CLI </title>
      <link>https://blog.leanku.com/post/php-fpm-%E5%92%8C-cli/</link>
      <pubDate>Sat, 17 Feb 2024 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php-fpm-%E5%92%8C-cli/</guid>
      <description>PHP的 FPM 和 CLI PHP-FPM PHP-FPM 即 PHP FastCGI 进程管理器。
要了解 PHP-FPM ，首先要看看 CGI 与 FastCGI 的关系。 CGI 的英文全名是 Common Gateway Interface，即通用网关接口，是 Web 服务器调用外部程序时所使用的一种服务端应用的规范。 早期的 Web 通信只是按照客户端请求将保存在 Web 服务器硬盘中的数据转发过去而已，这种情况下客户端每次获取的信息也是同样的内容（即静态请求，比如图片、样式文件、HTML文档），而随着 Web 的发展，Web 所能呈现的内容更加丰富，与用户的交互日益频繁，比如博客、论坛、电商网站、社交网络等。 这个时候仅仅通过静态资源已经无法满足 Web 通信的需求，所以引入 CGI 以便客户端请求能够触发 Web 服务器运行另一个外部程序，客户端所输入的数据也会传给这个外部程序，该程序运行结束后会将生成的 HTML 和其他数据通过 Web 服务器再返回给客户端（即动态请求，比如基于 PHP、Python、Java 实现的应用）。利用 CGI 可以针对用户请求动态返回给客户端各种各样动态变化的信息。 FastCGI 顾名思义，是 CGI 的升级版本，为了提升 CGI 的性能而生，CGI 针对每个 HTTP 请求都会 fork 一个新进程来进行处理（解析配置文件、初始化执行环境、处理请求），然后把这个进程处理完的结果通过 Web 服务器转发给用户，刚刚 fork 的新进程也随之退出，如果下次用户再请求动态资源，那么 Web 服务器又再次 fork 一个新进程，如此周而复始循环往复。 而 FastCGI 则会先 fork 一个 master 进程，解析配置文件，初始化执行环境，然后再 fork 多个 worker 进程（与 Nginx 有点像），当 HTTP 请求过来时，master 进程将其会传递给一个 worker 进程，然后立即可以接受下一个请求，这样就避免了重复的初始化操作，效率自然也就提高了。而且当 worker 进程不够用时，master 进程还可以根据配置预先启动几个 worker 进程等着；当空闲 worker 进程太多时，也会关掉一些，这样不仅提高了性能，还节约了系统资源。 这样一来，PHP-FPM 就好理解了，FastCGI 只是一个协议规范，需要每个语言具体去实现，PHP-FPM 就是 PHP 版本的 FastCGI 协议实现，有了它，就是实现 PHP 脚本与 Web 服务器（通常是 Nginx）之间的通信，同时它也是一个 PHP SAPI，从而构建起 PHP 解释器与 Web 服务器之间的桥梁。 PHP-FPM 负责管理一个进程池来处理来自 Web 服务器的 HTTP 动态请求，在 PHP-FPM 中，master 进程负责与 Web 服务器进行通信，接收 HTTP 请求，再将请求转发给 worker 进程进行处理，worker 进程主要负责动态执行 PHP 代码，处理完成后，将处理结果返回给 Web 服务器，再由 Web 服务器将结果发送给客户端。这就是 PHP-FPM 的基本工作原理。</description>
    </item>
    
    <item>
      <title>Redis的数据类型及使用场景</title>
      <link>https://blog.leanku.com/post/redis/redis%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8F%8A%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF/</link>
      <pubDate>Fri, 01 Sep 2023 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/redis/redis%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8F%8A%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF/</guid>
      <description>Redis的数据类型及使用场景 一、基本数据类型 1.字符串（String） string 是 redis 最基本的类型，你可以理解成与 Memcached 一模一样的类型，一个 key 对应一个 value。 string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如 jpg 图片或者序列化的对象。 string 类型是 Redis 最基本的数据类型，string 类型的值最大能存储 512MB。 常用命令： SET key value 设置指定 key 的值。 GET key 获取指定 key 的值。 应用场景： String 是最常用的一种数据类型，普通的 key/value 存储都可以归为此类，即可以完全实现目前 Memcached 的功能，并且效率更高。还可以享受 Redis 的定时持久化，操作日志及 Replication 等功能。除了提供与 Memcached 一样的 get、set、incr、decr 等操作外，Redis 还提供了下面一些操作：
获取字符串长度 往字符串 append 内容 设置和获取字符串的某一段内容 设置及获取字符串的某一位（bit） 批量设置一系列字符串的内容 使用场景： 常规 key-value 缓存应用。常规计数：微博数，粉丝数。
实现方式： String 在 redis 内部存储默认就是一个字符串，被 redisObject 所引用，当遇到 incr,decr 等操作时会转成数值型进行计算，此时 redisObject 的 encoding 字段为 int</description>
    </item>
    
    <item>
      <title>SQL语法速成</title>
      <link>https://blog.leanku.com/post/sql%E8%AF%AD%E6%B3%95%E9%80%9F%E6%88%90/</link>
      <pubDate>Fri, 01 Sep 2023 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/sql%E8%AF%AD%E6%B3%95%E9%80%9F%E6%88%90/</guid>
      <description>SQL语法速成 SQL 语法结构 子句 - 是语句和查询的组成成分。（在某些情况下，这些都是可选的。） 表达式 - 可以产生任何标量值，或由列和行的数据库表 谓词 - 给需要评估的 SQL 三值逻辑（3VL）（true/false/unknown）或布尔真值指定条件，并限制语句和查询的效果，或改变程序流程。 查询 - 基于特定条件检索数据。这是 SQL 的一个重要组成部分。 语句 - 可以持久地影响纲要和数据，也可以控制数据库事务、程序流程、连接、会话或诊断。 SQL 语法要点 SQL 语句不区分大小写，但是数据库表名、列名和值是否区分，依赖于具体的 DBMS 以及配置。 例如：SELECT 与 select 、Select 是相同的。 多条 SQL 语句必须以分号 ; 分隔。 处理 SQL 语句时，所有空格都被忽略。SQL 语句可以写成一行，也可以分写为多行。 SQL 支持三种注释 ## 注释1 -- 注释2 /* 注释3 */ 增删改查，又称为 CRUD，数据库基本操作中的基本操作。 插入数据 INSERT INTO 语句用于向表中插入新记录。
插入完整的行
INSERT INTO user VALUES (10, &amp;#39;root&amp;#39;, &amp;#39;root&amp;#39;, &amp;#39;xxxx@163.com&amp;#39;); 插入行的一部分
INSERT INTO user(username, password, email)VALUES (&amp;#39;admin&amp;#39;, &amp;#39;admin&amp;#39;, &amp;#39;xxxx@163.</description>
    </item>
    
    <item>
      <title>Kong API网关</title>
      <link>https://blog.leanku.com/post/microservice/kong-api%E7%BD%91%E5%85%B3/</link>
      <pubDate>Tue, 01 Aug 2023 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/microservice/kong-api%E7%BD%91%E5%85%B3/</guid>
      <description>Kong API网关 API网关特点 集合多个API，统一API入口 避免内部信息泄露 提供安全认证 支持混合通讯协议 降低微服务复杂度 常用的API网关有：NGINX，Zuul，Kong
Kong 介绍 kong是微服务中的一个网关组件，具有高可用和可扩展性，能提供易于使用的restful api来操作和配置API管理系统，同时它也可以通过负载均衡的功能把请求均匀的分发到各个服务器上，应对大量的请求。基于Nginx和OpenResty，是一个具有分布式、高性能、高并发、可伸缩&amp;hellip;亚毫秒级延迟等特性和功能的微服务抽象层。
konga 是kong的UI界面 多用户管理 管理多个kong节点 使用快照备份，还原和迁移Kong节点 使用运行状态检查监控节点和API状态 数据库集成postgresSQL Kong 流程图 Kong 安装 Kong下载安装
Konga下载安装
API操作 文档地址 示例:
负载均衡 # 添加负载均衡 curl -i -X POST \ -H &amp;#34;Content-Type:application/x-www-form-urlencoded&amp;#34; \ -d &amp;#34;name=demo-upstream&amp;#34; \ &amp;#39;http://127.0.0.1:8001/upstreams&amp;#39; #设置权重 curl -i -X POST \ -H &amp;#34;Content-Type:application/x-www-form-urlencoded&amp;#34; \ -d &amp;#34;target=127.0.0.1:8000&amp;#34; \ -d &amp;#34;weight=100&amp;#34; \ &amp;#39;http://127.0.0.1:8001/upstreams/demo-upstream/targets&amp;#39; curl -i -X POST \ -H &amp;#34;Content-Type:application/x-www-form-urlencoded&amp;#34; \ -d &amp;#34;target=127.0.0.1:8080&amp;#34; \ -d &amp;#34;weight=500&amp;#34; \ &amp;#39;http://127.</description>
    </item>
    
    <item>
      <title>Konga</title>
      <link>https://blog.leanku.com/post/microservice/konga/</link>
      <pubDate>Tue, 01 Aug 2023 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/microservice/konga/</guid>
      <description>Konga Konga的本质：Konga是一个图形化界面，它最终是通过调用你配置的 Kong Admin API 来修改Kong的配置的。
文档参考：遇到复杂场景时，最好的老师依然是Kong官方文档。
一、首次登录与初始化设置 访问Konga并注册：在浏览器中打开 http://&amp;lt;你的服务器IP&amp;gt;:1337。首次访问时，Konga会要求你注册一个管理员账户。填写用户名、邮箱和密码完成注册。 登录系统：注册成功后，Konga会自动跳转到登录页面，使用刚才注册的账号密码登录即可 二、 连接Konga与Kong网关 进入连接设置：登录成功后，你应该会看到&amp;quot;CONNECTIONS&amp;quot;或&amp;quot;Connections&amp;quot;界面。如果没有，请在左侧菜单或顶部导航栏中找到并点击 &amp;ldquo;Connections&amp;rdquo;。 填写Kong Admin API信息： Connection name：为你这个Kong连接起个名字，比如&amp;quot;My-Kong&amp;quot;或&amp;quot;Production&amp;quot;。 Kong Admin URL：这是你Kong网关的Admin API地址。非常重要！ 格式通常是 http://:8001 如果你的Kong容器和Konga容器在同一个Docker网络（如 kong-net）中，你可以使用Kong的容器名和内部端口，例如：http://kong:8001。 如果你希望通过宿主机IP访问，可能需要使用宿主机的IP和映射给Kong Admin API的端口（例如 http://localhost:8001 或 http://&amp;lt;宿主机IP&amp;gt;:8001）。 激活连接：信息填写完毕后，点击 &amp;ldquo;Active&amp;rdquo; 或 &amp;ldquo;Connect&amp;rdquo; 等按钮来激活并测试连接。如果一切正常，Konga会提示连接成功。 三、 Konga核心功能与使用介绍 连接成功后，你就可以使用Konga来管理Kong了。Konga的核心功能围绕以下几个概念展开，理解它们之间的关系很重要：
概念 (Concept) 作用 (Role) 类比 (Analogy) 配置要点 (Key Configuration) Upstream 负载均衡组：代表一个虚拟主机名，用于对后端多个Target进行负载均衡。 球队的名称 Name：为Upstream命名（如 my-api-upstream）。 Target 具体目标：代表一个物理服务（IP+Port），是Upstream组内的一个具体后端实例。必须先创建Upstream，才能添加Target。 球队里的一个球员 Target：后端服务的IP或主机名及端口（如 192.168.1.100:8080）。Weight：权重，流量分配比例。 Service 服务抽象：是上游服务的抽象，可以直接指向一个具体的URL，也可以关联一个Upstream来实现负载均衡。 比赛的战术安排 Name：服务名称。Protocol：协议（HTTP/HTTPS）。Host：可填写具体URL或关联的Upstream名称。Port：端口。Path：路径（可选）。 Route 路由规则：定义客户端请求的匹配规则（如路径、域名），将匹配的请求路由到指定的Service。 根据球衣颜色决定把球传给谁 Paths：匹配的请求路径（如 /api）。Hosts：匹配的域名（可选）。Service：选择该路由要关联的Service。 四、 创建服务 (Services) 和路由 (Routes) 这是最常用的功能，用于将外部请求转发到你的后端服务。</description>
    </item>
    
    <item>
      <title>VirtualBox&#43;Vagrant使用</title>
      <link>https://blog.leanku.com/post/devops/virtualbox&#43;vagrant%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Tue, 01 Aug 2023 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/devops/virtualbox&#43;vagrant%E4%BD%BF%E7%94%A8/</guid>
      <description>VirtualBox+Vagrant使用 一、 介绍 1. VirtualBox简介 VirtualBox是一个开源的 虚拟机管理软件，由 Oracle 开发。它的核心功能是允许你在一台物理机上运行多个虚拟机，每个虚拟机都可以装不同的操作系统。
特点： 跨平台：支持 Windows、Linux、macOS 主机上安装。
支持多种客操作系统：常见的 Linux 发行版（CentOS、Ubuntu）、Windows Server、BSD 等。
虚拟化功能：
配置虚拟 CPU、内存、磁盘、网卡等。
支持桥接网络、NAT、仅主机网络等多种网络模式。
GUI + CLI 管理：既可以用图形界面管理虚拟机，也可以用命令行 VBoxManage 控制。
适合个人和开发使用：开源免费，功能较全。
2. Vagrant简介 Vagrant 是一个虚拟机 自动化管理工具，它本身不提供虚拟化功能，而是调用 VirtualBox、VMware、Hyper-V、Docker 等“虚拟化提供者”（provider）来创建和管理虚拟机。
特点： 开发环境自动化：
通过 Vagrantfile 描述一台（或多台）虚拟机的配置，比如操作系统镜像、CPU/内存、网络、共享目录等。
跨平台一致性：
不同开发者只要用相同的 Vagrantfile，就能快速得到一模一样的开发环境，避免“在我机器上没问题”。
支持多种 Provider：
默认支持 VirtualBox，也可以配合 VMware、Hyper-V、Libvirt、Docker。
Provisioning（自动化配置）：
可以在虚拟机启动时自动执行脚本（Shell、Ansible、Puppet、Chef）来安装软件和配置环境。
命令行简单：
vagrant init → 生成配置文件
vagrant up → 启动虚拟机
vagrant ssh → 进入虚拟机
vagrant halt → 关闭虚拟机
vagrant destroy → 删除虚拟机</description>
    </item>
    
    <item>
      <title>ElasticSearch介绍</title>
      <link>https://blog.leanku.com/post/elasticsearch/</link>
      <pubDate>Wed, 19 Jul 2023 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/elasticsearch/</guid>
      <description>ElasticSearch 1. ElasticSearch介绍 Elasticsearch 是一个分布式、可扩展、实时的搜索和分析引擎，基于 Apache Lucene 构建。它能够快速存储、搜索和分析大量数据，广泛应用于全文搜索、日志分析、业务指标监控等场景。
Lucene 介绍 Lucene是开源、免费、高性能、纯Java编写的全文检索工具包
他是一个全文检索的工具包，是一个全文检索框架，并不是一个全文检索引擎
它非常复杂，并且需要Java集成使用
Lucene 和 ElasticSearch ElasticSearch和solr是基于lucene的开源项目 ElasticSearch通过简单易用的restful api接口，隐藏了lucene的复杂性 ElasticSearch自带分布式管理，并且可以跨语言使用 Lucene 和 Solr ElasticSearch自带分布式管理而Solr需要借助Zookpeeper实现分布式管理 Solr支持多格式的数据，在传统搜索中表现好于ES,但是它的更新效率比较低 ElasticSearch只支持json格式的数据，在处理实时索引搜索时明显好于Solr 2. 核心概念 1. 文档（Document） Elasticsearch 中的基本数据单元，类似于关系数据库中的一行记录。 文档以 JSON 格式存储，包含多个字段。 示例： { &amp;#34;id&amp;#34;: 1, &amp;#34;title&amp;#34;: &amp;#34;Elasticsearch Guide&amp;#34;, &amp;#34;content&amp;#34;: &amp;#34;Elasticsearch is a distributed search engine.&amp;#34;, &amp;#34;tags&amp;#34;: [&amp;#34;search&amp;#34;, &amp;#34;distributed&amp;#34;] } 2.索引（Index） 索引是文档的集合，类似于关系数据库中的表。 每个索引有一个唯一的名称，用于标识和操作数据。 示例：books 索引存储所有书籍相关的文档。 3.类型（Type）（已弃用） 在早期版本中，索引可以包含多个类型（类似于表结构），但在 Elasticsearch 7.x 及更高版本中已被弃用。
4.分片（Shard） 索引可以被分成多个分片，每个分片是一个独立的 Lucene 索引。 分片允许数据水平拆分，支持分布式存储和并行处理。 分片分为主分片（Primary Shard）和副本分片（Replica Shard）。 5.</description>
    </item>
    
    <item>
      <title>PHP 8 新特性之枚举</title>
      <link>https://blog.leanku.com/post/php8%E6%96%B0%E7%89%B9%E6%80%A7-%E6%9E%9A%E4%B8%BE/</link>
      <pubDate>Sun, 11 Jun 2023 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php8%E6%96%B0%E7%89%B9%E6%80%A7-%E6%9E%9A%E4%B8%BE/</guid>
      <description>PHP 8 新特性之枚举 枚举概览 枚举，或称 “Enum”，能够让开发者自定义类型为一系列可能的离散值中的一个。 在定义领域模型中很有用，它能够“隔离无效状态”（making invalid states unrepresentable）。
枚举以各种不同功能的形式出现在诸多语言中。 在 PHP 中， 枚举是一种特殊类型的对象。Enum 本身是一个类（Class）， 它的各种条目（case）是这个类的单例对象，意味着也是个有效对象 —— 包括类型的检测，能用对象的地方，也可以用它。
最常见的枚举例子是内置的 boolean 类型， 该枚举类型有两个有效值 true 和 false。 Enum 使开发者能够任意定义出用户自己的、足够健壮的枚举。
Enum 类似 class，它和 class、interface、trait 共享同样的命名空间。 也能用同样的方式自动加载。 一个 Enum 定义了一种新的类型，它有固定、数量有限、可能的合法值。 示例 #1 用注解实现接口的可选方法
&amp;lt;?php // 通过传入参数：待搜索的注解类名，可返回指定的注解类， 而不需要再到反射类中迭代循环获取所有注解。 示例
&amp;lt;?php &amp;lt;?php // 声明新的枚举类型 Suit，仅有四个有效的值： Suit::Hearts、Suit::Diamonds、 Suit::Clubs、Suit::Spades。 enum Suit { case Hearts; case Diamonds; case Clubs; case Spades; } // 变量可以赋值为以上有效值里的其中一个。 函数可以检测枚举类型，这种情况下只能传入类型的值。 function pick_a_card(Suit $suit) { /* .</description>
    </item>
    
    <item>
      <title>PHP 8 新特性之注解</title>
      <link>https://blog.leanku.com/post/php8%E6%96%B0%E7%89%B9%E6%80%A7-%E6%B3%A8%E8%A7%A3/</link>
      <pubDate>Sun, 11 Jun 2023 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php8%E6%96%B0%E7%89%B9%E6%80%A7-%E6%B3%A8%E8%A7%A3/</guid>
      <description>PHP 8 新特性之注解功能 注解概览 注解功能提供了代码中的声明部分都可以添加结构化、机器可读的元数据的能力， 注解的目标可以是类、方法、函数、参数、属性、类常量。 通过 反射 API 可在运行时获取注解所定义的元数据。 因此注解可以成为直接嵌入代码的配置式语言。
通过注解的使用，在应用中实现功能、使用功能可以相互解耦。 某种程度上讲，它可以和接口（interface）与其实现（implementation）相比较。 但接口与实现是代码相关的，注解则与声明额外信息和配置相关。 接口可以通过类来实现，而注解也可以声明到方法、函数、参数、属性、类常量中。 因此它们比接口更灵活。
注解使用的一个简单例子：将接口（interface）的可选方法改用注解实现。 我们假设接口 ActionHandler 代表了应用的一个操作： 部分 action handler 的实现需要 setup，部分不需要。 我们可以使用注解，而不用要求所有类必须实现 ActionHandler 接口并实现 setUp() 方法。 因此带来一个好处——可以多次使用注解。
示例 #1 用注解实现接口的可选方法
&amp;lt;?php interface ActionHandler { public function execute(); } #[Attribute] class SetUp {} class CopyFile implements ActionHandler { public string $fileName; public string $targetDirectory; #[SetUp] public function fileExists() { if (!file_exists($this-&amp;gt;fileName)) { throw new RuntimeException(&amp;#34;File does not exist&amp;#34;); } } #[SetUp] public function targetDirectoryExists() { if (!</description>
    </item>
    
    <item>
      <title>Consul注册中心</title>
      <link>https://blog.leanku.com/post/microservice/consul%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83/</link>
      <pubDate>Thu, 01 Jun 2023 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/microservice/consul%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83/</guid>
      <description>Consul注册中心 CAP原理 一致性（Consistency） 所有节点在同一时间具有相同的数据 可用性（Availablility） 保证每个请求不管或者失败都有响应 分区容错（Partition tolerance） 系统中任意数据的丢失或失败不会影响系统的继续运作 Consul 介绍 方便部署 采用Raft算法实现，有服务发现，key/value存储，可以做配置中心使用。有健康检查，同事提供了web管理页面 Consul角色 -dev 开发环境下的启动命令，提供基本的服务 -client 客户端，无状态的，将http和dns请求转发到服务端集群 -server 服务端，保存配置信息，可以搭建高可用的集群 Consul 内部端口 端口 说明 TCP/8300 8300端口用于服务器节点。客户端通过该端口RPC协议调用服务端接口。 TCP/UDP/8301 8301端口用于单个数据中心所有节点之间的相互通信，即对LAN池信息的同步。它使得整个数据中心能够自动发现服务器地址，分布式检测节点故障，事件广播 TCP/UDP/8302 8302端口用于单个或多个数据中心之间的服务器节点的信息同步。即对WAN池信息的同步。它针对互联网的高延迟进行了优化，能够实现跨数据中心请求。 8500 8500端口基于HTTP协议，用于API接口或WEB UI访问。 8600 8600端口作为DNS服务器，它使得我们可以通过节点名查询节点的信息。 Consul 工作原理 Consul 安装 下载地址
或者docker安装
docker run -d --name=consul -p 8500:8500 consul:1.15.4 agent -dev -client 0.0.0.0 -ui 安装完成后，命令行输入consul 检查 consul 是否可用
Consul支持web ui界面。UI可用于查看所有服务和节点，查看所有运行状况检查及其当前状态，以及读取和设置键/值数据。 用户界面自动支持多数据中心。要设置自带的UI，请使用-ui参数启动Consul代理：
consul agent -ui UI可以在与HTTP API相同的端口上的/ui路径中使用。 默认情况下，这是http://localhost:8500/ui。
注册个服务 使用HTTP API 注册个服务，使用[接口API](https://www.consul.io/api/agent/service.html API)调用</description>
    </item>
    
    <item>
      <title>常用Docker镜像</title>
      <link>https://blog.leanku.com/post/%E5%B8%B8%E7%94%A8docker%E9%95%9C%E5%83%8F/</link>
      <pubDate>Thu, 01 Jun 2023 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/%E5%B8%B8%E7%94%A8docker%E9%95%9C%E5%83%8F/</guid>
      <description>常用Docker镜像 php-msf-docker docker run --privileged --restart=always -it -d --hostname=php-msf --name=php-msf-docker -p 2202:22 -p 80:80 -p 8000:8000 -p 9501:9501 -v D:\Develop\Docker\WWW:/php-msf/data/www leanku/php-msf-docker Rabbitmq docker run -d --name rabbitmq -e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest -p 15672:15672 -p 5672:5672 rabbitmq:3.8-management MySQL docker run -p 13306:3306 --name mysql5.7 -e MYSQL_ROOT_PASSWORD=root -v D:\Develop\Docker\app-mysql:/var/lib/mysql -d mysql:5.7 Redis docker run --name redis -p 6379:6379 -d redis redis-server --appendonly yes Elasticsearch docker run -d --name es -p 9200:9200 -p 9300:9300 -e &amp;#34;discovery.</description>
    </item>
    
    <item>
      <title>Redis事务和锁</title>
      <link>https://blog.leanku.com/post/redis/redis%E4%BA%8B%E5%8A%A1%E5%92%8C%E9%94%81/</link>
      <pubDate>Sun, 28 May 2023 22:33:45 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/redis/redis%E4%BA%8B%E5%8A%A1%E5%92%8C%E9%94%81/</guid>
      <description>Redis事务 事务是指一个完整的动作，要么全部执行，要么什么也没有做。Redis 事务不是严格意义上的事务，只是用于帮助用户在一个步骤中执行多个命令。单个 Redis 命令的执行是原子性的，但 Redis 没有在事务上增加任何维持原子性的机制，所以 Redis 事务的执行并不是原子性的。
Redis 事务可以理解为一个打包的批量执行脚本，但批量指令并非原子化的操作，中间某条指令的失败不会导致前面已做指令的回滚，也不会造成后续的指令不做。
Redis 的事务不是原子性，但是Redi执行每一个命令都是原子性的
举例：INCR在redis中是自增，即使多个客户端对同一个密钥发出INCR，也永远不会进入竞争状态。例如，客户机1读取“10”，客户机2同时读取“10”，两者都增加到11，并将新值设置为11，这样的情况永远不会发生。最终的值将始终是12。
这个案例是官网提出来的：https://redis.io/docs/data-types/tutorial/
事务一般都是为原子性而生，既然Redis事务没有原子性，那他存在的意义是什么？
redis事务的主要作用就是串联多个命令防止 别的命令插队。
官网介绍：https://redis.com.cn/redis-transaction.html
Redis事务 - 基本使用 Redis 在形式上看起来也差不多，MULTI、EXEC、DISCARD这三个指令构成了 redis 事务处理的基础：
MULTI：用来组装一个事务，从输入Multi命令开始，输入的命令都会依次进入命令队列中，但不会执行，直到输入Exec后，redis会将之前的命令依次执行。
EXEC：用来执行一个事务
DISCARD：用来取消一个事务
所有的指令在 exec 之前不执行，而是缓存在服务器的一个事务队列中，服务器一旦收到 exec 指令，才开执行整个事务队列，执行完毕后一次性返回所有指令的运行结果。因为 Redis 的单线程特性，不用担心自己在执行队列的时候被其它指令打搅，可以保证他们能得到的有顺序的执行。
取消事务，放弃执行事务块内的所有命令。
组队中某个命令出现了错误报告，执行时整个队列中所有的命令都会被取消。
命令组队的过程中没有问题，执行中出现了错误会导致部分成功部分失败。
悲观锁&amp;amp;乐观锁 悲观锁（Pessimistic Lock），顾名思义，就是很悲观，每次去拿数据的时候都认为别人会修改，所以每次在拿数据的时候都会上锁，这样别人拿到这个数据就会block直到它拿到锁。传统的关系型数据库里面就用到了很多这种锁机制，比如行锁、表锁、读锁、写锁等，都是在做操作之前先上锁。
乐观锁（Optimistic Lock），顾名思义，就是很乐观，每次去那数据的时候都认为别人不会修改，所以不会上锁，但是在修改的时候会判断一下在此期间别人有没有去更新这个数据，可以使用版本号等机制。乐观锁适用于多读的应用类型，这样可以提高吞吐量。redis就是使用这种check-and-set机制实现事务的。
watch监听 WATCH：在执行multi之前，先执行watch key1 [key2 …]，可以监视一个或者多个key，若在事务的exec命令之前这些key对应的值被其他命令所改动了，那么事务中所有命令都将被打断，即事务所有操作将被取消执行。
unwatch：取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后， EXEC 命令或 DISCARD 命令先被执行了的话，那么就不需要再执行UNWATCH 了。
简单示例秒杀场景 &amp;lt;?php // 连接Redis $redis = new Redis(); $redis-&amp;gt;connect(&amp;#39;127.0.0.1&amp;#39;,6379); $redis-&amp;gt;watch(&amp;#39;sales&amp;#39;); $sales = $redis-&amp;gt;get(&amp;#39;sales&amp;#39;); $store = 10; if($sales &amp;gt;= $store){ exit(&amp;#39;结束&amp;#39;); } // 事务 $redis-&amp;gt;multi(); $redis-&amp;gt;incr(&amp;#39;sales&amp;#39;); $res = $redis-&amp;gt;exec(); if($res){ // 库存更新.</description>
    </item>
    
    <item>
      <title>JSON Web Token</title>
      <link>https://blog.leanku.com/post/json-web-token/</link>
      <pubDate>Fri, 12 May 2023 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/json-web-token/</guid>
      <description>JSON Web Token（缩写 JWT）是目前最流行的跨域认证解决方案，本文介绍它的原理和用法。 一、跨域认证的问题 互联网服务离不开用户认证。一般流程是下面这样。
1、用户向服务器发送用户名和密码。
2、服务器验证通过后，在当前对话（session）里面保存相关数据，比如用户角色、登录时间等等。
3、服务器向用户返回一个 session_id，写入用户的 Cookie。
4、用户随后的每一次请求，都会通过 Cookie，将 session_id 传回服务器。
5、服务器收到 session_id，找到前期保存的数据，由此得知用户的身份。
这种模式的问题在于，扩展性（scaling）不好。单机当然没有问题，如果是服务器集群，或者是跨域的服务导向架构，就要求 session 数据共享，每台服务器都能够读取 session。
举例来说，A 网站和 B 网站是同一家公司的关联服务。现在要求，用户只要在其中一个网站登录，再访问另一个网站就会自动登录，请问怎么实现？
一种解决方案是 session 数据持久化，写入数据库或别的持久层。各种服务收到请求后，都向持久层请求数据。这种方案的优点是架构清晰，缺点是工程量比较大。另外，持久层万一挂了，就会单点失败。
另一种方案是服务器索性不保存 session 数据了，所有数据都保存在客户端，每次请求都发回服务器。JWT 就是这种方案的一个代表。
二、JWT 的原理 JWT 的原理是，服务器认证以后，生成一个 JSON 对象，发回给用户，就像下面这样。
{ &amp;ldquo;姓名&amp;rdquo;: &amp;ldquo;张三&amp;rdquo;, &amp;ldquo;角色&amp;rdquo;: &amp;ldquo;管理员&amp;rdquo;, &amp;ldquo;到期时间&amp;rdquo;: &amp;ldquo;2018年7月1日0点0分&amp;rdquo; } 以后，用户与服务端通信的时候，都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据，服务器在生成这个对象的时候，会加上签名（详见后文）。
服务器就不保存任何 session 数据了，也就是说，服务器变成无状态了，从而比较容易实现扩展。
三、JWT 的数据结构 实际的 JWT 大概就像下面这样。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9. TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
它是一个很长的字符串，中间用点（.）分隔成三个部分。注意，JWT 内部是没有换行的，这里只是为了便于展示，将它写成了几行。
JWT 的三个部分依次如下。
Header（头部） Payload（负载） Signature（签名） 写成一行，就是下面的样子。
Header.Payload.Signature
下面依次介绍这三个部分。</description>
    </item>
    
    <item>
      <title>MFA</title>
      <link>https://blog.leanku.com/post/safety/mfa/</link>
      <pubDate>Fri, 12 May 2023 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/safety/mfa/</guid>
      <description>MFA 一、MFA 是什么 MFA（Multi-Factor Authentication，多因素认证） 是一种提高账户安全性的认证方式。 它要求用户在登录或进行敏感操作时提供 多种不同类别的验证因素，从而增强安全性。
通常 MFA 包含三类因素：
因素类型 描述 示例 知识因素（Something you know） 用户知道的信息 密码、PIN 持有因素（Something you have） 用户拥有的物品 手机验证码（OTP）、硬件密钥 固有因素（Something you are） 用户自身的特征 指纹、面部识别、虹膜识别 核心理念：仅凭密码不安全，增加第二甚至第三因素可以有效防止账号被盗。
二、常见应用场景 金融系统
登录网银或支付系统时，需要输入密码 + 手机短信验证码。
企业内部 SSO / VPN 登录
员工登录内部系统时，需要密码 + 动态令牌或硬件钥匙。
云服务 / SaaS 平台
如 GitHub、Google、AWS 等，用户可启用 MFA 提高账户安全。
敏感操作验证
修改密码、提现或支付等操作，需要额外的 MFA 验证。
三、MFA 的典型流程（以 TOTP 为例） 绑定 MFA
用户登录后扫描二维码绑定 MFA（生成密钥），服务器存储密钥。 生成动态验证码
用户通过 App（Google Authenticator、Authy）生成 6 位一次性验证码。 登录验证</description>
    </item>
    
    <item>
      <title>OAuth 2.0</title>
      <link>https://blog.leanku.com/post/safety/oauth2/</link>
      <pubDate>Fri, 12 May 2023 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/safety/oauth2/</guid>
      <description>OAuth 2.0 一、OAuth2.0 是什么 OAuth 2.0 是一种开放标准的授权协议，用于在不暴露账号密码的情况下，让用户授权第三方应用访问其受保护的资源。
它主要解决的问题是：如何安全地委托访问权限。
核心概念：
角色 说明 资源所有者（Resource Owner） 用户或数据所有者 客户端（Client） 第三方应用，需要访问资源 授权服务器（Authorization Server） 颁发令牌的服务器，负责验证用户身份并授权 资源服务器（Resource Server） 存储用户受保护资源的服务器，验证令牌后提供数据 二、 常用场景 第三方登录（Social Login）
用户使用微信、GitHub、Google 登录你的站点，后端获取 Access Token 调用接口获取用户信息。
开放 API / 平台化
向合作伙伴提供 API，使用 OAuth 2.0 控制访问权限和作用域。
微服务内部接口调用
服务 A 调用服务 B 的接口，通过 Client Credentials 模式获取 Token，避免硬编码密码。
企业内部 SSO（单点登录）
多系统统一认证，用户在登录一次后，访问其他系统不需要重复登录。
前后端分离应用（SPA / Mobile App）
前端获取授权码，换取 Access Token，安全访问 API，密码不在前端传递。
三、OAuth 2.0 主要流程 以 授权码模式（Authorization Code Grant） 为例：
请求授权：客户端引导用户跳转到授权服务器，传入 client_id、redirect_uri、scope。</description>
    </item>
    
    <item>
      <title>Brew 使用指南</title>
      <link>https://blog.leanku.com/post/brew%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Thu, 11 May 2023 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/brew%E4%BD%BF%E7%94%A8/</guid>
      <description>Brew 使用指南 一、什么是 brew？ 全程：Homebrew
macOS（或 Linux）软件包管理器。它可以让你轻松地安装、更新、卸载软件，解决软件依赖关系，你不再需要手动下载、拖拽安装或处理复杂的编译选项。
Homebrew 会将软件包安装到独立目录，并将其文件软链接至 /opt/homebrew 。
brew官网
二、安装 Homebrew 在终端（Terminal）中执行以下命令：
/bin/bash -c &amp;#34;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)&amp;#34; 安装完成后，运行以下命令确保 Brew 工作正常：
brew doctor 三、基础使用命令 1. 安装软件 安装命令行工具（Formula）： brew install &amp;lt;formula_name&amp;gt; # 示例：安装 wget, tree, node brew install wget tree node 安装图形界面应用（Cask） brew install --cask &amp;lt;cask_name&amp;gt; # 示例：安装 Chrome, VS Code, Spotify brew install --cask google-chrome visual-studio-code spotify 2. 查询软件 搜索软件（不确定完整包名时非常有用）： brew search &amp;lt;keyword&amp;gt; # 示例：搜索所有与 python 相关的包 brew search python 查看已安装的软件列表： brew list # 列出所有通过 Formula 安装的命令行工具 brew list --cask # 列出所有通过 Cask 安装的应用程序 查看某个软件的信息： brew info &amp;lt;formula_name&amp;gt; brew info --cask &amp;lt;cask_name&amp;gt; 3.</description>
    </item>
    
    <item>
      <title>PHP 8 新特性</title>
      <link>https://blog.leanku.com/post/php8%E6%96%B0%E7%89%B9%E6%80%A7/</link>
      <pubDate>Thu, 11 May 2023 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php8%E6%96%B0%E7%89%B9%E6%80%A7/</guid>
      <description>PHP 8 新特性 命名参数（8.0） 新增命名参数的功能:
在函数或方法调用时，可通过参数名来指定参数的值，而不仅仅依赖参数的位置
从 PHP 8.0.0 开始，函数参数列表可以包含一个尾部的逗号，这个逗号将被忽略。这在参数列表较长或包含较长的变量名的情况下特别有用，这样可以方便地垂直列出参数。
&amp;lt;?php function takes_many_args( $first_arg, $second_arg, $again = &amp;#39;a default string&amp;#39;, // 在 8.0.0 之前，这个尾部的逗号是不允许的。 ){ // ... } z takes_many_args(1, 2); //按照参数顺序传参 takes_many_args(first_arg:1, second_arg:2); //指定参数，不分顺序 // 类也可以使用命名参数，假设Demo类构造函数有$first_arg，$second_arg,两个参数，有takes_many_args方法 $demo = new Demo(first_arg:1, second_arg:2); $demo-&amp;gt;takes_many_args(first_arg:1, second_arg:2); // 不能用位置的参数和命名的参数一起 // 可选参数必须在必选参数后面 例如上面的$again ?&amp;gt; 注解（Attributes）（8.0） 新增注解的功能。 此篇单独介绍
构造器属性提升（Constructor Property Promotion）（8.0） 新增构造器属性提升功能 在构造函数中声明类的属性）。
构造器的参数也可以相应提升为类的属性。 构造器的参数赋值给类属性的行为很普遍，否则无法操作。 而构造器提升的功能则为这种场景提供了便利。
&amp;lt;?php class Point { protected int $x; protected int $y; public function __construct(int $x, int $y = 0) { $this-&amp;gt;x = $x; $this-&amp;gt;y = $y; } } // 两个参数都传入 $p1 = new Point(4, 5); // 仅传入必填的参数。 $y 会默认取值 0。 $p2 = new Point(4); // 使用命名参数（PHP 8.</description>
    </item>
    
    <item>
      <title>项目规范指南</title>
      <link>https://blog.leanku.com/post/project-management/%E9%A1%B9%E7%9B%AE%E8%A7%84%E8%8C%83%E6%8C%87%E5%8D%97/</link>
      <pubDate>Sat, 01 Apr 2023 21:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/project-management/%E9%A1%B9%E7%9B%AE%E8%A7%84%E8%8C%83%E6%8C%87%E5%8D%97/</guid>
      <description>项目规范指南 本规范适用于团队/开源项目的版本管理，目标是做到：规范化、可追踪、可溯源。
1. 版本管理 (Versioning) 遵循 语义化版本规范 (Semantic Versioning, SemVer 2.0.0) MAJOR.MINOR.PATCH MAJOR：主版本号，不兼容的 API 改动
MINOR：次版本号，新增功能（向下兼容）
PATCH：修订号，修复 bug（向下兼容）
先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面，作为延伸。 预发布版本：1.0.0-alpha.1、2.0.0-rc.1 参考语义化版本规范：https://semver.org/lang/zh-CN/
2. LICENSE (MIT) 作用：MIT，明确版权
规范 项目必须包含 LICENSE 文件，放置于项目根目录。
推荐使用 MIT License（宽松、常用，几乎所有开源项目可接受）。
文件名统一：LICENSE（不要写成 LICENSE.txt 或 license.md）。
在 README.md 中需明确说明 License 类型。
示例 LICENSE 文件（MIT）：
MIT License Copyright (c) 2025 Your Name Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &amp;#34;Software&amp;#34;), to deal .</description>
    </item>
    
    <item>
      <title>PHP8新特性之match表达式</title>
      <link>https://blog.leanku.com/post/php8%E6%96%B0%E7%89%B9%E6%80%A7%E4%B9%8Bmatch%E8%A1%A8%E8%BE%BE%E5%BC%8F/</link>
      <pubDate>Tue, 14 Mar 2023 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php8%E6%96%B0%E7%89%B9%E6%80%A7%E4%B9%8Bmatch%E8%A1%A8%E8%BE%BE%E5%BC%8F/</guid>
      <description>PHP8 alpha2发布了，最近引入了一个新的关键字：match, 这个关键字的作用跟switch有点类似。
虽然我一般对语法糖无感，但这个我觉得还是有点意思，match这个词也挺好看，那么它是干啥的呢？
在以前我们可能会经常使用switch做值转换类的工作，类似:
switch ($input) { case &amp;#34;true&amp;#34;: $result = 1; break; case &amp;#34;false&amp;#34;: $result = 0; break; case &amp;#34;null&amp;#34;: $result = NULL; break; } (当然，有的同学会说，谁会这么写，用个数组转换不行么？ 拜托，这是举例啊，数组也只能数字键和整数啊，万一key是需要其他表达式呢，万一你要多个key对应一个值呢，对吧？)
那么如果使用match关键字呢，可以变成类似:
$result = match($input) { &amp;#34;true&amp;#34; =&amp;gt; 1, &amp;#34;false&amp;#34; =&amp;gt; 0, &amp;#34;null&amp;#34; =&amp;gt; NULL, }; 相比switch， match会直接返回值，可以直接赋值给$result了。
并且，类似switch的多个case一个block一样，match的多个条件也可以写在一起，比如:
$result = match($input) { &amp;#34;true&amp;#34;, &amp;#34;on&amp;#34; =&amp;gt; 1, &amp;#34;false&amp;#34;, &amp;#34;off&amp;#34; =&amp;gt; 0, &amp;#34;null&amp;#34;, &amp;#34;empty&amp;#34;, &amp;#34;NaN&amp;#34; =&amp;gt; NULL, }; 需要注意的和switch不太一样的是，以前我们用switch可能会经常遇到这种诡异的问题:
$input = &amp;#34;2 person&amp;#34;; switch ($input) { case 2: echo &amp;#34;bad&amp;#34;; break; } 你会发现，bad竟然被输出了，这是因为switch使用了宽松比较(==)。match就不会有这个问题了, 它使用的是严格比较(===)，就是值和类型都要完全相等。</description>
    </item>
    
    <item>
      <title>B&#43;Tree</title>
      <link>https://blog.leanku.com/post/data-structure/b&#43;tree/</link>
      <pubDate>Sun, 12 Mar 2023 22:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/data-structure/b&#43;tree/</guid>
      <description>B+Tree B+Tree 是一种平衡多路搜索树，广泛应用于数据库和文件系统等领域，其核心优势在于优化磁盘存储效率和查询性能.
MySQL的InnoDB存储引擎使用的索引结构就是 B+树，它是B树的一个重要变种。
1. 从B树到B+树 B树：一种自平衡的、多路的搜索树。它允许每个节点有多个子节点（多于两个，所以不是二叉树）。
B+树：在B树基础上优化而来的数据结构，是现代数据库系统中事实上的标准索引结构。
MySQL的InnoDB使用的正是 B+树。
2. 为什么数据库需要B+树？ 要理解B+树，必须先理解它的设计目标。数据库的数据存储在磁盘上，磁盘I/O（读写磁盘）的速度比内存访问慢几个数量级。因此，数据库索引的核心目标是：最大限度地减少磁盘I/O次数。
B+树通过以下方式完美地实现了这一目标：
矮胖：与“瘦高”的二叉树相比，B+树每个节点可以存储非常多的键，这使得树的层级非常少（通常只有3-4层），从而保证在亿万级数据量下，查找任何一条记录最多只需要3-4次磁盘I/O。
顺序访问友好：B+树非常适合磁盘的预读特性，能够高效地进行范围查询。
3. B+树的详细结构 它由两种类型的节点组成：内部节点 和 叶子节点。
内部节点（非叶子节点） 作用：仅充当导航目录。
存储内容：只存储键值（索引列的值）和指向子节点的指针。
不存储：实际行的数据。
叶子节点 作用：存储实际的数据。
存储内容：
在 主键索引（聚簇索引） 中：叶子节点存储的就是完整的行数据。
在 辅助索引（二级索引） 中：叶子节点存储的是该索引的键值和对应的主键值。
关键特性：所有叶子节点通过指针相互连接，形成了一个有序的双向链表。这是B+树与B树的一个核心区别。
4. B+树的核心特性与优势（对比B树） 特性 B树 B+树 B+树的优势 数据存储位置 内部节点和叶子节点都存储数据。 只有叶子节点存储数据，内部节点仅为索引。 更“矮胖”的树。因为内部节点不存数据，所以一个节点能容纳的键更多，扇出（子节点数）更大，树高更低，I/O次数更少。 叶子节点链接 叶子节点之间没有链接。 叶子节点通过双向链表连接。 无敌的范围查询。要查询age BETWEEN 20 AND 30的所有记录，B+树只需找到20，然后顺着链表遍历即可。B树则需要不断地在树的中上层和下层之间来回跳跃，性能极差。 扫描和全表遍历 需要对整棵树进行复杂的中序遍历。 只需遍历底层的链表即可获得所有数据，非常高效。 对数据仓库、聚合查询等场景非常友好。 查询稳定性 由于数据可能在内部节点找到，查询时间不稳定。 任何查询都必须走到叶子节点，查询时间非常稳定。 保证了可预测的性能。 5. 在MySQL中的具体体现：聚簇索引 在MySQL InnoDB中，主键索引就是一颗B+树，并且这棵B+树的叶子节点直接存储了完整的行数据。这种索引组织表的方式被称为“聚簇索引”。
表数据文件本身就是按B+树结构组织的一个索引文件。
如果你没有定义主键，InnoDB会选择一个唯一的非空索引代替，如果没有这样的索引，它会隐式地定义一个主键。
辅助索引（二级索引） 也是一颗B+树，但它的叶子节点存储的是该索引列的值和对应记录的主键值。当通过二级索引查找数据时，需要先找到主键，再回到主键索引（聚簇索引）中查找完整数据，这个过程称为“回表”。</description>
    </item>
    
    <item>
      <title>常用算法的PHP实现</title>
      <link>https://blog.leanku.com/post/algorithm/%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95%E7%9A%84php%E5%AE%9E%E7%8E%B0/</link>
      <pubDate>Sun, 12 Mar 2023 22:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/algorithm/%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95%E7%9A%84php%E5%AE%9E%E7%8E%B0/</guid>
      <description>常用算法的PHP实现 1. 快速排序 (Quick Sort) &amp;lt;?php function quickSort($arr) { if (count($arr) &amp;lt;= 1) { return $arr; } $pivot = $arr[0]; $left = $right = []; for ($i = 1; $i &amp;lt; count($arr); $i++) { if ($arr[$i] &amp;lt; $pivot) { $left[] = $arr[$i]; } else { $right[] = $arr[$i]; } } return array_merge(quickSort($left), [$pivot], quickSort($right)); } // 测试 $numbers = [64, 34, 25, 12, 22, 11, 90]; echo &amp;#34;原始数组: &amp;#34; . implode(&amp;#39;, &amp;#39;, $numbers) .</description>
    </item>
    
    <item>
      <title>数据结构</title>
      <link>https://blog.leanku.com/post/data-structure/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</link>
      <pubDate>Sun, 12 Mar 2023 22:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/data-structure/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</guid>
      <description>数据结构 一、说明 数据结构是计算机科学中一个非常基础和核心的概念，它对于编程、算法设计和软件工程都至关重要。
简单来说，数据结构是一种在计算机中组织、管理和存储数据的方式，目的是为了实现高效地访问和修改。
可以把它想象成一个储物系统：
把一堆书随便堆在地上，这是一种“存储”，但找起来非常困难。
使用一个带标签的书架，把书分门别类地放好，找书、放书就高效得多。
这个“书架”以及“如何给书分类、摆放”的规则，就是一种“数据结构”。
为什么数据结构如此重要？ 选择合适的数据结构可以极大地影响程序的性能和效率。一个精心选择的数据结构可以让操作（如搜索、插入、删除）变得非常快；而错误的选择则可能导致程序运行缓慢甚至崩溃。
二、 常见的数据结构分类和类型 数据结构主要可以分为两大类：线性结构和非线性结构。
一、 线性数据结构 元素按顺序排列，形成一条“线”。
数组：在内存中连续存储相同类型的元素。通过索引可以快速访问任意元素。
优点：随机访问速度快。
缺点：大小固定（在某些语言中），插入和删除元素效率低。
链表：由一系列节点组成，每个节点包含数据和指向下一个节点的指针。
优点：大小动态，插入和删除元素效率高。
缺点：不能随机访问，必须从头开始遍历。
栈：一种后进先出的结构，像一摞盘子。只能在顶部进行添加（压栈）和移除（弹栈）操作。
应用：函数调用栈、撤销操作、表达式求值。 队列：一种先进先出的结构，像排队一样。从队尾添加元素，从队首移除元素。
应用：任务调度、消息队列、广度优先搜索。
变种：双端队列、优先队列。
二、 非线性数据结构 元素之间不是简单的前后关系，可能存在多个连接。
树：一种分层结构，由节点和边组成。最顶端的节点叫根节点。
二叉树：每个节点最多有两个子节点。
二叉搜索树：左子树所有节点的值小于根节点，右子树所有节点的值大于根节点。这使得搜索非常高效。
应用：文件系统、数据库索引、决策树。
图：由顶点和连接顶点的边组成。可以表示任意复杂的关系网络。
应用：社交网络、地图导航、网络路由。 哈希表：通过一个哈希函数将键映射到一个位置来访问记录，以实现极快的查找速度。
优点：在平均情况下，插入、删除和查找的时间复杂度都是 O(1)。
应用：字典、集合、缓存。
三、核心操作与算法 对于每种数据结构，我们通常关心以下几个核心操作的效率：
访问
搜索
插入
删除
这些操作的效率通常用 大O表示法 来衡量，它描述了算法时间或空间复杂度随数据规模增长的趋势。
四、作用 数据结构是构建高效算法的基石。学习数据结构能帮助你：
写出更高效的代码：理解不同操作的代价。
解决复杂问题：很多复杂问题本质上就是数据组织和处理的问题。
更好地理解计算机系统：从内存管理到数据库，底层都离不开数据结构。</description>
    </item>
    
    <item>
      <title>算法</title>
      <link>https://blog.leanku.com/post/algorithm/%E7%AE%97%E6%B3%95/</link>
      <pubDate>Sun, 12 Mar 2023 22:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/algorithm/%E7%AE%97%E6%B3%95/</guid>
      <description>算法 算法是计算机科学的核心基础之一，简单来说它是解决特定问题的一系列清晰指令。无论是简单的计算还是复杂的人工智能任务，都离不开算法。
1. 算法是什么？ 你可以把算法想象成一个菜谱：
输入：食材（数据）
处理步骤：清晰的烹饪步骤（算法逻辑）
输出：一道菜肴（结果）
它的核心目标是用最优的方式（最快、最省资源）解决问题。
2. 算法的核心特性 一个“好”的算法通常具备以下特点：
正确性：必须能正确解决问题。
高效性：执行时间和占用空间要尽可能少。
明确性：每一步都必须清晰、无歧义。
有限性：必须在有限的步骤内结束。
3. 常见的算法类别与实例 算法种类繁多，以下是一些主要类别和经典例子：
排序算法
快速排序：采用“分治”思想，选择一个基准元素，将数组分成左右两部分，效率很高。
归并排序：也是“分治”思想，先将数组不断拆分，再合并排序，稳定且高效。
冒泡排序：反复交换相邻的逆序元素，简单但效率低。
搜索算法
二分查找：在已排序的数组中，每次比较都能排除一半的数据，效率极高（O(log n)）。
深度优先搜索和广度优先搜索：用于遍历或搜索树和图结构，是许多复杂算法的基础。
图算法
Dijkstra算法：用于寻找图中两点之间的最短路径。
A*搜索算法：在Dijkstra基础上加入了启发式函数，是路径规划和游戏AI的基石。
动态规划
用于解决具有重叠子问题和最优子结构的复杂问题（如斐波那契数列、背包问题），通过存储中间结果来避免重复计算。 机器学习算法（AI领域）
线性回归/逻辑回归：用于预测和分类。
决策树/随机森林：通过树形结构做决策。
支持向量机：寻找最佳分类边界。
神经网络：模仿人脑神经元，是深度学习的核心。
4. 如何衡量算法的好坏？—— “复杂度分析” 我们使用 “大O表示法” 来描述算法的效率，主要看：
时间复杂度：随着数据规模增大，算法运行时间的增长趋势。例如 O(1), O(log n), O(n), O(n²)。
空间复杂度：随着数据规模增大，算法占用内存空间的增长趋势。
5. 为什么算法如此重要？ 效率：好的算法能处理海量数据，差的算法在大数据面前寸步难行。
性能：直接影响软件和应用的反应速度与用户体验。
解决问题的基础：是开发任何软件系统、进行科学计算和实现人工智能的基石。
面试核心：是国内外大型科技公司技术面试的必考内容。</description>
    </item>
    
    <item>
      <title>我步入丛林</title>
      <link>https://blog.leanku.com/post/life/%E6%88%91%E6%AD%A5%E5%85%A5%E4%B8%9B%E6%9E%97/</link>
      <pubDate>Sun, 12 Mar 2023 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/life/%E6%88%91%E6%AD%A5%E5%85%A5%E4%B8%9B%E6%9E%97/</guid>
      <description>我步入丛林，因为我希望生活的有意义，我希望活的深刻。汲取生命中所有的精华，把非生命的一切都击溃，以免让我在生命终结时，发现自己从来没有活过！
I went to the woods because I wanted to live deliberately. I wanted to live deep and suck out all the marrow of life!To put to rout allthat was not life, and not, when I had come to die, discover that I had not lived.
推荐电影《死亡诗社》
原文出自 《瓦尔登湖》-亨利·戴维·梭罗</description>
    </item>
    
    <item>
      <title>记录一些句子</title>
      <link>https://blog.leanku.com/post/life/%E8%AE%B0%E5%BD%95%E4%B8%80%E4%BA%9B%E5%8F%A5%E5%AD%90/</link>
      <pubDate>Sun, 12 Mar 2023 13:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/life/%E8%AE%B0%E5%BD%95%E4%B8%80%E4%BA%9B%E5%8F%A5%E5%AD%90/</guid>
      <description>记录一些句子 你是否也曾被一句话深深触动？还记得吗？
生活 刀枪入库，马放南山。- 清代.钱彩.《说岳全传》
先去你的塞外,再回我的江南。 -金庸.《天龙八部》
小舟从此逝，江海寄余生。 - 《临江仙·夜饮东坡醒复醉》
行到水穷处，坐看云起时。 - 《终南别业》
道 上善若水，水利万物而不争。 - 《道德经》
朝闻道，夕死可矣。 ——《论语·里仁》
天下同归而殊途，一致而百虑。 ——《易经·系辞下》
大方无隅，大器晚成，大音希声，大象无形。 - 《道德经》
为天地立心，为生民立命，为往圣继绝学，为万世开太平。 - 《横渠语录》
相濡以沫，不如相忘于江湖。 - 《庄子》
苟日新，日日新，又日新。 - 《大学》
慎终如始，则无败事。 - 《道德经》
为者常成，行者常至。 - 《晏子春秋》
一念起天涯咫尺，一念灭咫尺天涯。</description>
    </item>
    
    <item>
      <title>docker删除none镜像</title>
      <link>https://blog.leanku.com/post/docker%E5%88%A0%E9%99%A4none%E9%95%9C%E5%83%8F/</link>
      <pubDate>Sat, 11 Mar 2023 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/docker%E5%88%A0%E9%99%A4none%E9%95%9C%E5%83%8F/</guid>
      <description>docker删除none镜像 1、使用git bash进入到docker文件夹
2、查询所有的none镜像
docker images | grep none 3、查询所有的none镜像的id
docker images | grep none | awk &amp;#39;{print $3}&amp;#39; 4、删除所有的none镜像
docker images | grep none | awk &amp;#39;{print $3}&amp;#39; | xargs docker rmi docker none镜像说明 一、有效的 none 镜像 Docker文件系统的组成，docker镜像是由很多 layers组成的，每个 layer之间有父子关系，所有的docker文件系统层默认都存储在/var/lib/docker/graph目录下，docker称之为图层数据库。
最后做一个总结&amp;lt; none&amp;gt;:&amp;lt; none&amp;gt; 镜像是一种中间镜像，我们可以使用docker images -a来看到，他们不会造成硬盘空间占用的问题（因为这是镜像的父层，必须存在的），但是会给我们的判断带来迷惑。
二、无效的 none 镜像 另一种类型的 &amp;lt; none&amp;gt;:&amp;lt; none&amp;gt; 镜像是dangling images ，这种类型会造成磁盘空间占用问题。
像Java和Golang这种编程语言都有一个内存区，这个内存区不会关联任何的代码。这些语言的垃圾回收系统优先回收这块区域的空间，将他返回给堆内存，所以这块内存区对于之后的内存分配是有用的
docker的悬挂(dangling)文件系统与上面的原理类似，他是没有被使用到的并且不会关联任何镜像，因此我们需要一种机制去清理这些悬空镜像。
我们在上文已经提到了有效的&amp;lt; none&amp;gt;镜像，他们是一种中间层，那无效的&amp;lt; none&amp;gt;镜像又是怎么出现的？这些 dangling镜像主要是我们触发 docker build 和 docker pull命令产生的。
使用下面的命令可以清理
docker rmi $(docker images -f &amp;#34;dangling=true&amp;#34; -q) </description>
    </item>
    
    <item>
      <title>php-msf-docker</title>
      <link>https://blog.leanku.com/post/php-msf-docker/</link>
      <pubDate>Sat, 11 Mar 2023 11:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php-msf-docker/</guid>
      <description>php-msf-docker 基于centos:centos7.9.2009镜像制作的php开发环境镜像
主要包含： PHP-8.1.14 redis-5.3.7 swoole-src-5.0.2 nginx-1.21.5 supervisor sshd GitHub地址 : https://hub.docker.com/r/leanku/php-msf-docker
DockerHub地址 : https://hub.docker.com/r/leanku/php-msf-docker
包含扩展 bcmath,Core,ctype,curl,date,dom,exif,fileinfo,filter,ftp,gd,gettext,hash,iconv,intl,json,libxml,mbstring,mysqli,mysqlnd,openssl,pcntl,pcre,PDO,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,Phar,posix,redis,Reflection,session,shmop,SimpleXML,soap,sockets,sodium,SPL,sqlite3,standard,sysvsem,tokenizer,xml,xmlreader,xmlwriter,xsl,zip,zlib,swoole 运行示例 docker run --privileged --restart=always -it -d \ --hostname=php-msf --name=php-msf-docker \ -p 22:22 -p 80:80 -p 3306:3306 -p 8000:8000 -p 9501:9501 \ -v /c/docker/www:/php-msf/data/www \ leanku/php-msf-docker SSH 默认用户：super 密码：123456
ssh super@127.0.0.1 </description>
    </item>
    
    <item>
      <title>行有余力，则以学文</title>
      <link>https://blog.leanku.com/post/life/%E8%A1%8C%E6%9C%89%E4%BD%99%E5%8A%9B%E5%88%99%E4%BB%A5%E5%AD%A6%E6%96%87/</link>
      <pubDate>Thu, 09 Mar 2023 21:04:48 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/life/%E8%A1%8C%E6%9C%89%E4%BD%99%E5%8A%9B%E5%88%99%E4%BB%A5%E5%AD%A6%E6%96%87/</guid>
      <description>子曰：弟子入则孝，出则弟，谨而信，泛爱众，而亲仁，行有余力，则以学文。
孔子说：“弟子们在父母跟前，就孝顺父母；出门在外，顺从师长，言行要谨慎，要诚实可信，寡言少语，要广泛地去爱众人，亲近那些有仁德的人。这样躬行实践之后，还有余力的话，就再去学习文献知识。”
《论语·学而篇》- 孔子</description>
    </item>
    
    <item>
      <title>PHP位运算使用</title>
      <link>https://blog.leanku.com/post/php-%E4%BD%8D%E8%BF%90%E7%AE%97%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Tue, 28 Feb 2023 22:33:45 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/php-%E4%BD%8D%E8%BF%90%E7%AE%97%E4%BD%BF%E7%94%A8/</guid>
      <description>PHP 位运算介绍 位运算符允许对整型数中指定的位进行求值和操作。 以下是官网的一个介绍。
例子 名称 结果 $a &amp;amp; $b And（按位与） 将把 $a 和 $b 中都为 1 的位设为 1。 $a | $b Or（按位或） 将把 $a 和 $b 中任何一个为 1 的位设为 1。 $a ^ $b Xor（按位异或） 将把 $a 和 $b 中一个为 1 另一个为 0 的位设为 1。 ~ $a Not（按位取反） 将 $a 中为 0 的位设为 1，反之亦然。 $a &amp;laquo; $b Shift left（左移） 将 $a 中的位向左移动 $b 次（每一次移动都表示 “乘以 2”）。 $a &amp;raquo; $b Shift right（右移） 将 $a 中的位向右移动 $b 次（每一次移动都表示 “除以 2”）。 详情请点击这里了解。 平常开发需要用位运算吗？ 位运算符都是针对整数的二进制数字形式而进行的。</description>
    </item>
    
    <item>
      <title>Git创建不继承内容的新分支</title>
      <link>https://blog.leanku.com/post/git%E5%88%9B%E5%BB%BA%E4%B8%8D%E7%BB%A7%E6%89%BF%E5%86%85%E5%AE%B9%E7%9A%84%E6%96%B0%E5%88%86%E6%94%AF/</link>
      <pubDate>Sun, 26 Feb 2023 19:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/git%E5%88%9B%E5%BB%BA%E4%B8%8D%E7%BB%A7%E6%89%BF%E5%86%85%E5%AE%B9%E7%9A%84%E6%96%B0%E5%88%86%E6%94%AF/</guid>
      <description>Git创建不继承内容的新分支方法 在 Git 中，想创建一个新的分支，并且不想要当前分支的任何内容（即希望新分支是完全干净的，不包含当前分支的修改或提交），可以按照以下步骤操作：
方法 1：基于远程默认分支（如 main/master）创建新分支 如果你希望新分支是基于远程仓库的默认分支（而不是当前分支），可以这样做： ``` # 1. 确保本地没有未提交的修改（否则会提示你提交或暂存） git status
# 2. 拉取远程最新代码（确保本地默认分支是最新的） git fetch origin # 3. 基于远程默认分支（如 origin/main）创建新分支 git checkout -b 新分支名 origin/main 方法 2：基于某个提交或分支创建全新分支 如果你想基于某个特定的提交（而不是当前分支）创建新分支： ``` # 1. 先切换到目标分支或提交（例如切换到 main 分支） git checkout main
# 2. 拉取最新代码（可选） git pull origin main # 3. 创建并切换到新分支 git checkout -b 新分支名 方法 3：强制创建孤立分支（完全无历史） 如果你想创建一个完全独立的新分支（不继承任何历史）：
在切换分支之前，确保你没有未提交的修改，否则 Git 可能会尝试携带这些修改到新分支：
git status # 提交他们 git add . git commit -m &amp;#34;暂存当前修改&amp;#34; # 或者丢弃它们 git reset --hard # 强制丢弃所有未提交的修改 创建一个完全独立的新分支（不继承任何历史）</description>
    </item>
    
    <item>
      <title>Git历史重置</title>
      <link>https://blog.leanku.com/post/git%E5%8E%86%E5%8F%B2%E9%87%8D%E7%BD%AE/</link>
      <pubDate>Sun, 26 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/git%E5%8E%86%E5%8F%B2%E9%87%8D%E7%BD%AE/</guid>
      <description>Git历史重置 有时候需要克隆github的项目使用，自己进行修改需要提交到自己的代码仓库，但是会包含前仓库的大量提交历史，看起来不方便，就需要清理历史记录并重置为一个全新的提交
新项目（如git clone 的项目） # 进入项目目录 cd template-repo-master # 删除原有的.git目录（如果存在）初始化全新的Git仓库 rm -rf .git git init git add . git commit -m &amp;#34;Initial commit from template&amp;#34; git remote add origin git@github.com:your-username/your-new-repo.git git push -u origin master --force 已经将代码推送到自己的远程仓库 清理历史记录并重置为一个全新的提交 # 1. 克隆你的远程仓库（可选） git clone git@github.com:your-username/your-repo.git cd your-repo # 2.创建孤立分支（全新的历史起点） git checkout --orphan new-branch # 3. 添加所有文件到新分支 git add -A git commit -m &amp;#34;Initial commit (cleaned history)&amp;#34; #4. 删除旧的主分支 git branch -D master # 或 main # 5.</description>
    </item>
    
    <item>
      <title>Git同时配置github和gitee</title>
      <link>https://blog.leanku.com/post/git%E5%90%8C%E6%97%B6%E9%85%8D%E7%BD%AEgithub%E5%92%8Cgitee/</link>
      <pubDate>Sun, 26 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/git%E5%90%8C%E6%97%B6%E9%85%8D%E7%BD%AEgithub%E5%92%8Cgitee/</guid>
      <description>Git同时配置github和gitee 想要同时使用GitHub和Gitee，但是每次输入密码就会很麻烦。为此，本文将介绍 Git 同时配置 github和 gitee 的ssh key #查看git配置 git config --global --list #没配置过的话先配置用户名和邮箱信息 git config --global user.name “username” git config --global user.email “email” #默认没有.ssh目录， ssh-keygen -t rsa -C &amp;#34;xxxxxxx@xx.com&amp;#34; #在windows下会生成.ssh目录 [c盘/用户/用户名/.ssh] 1. 查看ssh文件 cd ~/.ssh** ls 2. 删除之前的.ssh rm -rf id_rsa id_rsa.pub 3. 生成gitee和github 的 SSH Key ssh-keygen -t rsa -C &amp;#34;xxxxxxx@xx.com&amp;#34; -f &amp;#34;id_rsa_github&amp;#34; ssh-keygen -t rsa -C &amp;#34;xxxxxxx@xx.com&amp;#34; -f &amp;#34;id_rsa_gitee&amp;#34; 4. 查看SSH Key cat id_rsa_github.pub** 5. 拷贝 ssh-rsa 开头的 ssh key，然后到github上添加ssh key 6.</description>
    </item>
    
    <item>
      <title>MySQL 运维常用脚本</title>
      <link>https://blog.leanku.com/post/database/mysql-%E8%BF%90%E7%BB%B4%E5%B8%B8%E7%94%A8%E8%84%9A%E6%9C%AC/</link>
      <pubDate>Fri, 03 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/database/mysql-%E8%BF%90%E7%BB%B4%E5%B8%B8%E7%94%A8%E8%84%9A%E6%9C%AC/</guid>
      <description>MySQL 运维常用脚本 1.导出整个数据库 #mysqldump -u 用户名 -p –default-character-set=latin1 数据库名 &amp;gt; 导出的文件名(数据库默认编码是latin1) mysql dump -u wcnc -p smgp_apps_wcnc &amp;gt; wcnc.sql 2.导出一个表 #mysqldump -u 用户名 -p 数据库名 表名&amp;gt; 导出的文件名 mysql dump -u wcnc -p smgp_apps_wcnc users&amp;gt; wcnc_users.sql 3.导出一个数据库结构 mysql dump -u wcnc -p -d –add-drop-table smgp_apps_wcnc &amp;gt;d:wcnc_db.sql #-d 没有数据 –add-drop-table 在每个create语句之前增加一个drop table 4.导入数据库 #A:常用source 命令 #进入mysql数据库控制台， 如 mysql -u root -p mysql&amp;gt;use databasename #然后使用source命令，后面参数为脚本文件(如这里用到的.sql) mysql&amp;gt;source wcnc_db.sql #B:使用mysqldump命令 mysqldump -u username -p dbname &amp;lt; filename.</description>
    </item>
    
    <item>
      <title>Vim 常用命令</title>
      <link>https://blog.leanku.com/post/vim%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E8%AE%B0%E5%BD%95/</link>
      <pubDate>Wed, 01 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/vim%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E8%AE%B0%E5%BD%95/</guid>
      <description>Vim介绍 Vim是一个类似于Vi的著名的功能强大、高度可定制的文本编辑器，在Vi的基础上改进和增加了很多特性。VIM是自由软件。Vim普遍被推崇为类Vi编辑器中最好的一个，事实上真正的劲敌来自Emacs的不同变体。1999 年Emacs被选为Linuxworld文本编辑分类的优胜者，Vim屈居第二。但在2000年2月Vim赢得了Slashdot Beanie的最佳开放源代码文本编辑器大奖，又将Emacs推至二线， 总的来看， Vim和Emacs在文本编辑方面都是非常优秀的。百度百科
使用 vim a.php # 控制屏幕光标的移动，字符、字或行的删除，移动复制某区段，以其它任何模式按esc 即可进宪普通模式 i 在当前光标字符前插入 insert
a 在当前光标字符后插入 append
I 在当前行首插入 Insert
A 在当前行尾插入 Append
o 在下方开一新行，插入 open
O 在上方开一新行，插入 Open
r 替代字符，将当前字符替代为紧跟着输入的字符 replace
R 进入替代模式，将当前及之后的字符都替代为紧跟着输入的字符串，直到按 `` 返回 Normal 模式 Replace
gj 移动到屏幕折行后的下行
gk 移动到屏幕折行后的上行
命令模式是在普通模式下按 : 进入，用于搜索、保存退出等操作。 :w 保存
:w file 另存为文件
:q 退出
:q! 放弃修改退出
:wq 保存修改并退出
移动命令 Vim 的各种移动命令主要是在标准模式下
h 光标左移
j 光标下移
k 光标上移
l 光标右移
0 跳到行首，可以理解为无穷大的</description>
    </item>
    
    <item>
      <title>10分钟带你了解什么是二进制</title>
      <link>https://blog.leanku.com/post/10%E5%88%86%E9%92%9F%E5%B8%A6%E4%BD%A0%E4%BA%86%E8%A7%A3%E4%BB%80%E4%B9%88%E6%98%AF%E4%BA%8C%E8%BF%9B%E5%88%B6/</link>
      <pubDate>Tue, 31 Jan 2023 20:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/10%E5%88%86%E9%92%9F%E5%B8%A6%E4%BD%A0%E4%BA%86%E8%A7%A3%E4%BB%80%E4%B9%88%E6%98%AF%E4%BA%8C%E8%BF%9B%E5%88%B6/</guid>
      <description>二进制 二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2，进位规则是“逢二进一”，借位规则是“借一当二”。 百度百科
世界上有10种人：一种是懂得二进制的，另一种是不懂二进制的
上面这是流传在程序员之间很久的一个冷笑话。
是不是get不到梗的笑点？ 没有关系，看完本文，你再来看这句话就会会心一笑。
回到过去 让我们假设你回到了初中，这时候你情窦初开。喜欢上了临街的小哥哥(小姐姐)，你们俩家的窗户面对面。放寒假的时候，你们约好了某天晚上八点偷偷溜出来约会。但是不能让父母知道，所以你们不能通过打电话方式来通知对方，今晚自己是否能顺利溜出来。为了不让对方白等，你们不得不约定一种新的通信方式。
这种新的通信方式要满足：
安静&amp;ndash;不能让父母听到，能悄无声息自然是最好了 易懂&amp;ndash;对方看到后能立马知道你要表达的信息 因为住的很近，可以从窗户相互看到对方家里，聪明的你立马想到可以用屋子里吊灯的灯光来进行通信。
你们约定到了八点钟
如果我屋子里的灯亮着，代表我可以顺利溜出去
如果我屋子里的灯不亮，代表我无法顺利溜出去
现在你们就可以用屋子里的灯开关，来表达两种状态 开：能出来 关：不能出来
你们可以悄无声息给对方传达信息，这太完美了！
新的问题 不过过了一段时间你们发现了新问题，有时候，8点钟恰好有事情，可能要推迟半小时才能溜出来。有时候，8点钟事情比较多，可能要推迟1小时才能出来。
现在你们有四种信息要传递
今晚8点钟准时出来 今晚不能出来 今晚8点30能出来 今晚9点能出来 但是一盏灯的开关只能表示两种状态，怎么办才好呢？
聪明的你立马想到，可以再加一盏灯啊！你把书桌上的台灯放到窗前 并且更新了之前的通信方式
台灯关着，吊灯关着&amp;ndash;今晚没戏，出不来了 台灯关着，吊灯开着&amp;ndash;今晚8点，不见不散 台灯开着，吊灯关着&amp;ndash;推迟半小时，今晚八点半才能溜出来 台灯开着，吊灯开着&amp;ndash;推迟1小时，今晚9点才能溜出来 哇哦，再一次用自己的聪明才智解决了这个问题。 现在你用两盏灯，来表达四种状态。
一些思考 让我们用符号来重新表述下
我们用数字0表示灯灭
数字1表示灯亮
一盏灯的情况 0 ==&amp;gt; 今晚八点准时出来 1 ==&amp;gt; 今晚八点不能出来 两盏灯的情况 0 0 ==&amp;gt; 今晚没戏，出不来了 0 1 ==&amp;gt; 今晚8点，不见不散 1 0 ==&amp;gt; 推迟半小时，今晚八点半才能溜出来 1 1 ==&amp;gt; 推迟1小时，今晚9点才能溜出来 让我们再来简化一下箭头右边，我们用数字0,1,2,3 分别来代表今晚约会的4种状态
0: 今晚没戏，出不来了 1: 今晚8点，不见不散 2: 推迟半小时，今晚八点半才能溜出来 3: 推迟1小时，今晚9点才能溜出来 现在我们可以把两边都用数字来简化了</description>
    </item>
    
    <item>
      <title>PHP标准输入与输出</title>
      <link>https://blog.leanku.com/post/php%E6%A0%87%E5%87%86%E8%BE%93%E5%85%A5%E4%B8%8E%E8%BE%93%E5%87%BA/</link>
      <pubDate>Wed, 11 Jan 2023 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/php%E6%A0%87%E5%87%86%E8%BE%93%E5%85%A5%E4%B8%8E%E8%BE%93%E5%87%BA/</guid>
      <description>PHP标准输入与输出 一、PHP STDIN、STDOUT、STDERR简介: STDIN、STDOUT、STDERR命令输入输出流，用于向控制台(linux shell终端、windows cmd终端)输入、输出内容，它们默认是已经打开的，可以直接对他们进行读写操作，它们只能在CLI(command-line interface，命令行界面)模式中使用，在Http模式时，它们是未定义的。
而他们的打开副本php://stdin、php://stdout、php://stderr 也无法输出内容到http浏览器，经测试：写入php://stderr的内容将会输入到默认站点的错误日志中，其它两种无任何效果。
STDIN/STDOUT/STDERR简介：原始流流打开副本描述STDINphp://stdin标准输入(standard input)，只读，用于从控制台输入内容；
STDOUTphp://stdout标准输出(standard output)，只写，用于向控制台输出正常信息；
STDERRphp://stderr错误输出(standard error)，只写，用于向控制台输出错误信息；
官方推荐使用常量 STDIN、 STDOUT 和 STDERR 来代替它们手动打开的副本封装器php://stdin、 php://stdout 和 php://stderr。
二、PHP STDIN用法： PHP语言中&amp;quot;STDIN&amp;quot;用于从控制台读取内容，遇到此常量或者通过fopen()函数打开php://stdin脚本将会等待用户输入内容，直到用户按下回车键提交。
新建文件demo.php
&amp;lt;?php echo &amp;#34;请输入内容:&amp;#34;; $input = fgets(STDIN); echo sprintf(&amp;#34;输入的内容为: %s\n&amp;#34;, $input); $handle = fopen(&amp;#39;php://stdin&amp;#39;, &amp;#39;r&amp;#39;); echo &amp;#34;请输入: &amp;#34;; $stdin = fread($handle, 10); //最多读取10个字符 echo sprintf(&amp;#34;输入为: %s\n&amp;#34;, $stdin); fclose($handle); //php demo.php 运行代码，键盘输入123，输出结果如下 //请输入内容:123 //输入的内容为: 123 //请输入: 456 //输入为: 456 三、PHP STDOUT用法： PHP语言中STDOUT用于向控制台输出标准信息；向此常量、或者向fopen()函数打开的php://stdout写入的内容将直接输出到控制台的标准输出；标准输出的内容可以用过&amp;quot;&amp;gt;&amp;ldquo;或者&amp;quot;1&amp;gt;&amp;ldquo;重定向到指定地方，比如文件。
&amp;lt;?php fwrite(STDOUT, &amp;#34;STDOUT写入的正常输出；\n&amp;#34;); $stdout = fopen(&amp;#34;php://stdout&amp;#34;, &amp;#34;w&amp;#34;); fwrite($stdout, &amp;#34;php://stdout写入的正常输出；\n&amp;#34;); fclose($stdout); // php demo.</description>
    </item>
    
    <item>
      <title>服务端基础知识</title>
      <link>https://blog.leanku.com/post/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/</link>
      <pubDate>Sat, 17 Dec 2022 21:46:01 +0800</pubDate>
      
      <guid>https://blog.leanku.com/post/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/</guid>
      <description>OSI七层模型 层 作用 注 应用层 为程序提供服务 规范数据格式 表示层 数据格式转换，加密 翻译 会话层 建立和管理会话 没有指定协议 传输层 管理端到端之间的连接 TCP协议、UDP协议 网络层 IP地址和路由 IP地址、ARP协议 数据链路层 链路管理 MAC地址、帧 物理层 提供传输环境 网线、WiFi TCP/IP四层模型 层 包含 应用层 应用层、表示层、会话层 传输层 传输层 网络层 网络层 数据链路层 数据链路层、物理层 ARP协议 地址解析协议，即ARP（Address Resolution Protocol），是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机，并接收返回消息，以此确定目标的物理地址；收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间，下次请求时直接查询ARP缓存以节约资源。地址解析协议是建立在网络中各个主机互相信任的基础上的，局域网络上的主机可以自主发送ARP应答消息，其他主机收到应答报文时不会检测该报文的真实性就会将其记入本机ARP缓存；由此攻击者就可以向某一主机发送伪ARP应答报文，使其发送的信息无法到达预期的主机或到达错误的主机，这就构成了一个ARP欺骗。ARP命令可用于查询本机ARP缓存中IP地址和MAC地址的对应关系、添加或删除静态对应关系等。相关协议有RARP、代理ARP。NDP用于在IPv6中代替地址解析协议。
TCP/UDP协议 TCP和UDP协议是TCP/IP协议的核心。 TCP 传输协议：TCP 协议是一TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议。其中TCP提供IP环境下的数据可靠传输，它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗说，它是事先为所发送的数据开辟出连接好的通道，然后再进行数据发送；而UDP则不为IP提供可靠性、流控或差错恢复功能。一般来说，TCP对应的是可靠性要求高的应用，而UDP对应的则是可靠性要求低、传输经济的应用
TCP三次握手 所谓的“三次握手”：为了对每次发送的数据量进行跟踪与协商，确保数据段的发送和接收同步，根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系，并建立虚连接。 为了提供可靠的传送，TCP在发送新的数据之前，以特定的顺序将数据包的序号，并需要这些包传送给目标机之后的确认消息。TCP总是用来发送大批量的数据。当应用程序在收到数据后要做出确认时也要用到TCP。
过程 第一次握手：建立连接时，客户端发送syn包（seq=j）到服务器，并进入SYN_SENT状态，等待服务器确认；SYN：同步序列编号（Synchronize Sequence Numbers）。
第二次握手：服务器收到syn包，必须确认客户端的SYN（ack=j+1），同时自己也发送一个SYN包（seq=k），即SYN+ACK包，此时服务器进入SYN_RECV状态。
第三次握手：客户端收到服务器的SYN+ACK包，向服务器发送确认包ACK(ack=k+1)，此包发送完毕，客户端和服务器进入ESTABLISHED（TCP连接成功）状态，完成三次握手。
完成三次握手，客户端与服务器开始传送数据（可使用抓包工具tcpdump 命令 tcpdump -nn -i eth0 prot 80）
TCP四次挥手 对于一个已经建立的连接，TCP使用改进的四次挥手来释放连接（使用一个带有FIN附加标记的报文段）。TCP关闭连接的步骤如下： 第一步，当主机A的应用程序通知TCP数据已经发送完毕时，TCP向主机B发送一个带有FIN附加标记的报文段（FIN表示英文finish）。 第二步，主机B收到这个FIN报文段之后，并不立即用FIN报文段回复主机A，而是先向主机A发送一个确认序号ACK，同时通知自己相应的应用程序：对方要求关闭连接（先发送ACK的目的是为了防止在这段时间内，对方重传FIN报文段）。</description>
    </item>
    
    <item>
      <title>Markdown入门</title>
      <link>https://blog.leanku.com/post/markdown%E5%85%A5%E9%97%A8/</link>
      <pubDate>Sat, 19 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/markdown%E5%85%A5%E9%97%A8/</guid>
      <description>Markdown 1.Markdown 简介
2.常用语法入门
标题 段落 分割线 列表 引用 强调 辅助线 字体字号 背景色 行内代码 代码块 超链接 图片
Markdown 是什么？ Markdown 是一种轻量级标记语言，创始人是约翰・格鲁伯（John Gruber）。它允许人们 “使用易读易写的纯文本格式编写文档，然后转换成有效的 HTML 文档”。
—— 维基百科。
常用语法总结 标题 1.在标题文字下方添加标记，连续的三个 “等号”（===） 代表一级标题，连续的三个 “减号”（—）代表二级标题。
2.在标题文字行首增加连续的 “井号” (#) 及空格。1 个 “井号” 代表一级标题，2 个连续 “井号” 代表二级标题，以此类推，最多支持到 6 级标题。
段落 不同于分段换行，不分段换行不是用 p 标签描述段落，而是用 br 标签折断文字。 如果要让文字另起一行而不分段，需在行尾增加两个空格。 分割线 连续的三个「星号 *」，或者连续的三个「减号 -」，或者连续的三个「下划线 _」会被渲染成分割线。 列表 支持有序和无序两种列表，无序列表使用 「星号 &amp;ldquo;*&amp;quot;」、「加号 &amp;ldquo;+&amp;quot;」、「减号 &amp;ldquo;-&amp;quot;」表示，有序列表使用数字定义，如: 1. xxx 2.xxx 3.xxx 等。 引用 使用邮件风格「大括号 &amp;gt;」的引用声明。如果你已了解如何在邮件中引用文章，那代表你也掌握了在 Markdown 文本中引用文字的方法了。其实现方式就是在被引用的文字行开头添加「大于号 &amp;gt;」。 如果需要在块引用内的换行，可以在行尾增加两个连续的空格。 强调 用 「星号 *」或者 「下划线 _」 包裹住，一个符号的时候代表斜体，如 斜体，两个符号的时候代表粗体，如 **粗体**。</description>
    </item>
    
    <item>
      <title>Markdown进阶</title>
      <link>https://blog.leanku.com/post/markdown%E8%BF%9B%E9%98%B6/</link>
      <pubDate>Sat, 19 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/markdown%E8%BF%9B%E9%98%B6/</guid>
      <description>Markdown语法进阶 常用语法总结
原样输出 页内跳转 代码高亮 注释 表格 生成目录 脚注尾注 流程图 饼图 数学公式
Markdown 是什么？ Markdown 是一种轻量级标记语言，创始人是约翰・格鲁伯（John Gruber）。它允许人们 “使用易读易写的纯文本格式编写文档，然后转换成有效的 HTML 文档”。
—— 维基百科。
常用语法总结 原样输出 1.使用反斜杠\ 如 \斜体
页内跳转 &amp;lt;a id=&amp;#34;table1&amp;#34;&amp;gt;Table - 1&amp;lt;/a&amp;gt; #要跳转的位置,id = 链接位置 [跳转到 Table-1](#table1) #在需要跳转的地方引用,点击即可实现跳转(编辑器中右键打开链接) 代码高亮 代码块后面标注语法类型，即可完成语法的高亮显示。
echo &amp;#39;hello&amp;#39;; 注释 第一是通过 html 的 &amp;lt;!&amp;ndash; &amp;ndash;&amp;gt; 标记；
第二可以通过样式隐藏段落内容，即 &amp;lt;div style=&amp;ldquo;display:none&amp;rdquo;&amp;gt;；第三是通过 Markdown 自身的解析原理实现。 表格 表格包含三个部分：表头、分割线、数据。
表头 用来对列名对象进行描述，也就是通常所说的列名；
数据 用来展示每行的具体内容，数据是表格的核心；
分割线 用来区分表头和数据，也是 Markdown 中表格定义的最基本语法要求。
竖线 用来定义列，每两个竖线之间为一个单元格元素；
减号 用来定义分割线，也就是分割表头和数据体；
冒号 配合减号使用，用于定义列数据的对齐属性。</description>
    </item>
    
    <item>
      <title># Carbon（nesbot/carbon）-- PHP 日期时间利器化</title>
      <link>https://blog.leanku.com/post/php/carbon-php-%E6%97%A5%E6%9C%9F%E6%97%B6%E9%97%B4%E5%88%A9%E5%99%A8/</link>
      <pubDate>Tue, 15 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/php/carbon-php-%E6%97%A5%E6%9C%9F%E6%97%B6%E9%97%B4%E5%88%A9%E5%99%A8/</guid>
      <description>Carbon（nesbot/carbon）&amp;ndash; PHP 日期时间利器化 一、Carbon介绍 Carbon 是 PHP 中最流行的 日期时间处理库，基于 PHP 原生的 DateTime 类封装，提供 链式操作、易读 API、时区支持 等强大功能。
特点：
链式调用，语义化强
支持日期时间加减、比较、格式化
支持中文等多语言友好显示
可与 Laravel、Hyperf 等框架无缝集成
官方文档：https://carbon.nesbot.com/docs/
安装：composer require nesbot/carbon
二、基本使用 2.1 获取当前时间 $now = Carbon::now(); // 当前时间，默认系统时区 echo $now; // 2023-09-28 15:30:12 // 指定时区： $nowShanghai = Carbon::now(&amp;#39;Asia/Shanghai&amp;#39;); 2.2 日期创建 $dt1 = Carbon::create(2023, 9, 28, 15, 30, 0); // 年, 月, 日, 时, 分, 秒 $dt2 = Carbon::parse(&amp;#39;2023-12-31 23:59:59&amp;#39;); $dt3 = Carbon::today(); // 当天 0:00:00 $dt4 = Carbon::tomorrow(); // 明天 0:00:00 $dt5 = Carbon::yesterday(); // 昨天 0:00:00 2.</description>
    </item>
    
    <item>
      <title>composer</title>
      <link>https://blog.leanku.com/post/php/composer/</link>
      <pubDate>Tue, 15 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/php/composer/</guid>
      <description>composer Composer是 PHP 用来管理依赖（dependency）关系的工具。你可以在自己的项目中声明所依赖的外部工具库（libraries），Composer 会帮你安装这些依赖的库文件。
一、Composer 基础概念 Composer 是 PHP 的依赖管理工具，它通过定义项目所需的依赖包及版本，自动安装和管理这些依赖，确保项目在不同环境下都能稳定运行。其核心概念主要包括以下几个方面：
1.1 包（Package） 包是 Composer 管理的基本单元，它可以是一个 PHP 类库、框架组件，或是某个功能模块。比如用于 HTTP 请求处理的 Guzzle，以及知名的 PHP 框架 Laravel、Symfony 等，都可以看作是 Composer 包。这些包被发布在 Packagist 等包仓库中，方便开发者获取使用。
1.2 composer.json 与 composer.lock composer.json是项目的依赖配置文件，开发者在其中定义项目所需的依赖包及其版本约束。例如，若要在项目中使用 PHPUnit 进行单元测试，可在composer.json添加 &amp;ldquo;phpunit/phpunit&amp;rdquo;: &amp;ldquo;^9.5&amp;rdquo; ，表示使用 PHPUnit 9.5 及以上版本，但低于 10.0 版本。​
composer.lock则是锁定依赖包具体版本的文件。当执行composer install或composer update时，Composer 会将实际安装的依赖包版本记录在composer.lock中。下次在其他环境安装依赖时，该文件能确保安装的依赖包版本与之前完全一致，避免因版本差异导致项目出现兼容性问题 。
1.3 包仓库（Repository）​ 包仓库是存储 Composer 包的地方，默认情况下，Composer 使用 Packagist 作为官方包仓库，它汇聚了海量的 PHP 开源包。除了 Packagist，开发者还可以搭建私有包仓库，用于管理内部开发的私有包，或者使用其他公共仓库，拓展包的来源。 packagist仓库地址
二、安装composer #下载安装脚本 － composer-setup.php － 到当前目录。 php -r &amp;#34;copy(&amp;#39;https://install.phpcomposer.com/installer&amp;#39;, &amp;#39;composer-setup.</description>
    </item>
    
    <item>
      <title>Composer 自动加载原理</title>
      <link>https://blog.leanku.com/post/php/composer-%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86/</link>
      <pubDate>Tue, 15 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/php/composer-%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86/</guid>
      <description>Composer 自动加载原理 Composer 的自动加载本质是 动态加载类文件，它实现了“按需加载”的机制，避免了手动 require 每个类文件。
一、Composer 自动加载的核心 PHP 提供了 spl_autoload_register() 函数：
spl_autoload_register(function ($class) { require &amp;#39;src/&amp;#39; . str_replace(&amp;#39;\\&amp;#39;, &amp;#39;/&amp;#39;, $class) . &amp;#39;.php&amp;#39;; }); 当你第一次使用一个类时，PHP 会调用这个函数。 $class 是你使用的类全名（包括命名空间）。 函数里通过规则找到对应文件并 require。 Composer 自动加载，就是在这个基础上做了 规范化管理。
二、Composer 生成的自动加载文件 安装依赖后，Composer 会生成：
vendor/autoload.php vendor/composer/autoload_*.php vendor/autoload.php：入口文件，只需 require 一次。 vendor/composer/autoload_psr4.php：记录 PSR-4 命名空间 → 文件路径映射。 vendor/composer/autoload_classmap.php：记录 类名 → 文件路径，用于 classmap 加速加载。 vendor/composer/autoload_files.php：记录需要立即加载的文件（如全局函数库）。 vendor/autoload.php 的核心逻辑：
require __DIR__ . &amp;#39;/composer/autoload_real.php&amp;#39;; return ComposerAutoloaderInit::getLoader(); ComposerAutoloaderInit::getLoader() 会：
初始化一个 ClassLoader 实例。 根据配置注册 PSR-4、PSR-0、classmap、files 自动加载函数到 PHP。 调用 spl_autoload_register() 注册这些函数。 三、PSR-4 自动加载机制 PSR-4 是 Composer 默认的推荐机制。 假设 composer.</description>
    </item>
    
    <item>
      <title>Guzzle</title>
      <link>https://blog.leanku.com/post/php/guzzle/</link>
      <pubDate>Tue, 15 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/php/guzzle/</guid>
      <description>Guzzle HTTP 客户端全解析及 PHP 使用与优化 一、介绍 Guzzle 是 PHP 世界中最流行的 HTTP 客户端库之一，用于发送 HTTP/HTTPS 请求并处理响应。
它支持：
同步和异步请求
HTTP/2
中间件机制（类似 Laravel / Hyperf 的管道）
并发请求
请求重试、超时、连接池
Guzzle 常被用于调用第三方 API、微服务接口或爬取网页数据。
官方文档：https://docs.guzzlephp.org
二 、安装 composer require guzzlehttp/guzzle 三、基本使用 3.1 同步 GET 请求 use GuzzleHttp\Client; $client = new Client([ &amp;#39;base_uri&amp;#39; =&amp;gt; &amp;#39;https://api.example.com&amp;#39;, &amp;#39;timeout&amp;#39; =&amp;gt; 5.0, // 超时时间 ]); $response = $client-&amp;gt;get(&amp;#39;/users/1&amp;#39;); echo $response-&amp;gt;getStatusCode(); // 200 echo $response-&amp;gt;getBody(); // JSON 或 HTML 3.2 POST 请求与 JSON 数据 $response = $client-&amp;gt;post(&amp;#39;/users&amp;#39;, [ &amp;#39;json&amp;#39; =&amp;gt; [ &amp;#39;name&amp;#39; =&amp;gt; &amp;#39;John&amp;#39;, &amp;#39;email&amp;#39; =&amp;gt; &amp;#39;john@example.</description>
    </item>
    
    <item>
      <title>Netlify部署静态网站</title>
      <link>https://blog.leanku.com/post/ntelify%E5%88%9D%E4%BD%93%E9%AA%8C/</link>
      <pubDate>Sat, 22 Oct 2022 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/ntelify%E5%88%9D%E4%BD%93%E9%AA%8C/</guid>
      <description>关于Netlify
在它的主页上可以看到它的宣传语：
用最快的方式构建最快的网站。
官方文档
为什么选择Netlify
内置 CI/CD 支持自动构建拉取代码仓库，每次提交的自动构建并发布预览
能够托管服务免费 CDN
能够绑定自定义域名
能够启用免费的TLS证书启用HTTPS
提供 Webhooks 和 API
通过内置应用程序添加动态功能
部署一个静态网站就非常简单，此处以GitHub仓库为例
静态网站push到GitHub仓库
进入netlify
登录 直接使用GitHub账号，授权
创建网站 点击New site from Git
选择仓库 选择分支（Branch to deploy） 4.3 打包命令 （Build command）诸如 npm run build，gulp build 之类；如果本身已是静态文件，不需打包编译，这一栏则不填
4.4 打包后目录 （Publish directory）诸如 public,dist，_site 之类；如果本身已是静态文件，这一栏则不填
4.5 deploy site
设置域名 netlify会随机生成了一个netlify下的域名，我们可以更改其前缀，并绑定到我们自己的域名下： Site settings-&amp;gt;Change site name 更换默认域名 Domain settings-&amp;gt;Add custom domain添加域名，然后到域名服务商网站绑定的域名下添加一条CNAME解析，解析的主机记录即对应的netlify域名值（即 xx.netlify.com） 关于.netlify.toml自动部署参阅文档 https://docs.netlify.com/configure-builds/file-based-configuration/
更多操作后续更新。。。</description>
    </item>
    
    <item>
      <title>Git版本升级</title>
      <link>https://blog.leanku.com/post/git%E7%89%88%E6%9C%AC%E9%97%AE%E9%A2%98%E8%AE%B0%E5%BD%95/</link>
      <pubDate>Fri, 21 Oct 2022 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/git%E7%89%88%E6%9C%AC%E9%97%AE%E9%A2%98%E8%AE%B0%E5%BD%95/</guid>
      <description>使用 Brew 对Mac系统Git进行版本升级
#安装最新的Git ➜ ~ brew install git #改变默认Git指向 ➜ ~ which git #/usr/bin/git ➜ ~ git --version #git version 2.24.1 (Apple Git-126) ➜ ~ brew link git --overwrite #新开终端查看版本 ➜ ~ git version #git version 2.38.1 可以看到，我们的 git 版本已经升级到最新版了</description>
    </item>
    
    <item>
      <title>Hello Hugo</title>
      <link>https://blog.leanku.com/post/hugo-%E5%88%9D%E4%BD%93%E9%AA%8C/</link>
      <pubDate>Fri, 21 Oct 2022 00:00:00 +0000</pubDate>
      
      <guid>https://blog.leanku.com/post/hugo-%E5%88%9D%E4%BD%93%E9%AA%8C/</guid>
      <description>Hugo 是用 Go 语言写的，支持多个平台 包括 Windows, Linux, FreeBSD 和 OS X (Darwin) for x64, i386 和 ARM architectures.
官方文档
为什么选择hugo
通过 Hugo 你可以快速搭建你的静态网站，比如博客系统、文档介绍、公司主页、产品介绍等等。相对于其他静态网站生成器来说，Hugo 具备如下特点：
极快的页面编译生成速度。（ ~1 ms 每页面）
完全跨平台支持，可以运行在 Mac OS X, Linux, Windows, 以及更多!
安装方便 Installation
本地调试 Usage 时通过 LiveReload 自动即时刷新页面。
完全的皮肤支持。
可以部署在任何的支持 HTTP 的服务器上。
一.安装 下载最新的 release 版本 Hugo Releases， Windows, Linux, FreeBSD 和 OS X (Darwin) for x64, i386 和 ARM architectures.
Windows安装时需要加入环境变量
Mac就比较方便直接执行：brew install hugo
安装成功之后的操作如下</description>
    </item>
    
  </channel>
</rss>
