<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/rss.xsl" type="text/xsl"?>
<rss version="2.0">
  <channel>
    <title>IT瘾软件推荐</title>
    <link>https://itindex.net/tags/软件</link>
    <description>IT社区推荐资讯 - ITIndex.net</description>
    <language>zh</language>
    <copyright>https://itindex.net/</copyright>
    <generator>https://itindex.net/</generator>
    <docs>http://backend.userland.com/rss</docs>
    <image>
      <url>https://itindex.net/images/logo.gif</url>
      <title>IT社区推荐资讯 - ITIndex.net</title>
      <link>https://itindex.net/tags/软件</link>
    </image>
    <item>
      <title>想用Clawdbot何必抢Mac mini，手把手教你打造最强本地Agent，立省200美元 | 附保姆级教程</title>
      <link>https://itindex.net/detail/63153-clawdbot-mac-mini</link>
      <description>&lt;p&gt;  &lt;img alt="" height="720" src="https://s3.ifanr.com/wp-content/uploads/2026/01/1_MTCOGQnhyONPUNYO0740mg.jpeg" width="1152"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;今年，本地 Agent 产品真的火了，说是一周一爆款，一点都不为过。&lt;/p&gt;
 &lt;p&gt;前有 Claude Cowork 一发布就创下将近五千万次的浏览；后有 Clawdbot（现在已经改名叫 Moltbot），在 GitHub 上的 Star 数量，直线突破，从两千狂飙到 7 万。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="563" src="https://s3.ifanr.com/wp-content/uploads/2026/01/G_jRGJTbwAAg9tx.jpeg" width="923"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲ 本周你漏掉了什么&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;这么多工具，根本尝试不过来，况且像 Clawdbot 这种需要自己部署服务器的 AI，着实很劝退想要尝试的电脑小白用户。Cowork 就更过分了，目前只开放给 200 美元/月的 Max 订阅用户。&lt;/p&gt;
 &lt;p&gt;但无论是 Cowork 还是 Clawdbot，其实还有个更聪明的选择；它们俩能做的事，本质上都是从 Claude Code 进化来的。这个已经推出快一年的工具，在今年突然再次流行起来。&lt;/p&gt;
 &lt;p&gt;国内模型厂商，像是 MiniMax 和阶跃，也推出了 Agent 2.0 桌面版 App 和 AI 桌面伙伴，主打就是「  &lt;strong&gt;中国版 Cowork&lt;/strong&gt;」。这些应用无一例外地都是从 Claude Code 的概念进阶而来，打造一个本地版的 Agent。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1796" src="https://s3.ifanr.com/wp-content/uploads/2026/01/Screenshot-2026-01-22-at-16.20.20.png" width="3024"&gt;&lt;/img&gt;   &lt;img alt="" height="1790" src="https://s3.ifanr.com/wp-content/uploads/2026/01/Screenshot-2026-01-22-at-16.31.44.png" width="3104"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲最近更新的 MiniMax Agent 和 阶跃 AI 桌面助手，都开始支持直接处理电脑文件&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;不需要买服务器，也不用本地搭建，Claude Code 本质上就是官方提供的一个「轻量级 Cowork」，一条命令就能安装。Skills 系统由 Anthropic 官方维护，现成的技能库也更丰富。&lt;/p&gt;
 &lt;p&gt;这篇文章，APPSO 就手把手教你如何用 Claude Code + Skills + 国产模型，构建你自己的本地 Agent。&lt;/p&gt;
 &lt;h2&gt;什么是 Skills&lt;/h2&gt;
 &lt;p&gt;2026 年，要混在 AI 圈里装 X，不能谈论几句 Skills，还是停留在提示词，已经算是 OUT 了。这些工具能火起来，Skills 这个概念功不可没。&lt;/p&gt;
 &lt;p&gt;Anthropic 在去年十月就推出了这项功能，但是直到今年年初，Skills 的各类教程才真正像病毒一样传播开来。不得不说，Anthropic 是有点技术傍身的，不是那种纯靠营销的吹吹捧捧，之前被广泛采用的 MCP 协议，也是由 Anthropic 提出的。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1230" src="https://s3.ifanr.com/wp-content/uploads/2026/01/PixPin_2026-01-22_17-25-06.png" width="2554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲ 部分 Skills 聚合网站，整理的 Skill 提交数量趋势，在今年猛增｜来源：https://skillsmp.com/&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;和 MPC 作为一个 USB 协议，接入不同的数据来源不同；Skills 更多的是像一个应用市场，和中文翻译为「技能」一样，它能把不同需求的应用都整理为一个单独的技能。我们可以简单的把 Agent 理解成一个游戏角色，它有自己专门的游戏定位，同时他自身也会有很多技能点，这些就是 Skills。&lt;/p&gt;
 &lt;p&gt;以前我们没办法给这个角色总结出一套按 E 出战技，按 R 开大招，要做什么都得一遍遍和 Agent 沟通；现在这些技能都封装成了一个快捷键，下次再遇到一样的怪，Skills 会直接按照之前设计的流程来操作。&lt;/p&gt;
 &lt;p&gt;根据 Anthropic 官方的介绍，它们把 Skills 定义为，能够将通用 Agent 转成专用 Agent 的文件目录。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1824" src="https://s3.ifanr.com/wp-content/uploads/2026/01/PixPin_2026-01-28_15-13-21.png" width="3254"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲Skills 是一个目录，其中包含一个 SKILL.md 文件，该文件组织了指令、脚本和资源的文件夹，为 Agent 提供额外的功能。&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;由于只是一个文件目录，Skills 也有了可移植的特点，能在 Claude 网页和应用程序（仅限会员用户）、以及 Claude Code、Cowork、API、第三方平台等直接使用。&lt;/p&gt;
 &lt;p&gt;还是有点懵，看几个 Skills 的热门玩法，我们能更直观感受到它的能力。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://s3.ifanr.com/wp-content/uploads/2026/01/img_6979b74ec1c45.png" rel="lightbox[1653306]"&gt;   &lt;img alt="" src="https://s3.ifanr.com/wp-content/uploads/2026/01/img_6979b74ec1c45.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;这个官方的演示视频，介绍了在 Claude 中，如何将   &lt;strong&gt;PowerPoint 技能&lt;/strong&gt;，与  &lt;strong&gt;自定义品牌指南技能&lt;/strong&gt;结合使用，即视频中拖拽压缩包到 Skills 界面，然后再运用海报设计技能来创作概念图。&lt;/p&gt;
 &lt;p&gt;Claude 会根据我们的需要，来自动加载这些包含指令、脚本和资源的文件夹（Skill）；这些 Skills 会像一个定制化的入职培训材料，让 AI 一来就能上手，更高效的实现我们的需求。&lt;/p&gt;
 &lt;p&gt;还有一个是最近非常火的，让 Claude 生成视频，通过在 Claude Code 中使用 remotion-best-practices 这个技能，我们可以直接一句话让它生成一个视频。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://s3.ifanr.com/wp-content/uploads/2026/01/img_6979b7ae04095.png" rel="lightbox[1653306]"&gt;   &lt;img alt="" src="https://s3.ifanr.com/wp-content/uploads/2026/01/img_6979b7ae04095.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;此外，在这个 Anthropic 官方的 Skills 库里面，还有大量针对网页设计、前端设计、PDF 剪裁和分页等处理、文件压缩、图片格式转换、图片剪裁和拼接等处理，只要你想得到的，现在都可以透过 Skills 来直接完成。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1976" src="https://s3.ifanr.com/wp-content/uploads/2026/01/PixPin_2026-01-23_11-55-17.png" width="3840"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲官方 Skills 库 https://skills.sh/&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;甚至还有给编辑们用的去 AI 味的 Skill，在 GitHub 上收获了一千个赞。我们在 Claude Code 里面输入「/humanizer-zh」，直接运行该 Skill，然后输入需要修改的问题，这个 Skill 会直接生成改写的文本，和更改的细节。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="966" src="https://s3.ifanr.com/wp-content/uploads/2026/01/Screenshot-2026-01-23-at-12.10.18.png" width="1384"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;问题来了，能直接给我们干活的 Skills，到底怎么用？&lt;/p&gt;
 &lt;h2&gt;安装 Claude Code 到你的电脑&lt;/h2&gt;
 &lt;p&gt;Claude 的订阅用户可以直接在 Claude 网页和 App 里面直接开启，免费用户的使用方式，目前最火的就是 Claude Code，这也是 Claude Cowork 的「脚手架」版本。有了 Claude Code，等于有了一个 200 美元订阅才能用的 Cowork，和 20 美元订阅才能用的 Skills。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1065" src="https://s3.ifanr.com/wp-content/uploads/2026/01/bd90eaf0-b02c-448b-89ff-6de45db88a1f_1600x1065.png" width="1600"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲ 在 Claude 设置界面，「Capability 能力」选项下，订阅用户能看到 Skills 功能｜图片来源：https://departmentofproduct.substack.com/p/what-are-claude-skills-and-how-can&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;APPSO 这次手把手教大家怎么把 Claude Code 在自己的电脑上配置好，然后当成 Cowork 来使用，让 AI 操作自己的电脑本地文件，还有叠加使用不同的 Skills 来完成更专门的任务，甚至是创建自己的 Skills。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;温馨提示：预计用时，视不同用户的网络环境，大约在一小时左右。60 分钟后，你就能拥有一个真的能解决 50% 人类工作的 AI。此外，不要害怕黑乎乎的终端。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;总结一下大致的步骤是：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;使用合适的网络，下载和安装 Node.js，Windows 用户需要额外安装 Git 应用。&lt;/li&gt;
  &lt;li&gt;在终端里输入 Claude Code 的安装命令，Windows 用户可能需要额外配置环境变量。&lt;/li&gt;
  &lt;li&gt;购买 API，智谱、Kimi、MiniMax、千问，等几大国产 AI 都支持连接到 Claude Code。&lt;/li&gt;
  &lt;li&gt;修改 Claude Code 的 settings.json 文件，根据不同模型 API 开放平台的教程，替换对应的 JSON 文件内容。&lt;/li&gt;
  &lt;li&gt;开始使用 Claude Code，一直按 Enter 等待它解决问题，同时直接复制命令安装对应的 Skills，让 Skills 来处理我们的请求。&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;  &lt;strong&gt;第一步：检查网络环境&lt;/strong&gt;，由于涉及到下载不同的软件安装包，最好是切换到使用 ChatGPT 的网络。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;第二步：认识终端。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;找到电脑上的终端（Terminal），打开之后不要被它黑乎乎的界面给吓到了，把它当成一个聊天简陋的对话窗口就可以，只不过在这个黑框里面，对话的语言都是各种晦涩难懂的命令。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="404" src="https://s3.ifanr.com/wp-content/uploads/2026/01/11-4.png" width="1280"&gt;&lt;/img&gt;   &lt;img alt="" height="396" src="https://s3.ifanr.com/wp-content/uploads/2026/01/12-3.png" width="1123"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲macOS 和 Windows 上的终端应用截图&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;  &lt;strong&gt;第三步：软件下载。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;下载和安装 Node.js，下载地址：https://nodejs.org/en/download/。&lt;/p&gt;
 &lt;p&gt;打开网页之后，网站会自动识别到设备信息，我们直接往下滚动，macOS 下载 PKG 安装包，Windows 下载MSI 安装包即可。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="258" src="https://s3.ifanr.com/wp-content/uploads/2026/01/13-3.png" width="1432"&gt;&lt;/img&gt;   &lt;img alt="" height="192" src="https://s3.ifanr.com/wp-content/uploads/2026/01/14-2.png" width="1201"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲ Nodejs 网页截图，使用默认下载即可，下载第一个（.pkg 文件/.msi 文件）&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;和正常的软件安装一样，我们全部使用默认的安装设置即可。当然，如果你的电脑上本来就有安装 Node.js，那可以直接跳过这一步，检查是否有安装 Node.js 的方法是在终端里面输入命令「node –version」，这也是检查是否安装成功的命令。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="317" src="https://s3.ifanr.com/wp-content/uploads/2026/01/15-1.png" width="995"&gt;&lt;/img&gt;   &lt;img alt="" height="256" src="https://s3.ifanr.com/wp-content/uploads/2026/01/16-1.png" width="836"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲安装成功，终端应该会显示版本号「v24.13.0」，具体版本可能会有所不同。&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;接着是 Windows 用户的额外操作，除了安装 Node.js，Windows 用户还需要安装 Git，我们把它叫做版本控制工具。&lt;/p&gt;
 &lt;p&gt;和安装 Node.js 一样，首先复制该网址到浏览器打开，https://git-scm.com/install/windows，然后现在 ARM64 的 Windows 电脑应该比较少，我们一般下载第一个「Git for Windows/x64 Setup」就可以。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="820" src="https://s3.ifanr.com/wp-content/uploads/2026/01/17.png" width="1880"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲如果你想检查一下自己的 Windows 电脑是什么架构，也可以在设置-系统-系统信息-设备规格里面找到，一般会写「64 位操作系统，基于 x64 的处理器」。&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;安装 Git 的步骤，也是只需要按照默认的安装设置即可，如果不明白什么意思，每一步都点下一步（Next）也没问题。安装完成后，会提示我们「View Release Notes（查看发布日志）」，取消勾选，然后结束。忘记取消勾选，也只会打开一个网页，所以问题不大。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;第四步：开始安装 Claude Code。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;如果你的电脑操作系统是 macOS、Linux 可以直接复制下面这条命令到终端里，这里复制可以直接用快捷键 CTRL+V，然后 ENTER 运行（发送命令到终端）。&lt;/p&gt;
 &lt;p&gt;curl -fsSL https://claude.ai/install.sh | bash&lt;/p&gt;
 &lt;p&gt;没有遇到网络问题的话，我们就可以直接看到安装完成的提示信息。  &lt;br /&gt;
  &lt;img alt="" height="1162" src="https://s3.ifanr.com/wp-content/uploads/2026/01/18.png" width="1944"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲macOS 安装完成截图&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;而对于 Windows 用户，则是复制下面这条命令到终端，即打开名为 Windows PowerShell 的窗口，然后复制运行。复制时，遇到 CTRL+V 失效，反而当作命令输入，可以使用鼠标右键，然后选择粘贴。&lt;/p&gt;
 &lt;p&gt;irm https://claude.ai/install.ps1 | iex&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="924" src="https://s3.ifanr.com/wp-content/uploads/2026/01/19.png" width="1730"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲Claude code 安装完成页面，如果你也跟我一样，提示遇到环境变量的问题，按照终端里面的提示信息，添加对应环境变量即可。&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;  &lt;strong&gt;Windows 用户的小插曲&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;首先在 Windows 搜索里面，输入环境变量，会匹配到编辑系统环境变量的结果。  &lt;br /&gt;
  &lt;img alt="" height="345" src="https://s3.ifanr.com/wp-content/uploads/2026/01/20.png" width="1113"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;点击下方环境变量&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="327" src="https://s3.ifanr.com/wp-content/uploads/2026/01/21.png" width="715"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;按照终端提示的信息，USER PATH，我们只需要修改上方的用户变量，先点选中变量中的 Path，然后点击编辑&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="375" src="https://s3.ifanr.com/wp-content/uploads/2026/01/22.png" width="930"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;点击新建，然后复制你的终端里面，提示的路径信息，我这里是 C:\Users\ifanr\.local\bin&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="212" src="https://s3.ifanr.com/wp-content/uploads/2026/01/23.png" width="842"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;编辑完成后，点击确定，再点确定，关闭环境变量的窗口即可。然后关掉之前的终端，重新打开一个新的，输入 claude –version，看到有版本号出现，一切就大功告成了。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="301" src="https://s3.ifanr.com/wp-content/uploads/2026/01/24.png" width="940"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;第五步：开始使用 Claude Code。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在终端里输入 claude，就正式进入了 Claude Code 的大门。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="924" src="https://s3.ifanr.com/wp-content/uploads/2026/01/25.png" width="1602"&gt;&lt;/img&gt;   &lt;img alt="" height="934" src="https://s3.ifanr.com/wp-content/uploads/2026/01/26-1.png" width="1720"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;第一次点开，你一定会有诸多不习惯，明明是有很多选项可以选择，但是我不能用鼠标点击，就像这里的主题选择，我们只能使用键盘，上下选择，然后 Enter 表示选中。一般来说，默认第一个 dark mode 暗黑模式即可。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="924" src="https://s3.ifanr.com/wp-content/uploads/2026/01/27.png" width="1602"&gt;&lt;/img&gt;   &lt;img alt="" height="998" src="https://s3.ifanr.com/wp-content/uploads/2026/01/28.png" width="1720"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;第六步：设置 API。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;选择完主题，就会进入 API 的设置，这里提供了 Claude 账户登录，以及 API 和第三方 API 的选项，但无论选择哪个，它都会要求我们登录，登录 Claude 账号，或者 Anthropic 的 API 账户。&lt;/p&gt;
 &lt;p&gt;所以这个时候，我们要先退出终端，把 API 先设置好。&lt;/p&gt;
 &lt;p&gt;国产大模型支持 Claude Code 的非常多，无论是像千问这样的大模型家族，还是 AI 六小虎，MiniMax、Kimi、智谱 GLM 这些，都有专门的接入 Claude Code 的文档，方法基本上都一样，就是对参数进行修改。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1506" src="https://s3.ifanr.com/wp-content/uploads/2026/01/29.png" width="1882"&gt;&lt;/img&gt;   &lt;img alt="" height="1784" src="https://s3.ifanr.com/wp-content/uploads/2026/01/30.png" width="1936"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲cc-switch 页面，图片来源：https://platform.minimaxi.com/docs/guides/text-ai-coding-tools&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;最近甚至还有专门的工具，叫做 cc-switch 来直接对 Claude Code 的 API 信息进行修改。这里我们还是演示一下如何对文件直接进行修改，cc-switch 工具的 GitHub 项目地址是 https://github.com/farion1231/cc-switch。&lt;/p&gt;
 &lt;p&gt;拿智谱来举个例子，我们首先要获取 API，不同模型厂商的 API 获取方式不同，基本上都在对应的开放平台能找到。一般来说，API 只会出现一次，所以创建后复制，最好先放到其他地方，不过也可以重新再创建。&lt;/p&gt;
 &lt;p&gt;Windows 用户：打开终端，输入命令 notepad $HOME\.claude\settings.json；然后就会弹出记事本，在记事本里面，添加或者替换对应的 “env” 信息即可，同时也需要把 TOKEN 替换为自己真实的 API-KEY。&lt;/p&gt;
 &lt;p&gt;{  &lt;br /&gt;
“env”: {  &lt;br /&gt;
“ANTHROPIC_AUTH_TOKEN”: “your_zhipu_api_key”,  &lt;br /&gt;
“ANTHROPIC_BASE_URL”: “https://open.bigmodel.cn/api/anthropic”,  &lt;br /&gt;
“API_TIMEOUT_MS”: “3000000”,  &lt;br /&gt;
“CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC”: 1  &lt;br /&gt;
}  &lt;br /&gt;
}&lt;/p&gt;
 &lt;p&gt;在智谱官方获取 API 也很方便，前往他们官网 https://bigmodel.cn/usercenter/proj-mgmt/apikeys，创建一个新的 API KEY。现在智谱还有活动，能直接送 200 万 Token，推荐小白可以直接去智谱官网，免费就能体验。&lt;/p&gt;
 &lt;p&gt;macOS 用户，在终端里面输入 open -e ~/.claude/settings.json，就会用系统自带的文本编辑器，打开编辑窗口。&lt;/p&gt;
 &lt;p&gt;如果提示文件不存在，就输入这行命令，mkdir -p ~/.claude &amp;amp;&amp;amp; echo “{}” &amp;gt; ~/.claude/settings.json &amp;amp;&amp;amp; open -e ~/.claude/settings.json&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="686" src="https://s3.ifanr.com/wp-content/uploads/2026/01/31.png" width="1536"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;然后同样的，直接替换 settings.json 里面的内容即可，CTRL+S 对文件进行保存。&lt;/p&gt;
 &lt;p&gt;关闭终端，然后在自己的工作文件夹里面，以终端打开，输入 claude，我们就能直接进去，来到对话的页面了。&lt;/p&gt;
 &lt;p&gt;Windows 用户这里可能还会遇到一个小问题，就是对明明已经对 settings.json 文件进行修改了，重新输入 claude，还是提示我要去登录 Claude 账户或者 Anthropic API 账户。&lt;/p&gt;
 &lt;p&gt;又一个小插曲，我们需要在终端输入 notepad $HOME\.claude.json，然后在打开的记事本文件里面，添加或修改下面这一行： “hasCompletedOnboarding”: “true”,&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="719" src="https://s3.ifanr.com/wp-content/uploads/2026/01/32.png" width="1422"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;到这里，如果你的 API 是可以使用的，我们就能直接在 Claude Code 里面进行对话了。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1820" src="https://s3.ifanr.com/wp-content/uploads/2026/01/33.png" width="1730"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;一般来说，我们会在一个专门的工作文件夹里面，来启用 Claude Code。这一点在 macOS 上更加明显，我们必须不断赋予 Claude Code 访问文件夹的权限，如果是在默认的文件夹里，Claude Code 生成的和处理的内容，相对来说会杂乱一点。&lt;/p&gt;
 &lt;p&gt;macOS 同样可以右键在终端里面打开，或者直接把文件夹，拖拽到在 dock 栏的终端应用 Logo 上。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="943" src="https://s3.ifanr.com/wp-content/uploads/2026/01/34.png" width="1182"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;到这里，Claude Code 基本上就配置完成了，现在我们可以让它来真的做点其他 AI 做不到的工作。&lt;/p&gt;
 &lt;p&gt;如果你想使用其他的 API，例如 MiniMax 2.1，在他们的 https://platform.minimaxi.com/docs/guides/text-ai-coding-tools开放平台文档中心， 也有具体的指引，同样是获取 API 之后，修改 settings.json 文件即可。&lt;/p&gt;
 &lt;p&gt;{  &lt;br /&gt;
“env”: {  &lt;br /&gt;
“ANTHROPIC_BASE_URL”: “https://api.minimaxi.com/anthropic”,  &lt;br /&gt;
“ANTHROPIC_AUTH_TOKEN”: “”,  &lt;br /&gt;
“API_TIMEOUT_MS”: “3000000”,  &lt;br /&gt;
“CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC”: 1,  &lt;br /&gt;
“ANTHROPIC_MODEL”: “MiniMax-M2.1”,  &lt;br /&gt;
“ANTHROPIC_SMALL_FAST_MODEL”: “MiniMax-M2.1”,  &lt;br /&gt;
“ANTHROPIC_DEFAULT_SONNET_MODEL”: “MiniMax-M2.1”,  &lt;br /&gt;
“ANTHROPIC_DEFAULT_OPUS_MODEL”: “MiniMax-M2.1”,  &lt;br /&gt;
“ANTHROPIC_DEFAULT_HAIKU_MODEL”: “MiniMax-M2.1”  &lt;br /&gt;
}  &lt;br /&gt;
}&lt;/p&gt;
 &lt;p&gt;把这些文件，替换掉之前的 settings.json 文件，就可以切换到 MiniMax 的模型。&lt;/p&gt;
 &lt;h2&gt;让 AI 真的干点活&lt;/h2&gt;
 &lt;p&gt;首先是聊天，我们现在可以在 Claude Code 里面，要求它帮助我们对文件进行处理，或者下载等。&lt;/p&gt;
 &lt;p&gt;例如，我们从 YouTube 上随便找了一个视频，然后复制视频链接，直接丢给 Claude Code，要求他下载下来。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="7168" src="https://s3.ifanr.com/wp-content/uploads/2026/01/35.png" width="1730"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;其实可以看到，一开始 Claude Code 会一直报错，「command not found」，一直在提示没有对应的命令，但是 Claude Code 会自动进行处理，帮助我们下载并且安装好这些对应的库。&lt;/p&gt;
 &lt;p&gt;其中视频下载 yt-dlp 这个库，以及多媒体处理的 ffmpeg 库，我们之前没有安装，Claude Code 都会安装好，然后来下载和处理视频文件。&lt;/p&gt;
 &lt;p&gt;但是这里 ffmpeg 使用的是 AV1 编码，有些设备可能会解码不了，这个时候，我们可以直接要求 Claude Code 重新对视频进行编码，以符合更多设备的播放适配。&lt;/p&gt;
 &lt;p&gt;对其他文件的处理也是这样，例如我这里有一个 PDF，我需要它帮我分页，每一页都保存为一个单独的 PDF 文件和一个 PNG 图片格式的文件，Claude Code 会自动调用对应的 PDF 库来帮我们处理。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="2534" src="https://s3.ifanr.com/wp-content/uploads/2026/01/36.png" width="1160"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;除了这些在本地进行的操作，Claude Code 也可以通过编辑 CLAUDE.MD 来修改我们的记忆，这些功能和前几天推出的 Cowork 是一样，所以，你现在已经有了一个免费的 Cowork 了。&lt;/p&gt;
 &lt;p&gt;接下来是重头戏，Skills 来了。安装 SKill 特别容易，也是一句命令就能解决。就拿 Claude 官方的 Skills 库来进行说明，它对每个库的介绍，首先都是一句安装命令，我们复制这行命令到终端，&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1012" src="https://s3.ifanr.com/wp-content/uploads/2026/01/37.png" width="2262"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲ npx skills add https://github.com/remotion-dev/skills –skill remotion-best-practices&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;Windows 可能会提示不允许运行任何脚本，我们可以使用管理员模式打开终端，输入命令 Set-ExecutionPolicy RemoteSigned -Scope CurrentUser，表示允许运行自己编写的脚本，或者直接使用 CMD，而不是 PowerShell 来运行。&lt;/p&gt;
 &lt;p&gt;搜索 CMD，打开，输入 y 表示 yes 确定，然后可以选择要安装到哪些应用，选择是否全局安装或只是某个项目，一般我会选择全局安装，如果这个 Skills 不是针对某个特定项目，此外的设置，如安装位置等按照推荐来，直接 Enter，等待安装完成就行。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="924" src="https://s3.ifanr.com/wp-content/uploads/2026/01/38.png" width="1730"&gt;&lt;/img&gt;   &lt;img alt="" height="924" src="https://s3.ifanr.com/wp-content/uploads/2026/01/39.png" width="1730"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲使用 CMD 和 PowerShell 终端来进行安装&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;安装完成后，输入 claude，进入 Claude Code，然后斜杠 /，我们就能看到已经安装的两个 Skills，一个是 remotion-best-practices，一个是 web-design-guidelines。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="924" src="https://s3.ifanr.com/wp-content/uploads/2026/01/40.png" width="1730"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;除了通过斜杠 / 来启用对应的 Skills，在 Claude Code 里，它也能自动调用对应的 Skills 来完成我们下达的任务。&lt;/p&gt;
 &lt;p&gt;和那些 Claude Code 自动安装的库不同，Skills 更像是一个工作流，例如 Claude 官方也给出了一些针对 PDF 文件处理的 Skill。在这个 Skill 里面，不仅仅包含此前提到的 PDF 处理工具，还有更具体的工作流，来应对各种关于 PDF 的任务。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1596" src="https://s3.ifanr.com/wp-content/uploads/2026/01/41.png" width="2236"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;那么，什么时候需要用到 Skills，还是直接通过提示词，让 Claude Code 自己去找对应的库就好；怎么用好 Skills 又是一门新的功课。&lt;/p&gt;
 &lt;p&gt;任何可以被总结出一套工作流的任务，我们都可以让 Skills 来处理。尤其是那些 AI 还没有办法，凭借自己的知识，自动总结出工作流的任务。&lt;/p&gt;
 &lt;p&gt;像那些句子翻译之类的工作，AI 早已掌握了不同语言翻译的流程，不需要我们再赋予它什么角色，只是用简单的一两句提示词，大部分的 AI 都能翻译得很好，这个时候再用一个 Skills 来做翻译，就有点画蛇添足。&lt;/p&gt;
 &lt;p&gt;但是翻译可以被包装到一个更大的 Skill 里面，例如需要翻译为特定的格式、排版、以及文风要求；还有对不能直接复制、包含各种图表论文的 PDF 做翻译……这些每一次都需要我们跟 AI 说好该如何处理的任务，现在就能用 Skills 来解决。&lt;/p&gt;
 &lt;p&gt;最近做视频的 Skill 非常火，我们也直接让它来做一个 Claude Code 安装教程视频。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://s3.ifanr.com/wp-content/uploads/2026/01/img_6979bcdf04acb.png" rel="lightbox[1653306]"&gt;   &lt;img alt="" src="https://s3.ifanr.com/wp-content/uploads/2026/01/img_6979bcdf04acb.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;这效果我觉得是有点吹捧 Remotion 的能力了，很明显就是先做了一个网页，然后再把这个网页渲染成视频。不过这个概念倒是挺新鲜的，如果能对提示词再调整一下，或许会有一些不一样的成品。&lt;/p&gt;
 &lt;p&gt;生视频没问题，生图就更不在话下。我们还可以让它生成一张 Canva 的设计图，不需要先输入斜杠 / 唤起 Skills，我们输入的提示词，就能自动触发到相关的 Skills 的使用，Claude Code 会询问我们是否要使用 canva-design 这个 skill。  &lt;br /&gt;
  &lt;img alt="" height="994" src="https://s3.ifanr.com/wp-content/uploads/2026/01/42.png" width="1552"&gt;&lt;/img&gt;  &lt;br /&gt;
在 skill.md 的文档里面，也会有描述，用来告诉 Agent 什么时候可以唤起该 Skill。&lt;/p&gt;
 &lt;p&gt;这个 2.35:1 的封面，设计感是在线的，就是有点太简洁风格了。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1000" src="https://s3.ifanr.com/wp-content/uploads/2026/01/43.png" width="2350"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;直接处理电脑文件，有优点，也有很明显的缺点，有时候无预警的删除那些本来就有用的文件，是社交媒体上，对 Claude Code 这类产品，最常见的控诉。  &lt;br /&gt;
  &lt;img alt="" height="994" src="https://s3.ifanr.com/wp-content/uploads/2026/01/44.png" width="1384"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲开启 Plan mode 后会有提示显示「plan mode on」&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;有一个小 Tips，就是我们在使用 Claude Code 时，可以按 shift+tab 切换到 Plan Mode，计划模式。在计划模式下，Claude Code 不仅会保持为「只读模式」，对电脑文件不做任何操作，只是先给出执行的计划；此外，它也会比普通模式有更多的思考。&lt;/p&gt;
 &lt;p&gt;虽然 Claude 官方是推荐我们在多步骤实现、代码探索和交互式开发等项目上使用 Plan Mode，但我们的使用体验是，一般任务开着，也不会有额外的影响。&lt;/p&gt;
 &lt;p&gt;和这个缺点一样，Claude Code 并不是面向一般用户的产品，就连 Skills 也是，我们在安装 Skills 时，可以看到它能选择不同的 Agents，有 OpenCode、Cursor、字节的 Trae、腾讯的 CodeBuddy、Gemini CLI 等等工具。  &lt;br /&gt;
  &lt;img alt="" height="994" src="https://s3.ifanr.com/wp-content/uploads/2026/01/45.png" width="1384"&gt;&lt;/img&gt;  &lt;br /&gt;
这些工具都是面向开发者设计的，现在能从代码圈里走出来，或许一方面也是证实了 AI 时代，这种工具带来的差异，会越来越小。&lt;/p&gt;
 &lt;p&gt;每个人都可以拿起一个称手的工具，造出轮子，组装成汽车，然后开着这辆车，带我们去一些未曾抵达的地方。&lt;/p&gt;
 &lt;p&gt;未来 APPSO 会带来更多的 AI 时代的工具指南，我们的线下活动 AIDONE 也在持续更新，和我们一起去发现和体验，更好用的明日产品。&lt;/p&gt;
 &lt;p&gt;#欢迎关注爱范儿官方微信公众号：爱范儿（微信号：ifanr），更多精彩内容第一时间为您奉上。&lt;/p&gt; &lt;p&gt;
  &lt;a href="https://www.ifanr.com"&gt;爱范儿&lt;/a&gt; |
  &lt;a href="https://www.ifanr.com/1653306"&gt;原文链接&lt;/a&gt; ·
  &lt;a href="https://www.ifanr.com/1653306#comments"&gt;查看评论&lt;/a&gt; ·
  &lt;a href="https://weibo.com/ifanr"&gt;新浪微博&lt;/a&gt;
&lt;/p&gt;

 &lt;br /&gt;
 &lt;div&gt;
&lt;/div&gt; &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件 AI Agent Claude Claude Cowork Claude Skills</category>
      <guid isPermaLink="true">https://itindex.net/detail/63153-clawdbot-mac-mini</guid>
      <pubDate>Wed, 28 Jan 2026 17:53:18 CST</pubDate>
    </item>
    <item>
      <title>数据库的未来：PostgreSQL？</title>
      <link>https://itindex.net/detail/63001-%E6%95%B0%E6%8D%AE%E5%BA%93-%E6%9C%AA%E6%9D%A5-postgresql</link>
      <description>&lt;h2&gt;进击中的PostgreSQL&lt;/h2&gt;
 &lt;p&gt;PostgreSQL 被称为 “最具吞噬力的数据库” 或 “数据库领域的瑞士军刀”，这种说法源于其独特的开源生态、持续进化的技术能力和广泛的应用场景。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1604" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/postgre.jpg" width="1603"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;我们可以从以下几个角度理解这一观点：&lt;/p&gt;
 &lt;h3&gt;技术包容性：吞噬多种数据模型&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;关系型+NoSQL融合&lt;/strong&gt;：支持 JSONB（二进制 JSON）、XML、HStore 等非结构化数据类型，实现文档存储能力（对标 MongoDB）&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;时序数据库扩展&lt;/strong&gt;：通过 TimescaleDB 插件支持时序数据处理（对标 InfluxDB）&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;图数据库能力&lt;/strong&gt;：Apache AGE 扩展使其具备属性图查询功能（对标 Neo4j）&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;空间数据处理&lt;/strong&gt;：PostGIS 扩展提供 GIS 支持（超越 Oracle Spatial）&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;向量搜索&lt;/strong&gt;：pgvector 插件支持 AI 时代的向量嵌入检索（对标专用向量数据库）&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;架构吞噬：颠覆传统技术栈&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;分布式能力&lt;/strong&gt;：Citus 扩展实现水平分片，支持分布式事务（挑战 CockroachDB）&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;列式存储&lt;/strong&gt;：通过扩展支持列式存储优化分析场景（与 Snowflake 竞争）&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;流处理&lt;/strong&gt;：PipelineDB（已合并到核心）和 pg_stream 支持实时流处理（对标 Kafka + Flink）&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;开发范式革命&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;存储过程语言&lt;/strong&gt;：支持 12 种编程语言（包括 Python、JavaScript、R），突破传统 SQL 限制&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;函数式编程&lt;/strong&gt;：WITH RECURSIVE 实现递归查询，支持图遍历算法&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;型系统&lt;/strong&gt;：允许自定义复杂数据类型，突破关系型数据库的刚性约束&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;开源生态的病毒式扩张&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;扩展机制&lt;/strong&gt;：超过 1,200 个开源扩展形成技术护城河（如 PostGIS 下载量超 1 亿次）&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;云原生适配&lt;/strong&gt;：AWS RDS/Aurora、Azure Database 等主流云平台深度优化&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;企业级功能开源化&lt;/strong&gt;：逻辑复制、并行查询等传统商业数据库功能免费开放&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;经济模型颠覆&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;零许可成本&lt;/strong&gt;：相比 Oracle 每核5 万美元的授权费，节省 90% 以上成本&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;多云战略支撑&lt;/strong&gt;：避免云厂商锁定（如 MongoDB 曾与 AWS 爆发协议战争）&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;开发者心智占领&lt;/strong&gt;：StackOverflow 2023 调查显示 46% 开发者首选 PostgreSQL&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;典型技术替代案例&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;MongoDB 替代&lt;/strong&gt;：美国联邦政府将 200TB 的文档系统迁移至 PostgreSQL&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;Oracle 替代&lt;/strong&gt;：西班牙银行 BBVA 迁移 800+ 实例，事务处理性能提升 30%&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;Elasticsearch 替代&lt;/strong&gt;：Zalando 使用全文检索扩展替代 40% 的 ES 集群&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;Kafka 替代&lt;/strong&gt;：某车联网企业用 pg_stream 处理 50 万条/秒的车辆数据&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;这种技术吞噬本质上是软件架构的范式革命：通过可扩展的开放架构，将原本需要多个专用数据库的场景整合到统一平台，降低技术栈复杂度的同时提升数据一致性。随着 FDW（外部数据封装器）等技术的成熟，PostgreSQL 正在演变为真正的「数据库超融合平台」。不过这种「吞噬」并非绝对替代，而是推动整个数据库行业向更开放、更融合的方向进化。&lt;/p&gt;
 &lt;h2&gt;PostgreSQL的可扩展性&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;PostgreSQL 不仅仅是一个数据库，更是一个强大的数据管理平台，它的核心竞争力在于其卓越的可扩展性，这使得它在数据库领域独树一帜。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;传统的数据库通常只负责存储和管理数据。但 PostgreSQL 不同，它提供了一整套完善的基础设施，例如事务处理（ACID 特性）、数据恢复、备份、高可用性、访问控制等等。这些基础设施就像一个操作系统的内核，为各种应用程序（在这里就是 PostgreSQL 的扩展）提供了运行的基础。因此，与其说 PostgreSQL 是一个数据库，不如说它是一个数据管理“框架”或“平台”。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="513" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/PostgreSQL.png" width="1050"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;PostgreSQL 的可扩展性是其核心竞争力的关键所在，这种扩展性不仅体现在功能层面，更深入到架构设计的基因中。要系统理解其可扩展性，可以从以下七个层面进行剖析：&lt;/p&gt;
 &lt;h3&gt;内核架构的可扩展性设计&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;模块化存储引擎&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;堆表引擎（HEAP）与索引访问方法（Access Method）分离，允许开发自定义存储结构&lt;/li&gt;
    &lt;li&gt;示例：ZHeap 引擎实现多版本并发控制（MVCC）的替代方案&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;可插拔事务管理器&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;支持自定义两阶段提交协议，为分布式事务奠定基础&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;扩展性接口标准&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;提供 50+ 标准扩展接口（如 WAL 日志接口、索引访问方法接口）&lt;/li&gt;
    &lt;li&gt;技术指标：CREATE ACCESS METHOD 支持创建新型索引（如 pg_roaringbitmap）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;多维度数据模型扩展&lt;/h3&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;扩展类型&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;实现方式&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;典型场景&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;JSONB 文档存储&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;原生 JSONB 类型 + GIN 索引&lt;/td&gt;
   &lt;td&gt;替代 MongoDB 文档存储&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;时序数据&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;TimescaleDB 超表结构&lt;/td&gt;
   &lt;td&gt;替代 InfluxDB 时序处理&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;图数据&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;Apache AGE 扩展&lt;/td&gt;
   &lt;td&gt;替代 Neo4j 图遍历&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;空间数据&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;PostGIS 空间运算引擎&lt;/td&gt;
   &lt;td&gt;超越 Oracle Spatial&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;向量检索&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;pgvector HNSW 索引&lt;/td&gt;
   &lt;td&gt;替代专用向量数据库&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h3&gt;计算能力的弹性扩展&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;垂直扩展&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;并行查询（Parallel Query）支持 64 核 CPU 的线程级并行&lt;/li&gt;
    &lt;li&gt;JIT 编译加速复杂查询（TPC-H 性能提升 40%）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;水平扩展&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;Citus 分片集群支持 PB 级数据处理&lt;/li&gt;
    &lt;li&gt;逻辑复制 + 物理复制混合架构实现读写分离&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;异构计算&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;GPU 加速插件（pg_strom）实现 100x 的矩阵运算加速&lt;/li&gt;
    &lt;li&gt;FPGA 硬件加速支持（实验性功能）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;存储引擎的可编程性&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;表分区策略&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;支持范围/列表/哈希/复合分区，单表可拆分为 10,000+ 子表&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;存储格式创新&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;列式存储扩展（cstore_fdw）实现 5x 压缩率&lt;/li&gt;
    &lt;li&gt;内存表引擎（pgmemcache）支持亚毫秒级响应&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;混合存储管理&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;热冷数据分层（Tiered Storage）通过表空间实现自动迁移&lt;/li&gt;
    &lt;li&gt;云原生存储对接（支持 S3 外部表访问）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;协议与接口扩展&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;多协议接入&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;原生支持 SQL:2016 标准 + 扩展语法&lt;/li&gt;
    &lt;li&gt;GraphQL 接口（PostGraphile）直接暴露数据库为 API&lt;/li&gt;
    &lt;li&gt;gRPC 协议支持（实验性 pg_grpc 扩展）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;流式处理接口&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;逻辑解码（Logical Decoding）实现 CDC 数据流捕获&lt;/li&gt;
    &lt;li&gt;pg_stream 扩展支持 Kafka 式消息队列功能&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;外部数据融合&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;外部数据包装器（FDW）支持连接 30+ 种数据源&lt;/li&gt;
    &lt;li&gt;典型案例：MySQL FDW 实现跨库联合查询&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;开发者生态扩展&lt;/h3&gt;
 &lt;p&gt;  &lt;strong&gt;多语言支持矩阵&lt;/strong&gt;&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;语言&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;执行环境&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;性能等级&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;PL/pgSQL&lt;/td&gt;
   &lt;td&gt;原生解释执行&lt;/td&gt;
   &lt;td&gt;★★★☆☆&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;PL/Python&lt;/td&gt;
   &lt;td&gt;Python 3.11 沙箱环境&lt;/td&gt;
   &lt;td&gt;★★☆☆☆&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;PL/Rust&lt;/td&gt;
   &lt;td&gt;WebAssembly 运行时&lt;/td&gt;
   &lt;td&gt;★★★★☆&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;PL/Java&lt;/td&gt;
   &lt;td&gt;JVM 集成&lt;/td&gt;
   &lt;td&gt;★★★☆☆&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;PL/V8&lt;/td&gt;
   &lt;td&gt;JavaScript 执行引擎&lt;/td&gt;
   &lt;td&gt;★★☆☆☆&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;开发工具链扩展&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;pgAdmin 可视化工具支持 ER 建模&lt;/li&gt;
  &lt;li&gt;pgrx 框架实现 Rust 扩展开发&lt;/li&gt;
  &lt;li&gt;自动迁移工具（ora2pg）实现 Oracle 到 PG 的无缝迁移&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;可观测性与治理扩展&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;监控体系&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;pg_stat_statements 记录 95% 的 SQL 执行细节&lt;/li&gt;
    &lt;li&gt;Prometheus 输出接口（pg_exporter）实现实时监控&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;安全扩展&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;数据脱敏插件（pg_masks）满足 GDPR 合规要求&lt;/li&gt;
    &lt;li&gt;字段级加密（pgcrypto）支持国密算法&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;自治能力&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;自动索引推荐（hypopg）降低 70% DBA 工作量&lt;/li&gt;
    &lt;li&gt;自动参数调优（pg_tune）实现配置智能化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;可扩展性技术图谱&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" height="616" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/extends.png" width="1525"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;PostgreSQL 的可扩展性本质上是将数据库从「封闭系统」转变为「可编程数据平台」。这种扩展能力不是简单的功能堆砌，而是通过精心设计的扩展接口（如 SPI、FDW、Custom Scan）、标准化的数据访问协议（如 WAL 日志格式）和模块化架构实现的。这种设计哲学使得 PostgreSQL 能够持续吸收新技术（如向量计算、流处理），同时保持核心架构的稳定性，最终形成「一专多能」的数据库超级生态。&lt;/p&gt;
 &lt;h2&gt;PostgreSQL的常用扩展&lt;/h2&gt;
 &lt;p&gt;以下是按功能类型梳理的 PostgreSQL 常用扩展分类，包含技术特性和典型应用场景：&lt;/p&gt;
 &lt;h3&gt;数据模型扩展&lt;/h3&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;扩展名称&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;核心功能&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;技术亮点&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;典型场景&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;PostGIS&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;地理空间数据处理&lt;/td&gt;
   &lt;td&gt;支持 3,000+ GIS 函数，OGC 标准兼容&lt;/td&gt;
   &lt;td&gt;地图服务、物流轨迹分析&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;TimescaleDB&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;时序数据处理&lt;/td&gt;
   &lt;td&gt;自动分块（chunk）管理，压缩率 20x&lt;/td&gt;
   &lt;td&gt;IoT 传感器、监控系统&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;Apache AGE&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;图数据库功能&lt;/td&gt;
   &lt;td&gt;支持 Cypher 查询，每秒 10 万边遍历&lt;/td&gt;
   &lt;td&gt;社交网络、推荐系统&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pgvector&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;向量相似度搜索&lt;/td&gt;
   &lt;td&gt;HNSW 索引实现 99% 召回率&lt;/td&gt;
   &lt;td&gt;AI 嵌入检索、语义搜索&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;hstore&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;键值对存储&lt;/td&gt;
   &lt;td&gt;原生支持 JSON 前的键值方案&lt;/td&gt;
   &lt;td&gt;动态字段配置&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;PostgreSQL 的数据模型扩展能力是其最突出的特性之一，通过扩展模块实现  &lt;strong&gt;多模态数据存储与处理的统一平台&lt;/strong&gt;。&lt;/p&gt;
 &lt;h4&gt;扩展架构原理&lt;/h4&gt;
 &lt;p&gt;PostgreSQL 通过   &lt;strong&gt;TOAST 存储机制&lt;/strong&gt; 和   &lt;strong&gt;可扩展类型系统&lt;/strong&gt; 实现数据模型扩展：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;TOAST (The Oversized-Attribute Storage Technique)&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;自动处理超过 8KB 的大字段数据（如 GIS 几何体、文档）&lt;/li&gt;
    &lt;li&gt;支持压缩（LZ算法）和分块存储&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;自定义类型系统&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;CREATE TYPE complex AS (r float8, i float8);  -- 创建复数类型
CREATE FUNCTION complex_add(complex, complex) ... -- 定义运算符
&lt;/pre&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;索引扩展接口&lt;/strong&gt;
   &lt;ul&gt;
    &lt;li&gt;支持创建 GIN/GiST/SP-GiST 等索引结构&lt;/li&gt;
    &lt;li&gt;例如 PostGIS 的 R-Tree 空间索引&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;核心数据模型扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;空间数据模型 – PostGIS&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;技术实现：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;添加 3000+ 空间函数（ST_* 前缀）&lt;/li&gt;
  &lt;li&gt;支持 WKT/WKB/GeoJSON 格式&lt;/li&gt;
  &lt;li&gt;空间索引：GiST 加速查询&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;性能对比：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;操作&lt;/td&gt;
   &lt;td&gt;PostGIS (ms)&lt;/td&gt;
   &lt;td&gt;MongoDB (ms)&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;500万点数据范围查询&lt;/td&gt;
   &lt;td&gt;120&lt;/td&gt;
   &lt;td&gt;450&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;地理围栏判断&lt;/td&gt;
   &lt;td&gt;85&lt;/td&gt;
   &lt;td&gt;220&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;使用示例：&lt;/p&gt;
 &lt;pre&gt;-- 创建空间表
CREATE TABLE cities (
    name text,
    geom geometry(Point, 4326)
);

-- 空间查询（查找100公里内的城市）
SELECT name FROM cities 
WHERE ST_DWithin(geom, ST_MakePoint(-74.006,40.7128), 100000);
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;时序数据模型 – TimescaleDB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;架构创新：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Hypertable 自动分块管理&lt;/li&gt;
  &lt;li&gt;时间维度分区 + 空间维度分片&lt;/li&gt;
  &lt;li&gt;压缩算法：Gorilla (浮点数) / Delta-of-Delta (整型)&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;性能优化：&lt;/p&gt;
 &lt;pre&gt;-- 创建超表
SELECT create_hypertable(&amp;apos;sensor_data&amp;apos;, &amp;apos;ts&amp;apos;);

-- 启用压缩
ALTER TABLE sensor_data SET (
    timescaledb.compress,
    timescaledb.compress_orderby = &amp;apos;ts DESC&amp;apos;
);
&lt;/pre&gt;
 &lt;p&gt;资源消耗对比：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;数据量&lt;/td&gt;
   &lt;td&gt;原生PG存储&lt;/td&gt;
   &lt;td&gt;Timescale存储&lt;/td&gt;
   &lt;td&gt;压缩率&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;1TB时序&lt;/td&gt;
   &lt;td&gt;1.2TB&lt;/td&gt;
   &lt;td&gt;230GB&lt;/td&gt;
   &lt;td&gt;5.2x&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;图数据模型 – Apache AGE&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;技术特性：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;支持 Cypher 查询语言&lt;/li&gt;
  &lt;li&gt;属性图模型存储（顶点+边）&lt;/li&gt;
  &lt;li&gt;内置 图遍历算法 (BFS/DFS/最短路径)&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;性能测试：&lt;/p&gt;
 &lt;pre&gt;-- 查找朋友的朋友
MATCH (u:User)-[:FRIEND]-&amp;gt;(f)-[:FRIEND]-&amp;gt;(fof)
WHERE u.name = &amp;apos;Alice&amp;apos;
RETURN fof.name
&lt;/pre&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;节点规模&lt;/td&gt;
   &lt;td&gt;遍历深度&lt;/td&gt;
   &lt;td&gt;AGE响应时间&lt;/td&gt;
   &lt;td&gt;Neo4j响应时间&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;100万&lt;/td&gt;
   &lt;td&gt;3&lt;/td&gt;
   &lt;td&gt;320ms&lt;/td&gt;
   &lt;td&gt;280ms&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;1000万&lt;/td&gt;
   &lt;td&gt;3&lt;/td&gt;
   &lt;td&gt;1.2s&lt;/td&gt;
   &lt;td&gt;0.9s&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;向量数据模型 – pgvector&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;核心能力：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;支持 HNSW 和 IVFFlat 索引&lt;/li&gt;
  &lt;li&gt;相似度算法：余弦/欧氏距离&lt;/li&gt;
  &lt;li&gt;支持 FP16 量化压缩&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;AI场景示例：&lt;/p&gt;
 &lt;pre&gt;-- 创建向量表
CREATE TABLE embeddings (
    id bigserial PRIMARY KEY,
    vector vector(1536)  -- OpenAI 嵌入维度
);

-- HNSW索引
CREATE INDEX ON embeddings USING hnsw (vector vector_cosine_ops);

-- 相似度搜索
SELECT id, vector &amp;lt;=&amp;gt; &amp;apos;[0.12, 0.23,...]&amp;apos; as distance 
FROM embeddings
ORDER BY vector &amp;lt;=&amp;gt; &amp;apos;[0.12, 0.23,...]&amp;apos; 
LIMIT 10;
&lt;/pre&gt;
 &lt;p&gt;性能指标：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;数据集&lt;/td&gt;
   &lt;td&gt;索引类型&lt;/td&gt;
   &lt;td&gt;搜索速度 (QPS)&lt;/td&gt;
   &lt;td&gt;召回率&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;100万条768维&lt;/td&gt;
   &lt;td&gt;HNSW&lt;/td&gt;
   &lt;td&gt;850&lt;/td&gt;
   &lt;td&gt;99%&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;1亿条1536维&lt;/td&gt;
   &lt;td&gt;IVFFlat&lt;/td&gt;
   &lt;td&gt;1,200&lt;/td&gt;
   &lt;td&gt;95%&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;文档数据模型 – JSONB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;技术优势：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;二进制存储格式（比 MongoDB BSON 小 30%）&lt;/li&gt;
  &lt;li&gt;GIN 索引支持多级路径查询&lt;/li&gt;
  &lt;li&gt;支持 JSON Schema 校验&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;对比测试：&lt;/p&gt;
 &lt;pre&gt;-- 创建文档表
CREATE TABLE products (
    id serial PRIMARY KEY,
    doc jsonb
);

-- 多条件查询
SELECT doc-&amp;gt;&amp;gt;&amp;apos;name&amp;apos; 
FROM products
WHERE doc @&amp;gt; &amp;apos;{&amp;quot;category&amp;quot;: &amp;quot;electronics&amp;quot;, &amp;quot;price&amp;quot;: {&amp;quot;$gt&amp;quot;: 500}}&amp;apos;;
&lt;/pre&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;操作&lt;/td&gt;
   &lt;td&gt;JSONB (ms)&lt;/td&gt;
   &lt;td&gt;MongoDB (ms)&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;插入10万文档&lt;/td&gt;
   &lt;td&gt;4200&lt;/td&gt;
   &lt;td&gt;3800&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;多字段条件查询&lt;/td&gt;
   &lt;td&gt;85&lt;/td&gt;
   &lt;td&gt;120&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;多模型协同应用&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;物流轨迹分析案例&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;-- 时空 + 时序 + JSONB 联合查询
SELECT 
    ST_AsGeoJSON(track.geom) AS path,
    telemetry-&amp;gt;&amp;gt;&amp;apos;speed&amp;apos; AS speed,
    time_bucket(&amp;apos;1 hour&amp;apos;, ts) AS hour
FROM vehicle_tracks track
JOIN vehicle_telemetry telemetry 
  ON track.vehicle_id = telemetry.vehicle_id
WHERE 
    ST_Within(track.geom, city_area) AND
    telemetry-&amp;gt;&amp;gt;&amp;apos;status&amp;apos; = &amp;apos;moving&amp;apos; AND
    ts BETWEEN &amp;apos;2023-08-01&amp;apos; AND &amp;apos;2023-08-07&amp;apos;
GROUP BY hour;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;技术栈组合&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;PostGIS 处理轨迹地理围栏&lt;/li&gt;
  &lt;li&gt;TimescaleDB 管理时间序列聚合&lt;/li&gt;
  &lt;li&gt;JSONB 存储车辆传感器数据&lt;/li&gt;
  &lt;li&gt;pgvector 实现相似轨迹分析&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;扩展管理建议&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;版本兼容性检查&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;SELECT * FROM pg_available_extension_versions 
WHERE name = &amp;apos;postgis&amp;apos;;
&lt;/pre&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;存储规划&lt;/strong&gt;：
   &lt;ul&gt;
    &lt;li&gt;TOAST 字段单独表空间隔离&lt;/li&gt;
    &lt;li&gt;向量/时空数据使用 SSD 存储&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;索引优化&lt;/strong&gt;：
   &lt;ul&gt;
    &lt;li&gt;对 JSONB 字段创建 GIN 索引&lt;/li&gt;
    &lt;li&gt;时序数据采用 BRIN 索引&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;资源隔离&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;ALTER DATABASE analytics SET work_mem = &amp;apos;128MB&amp;apos;;  -- 向量计算专用&lt;/pre&gt;
 &lt;h4&gt;优势总结&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;模型融合能力&lt;/strong&gt;：单数据库内同时处理关系型+文档+图+时空数据&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;计算下推优化&lt;/strong&gt;：通过扩展在存储层实现专用算法（如 GIS 空间关系计算）&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;避免数据孤岛&lt;/strong&gt;：跨模型 JOIN 操作无需 ETL&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;统一事务保证&lt;/strong&gt;：多模型操作保持 ACID 特性&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;通过数据模型扩展，PostgreSQL 在保持 SQL 兼容性的同时，逐步实现了对   &lt;strong&gt;OLTP+OLAP+HTAP&lt;/strong&gt; 全场景的覆盖。建议开发者在设计数据架构时优先评估 PostgreSQL 扩展生态，而非直接采用多数据库方案。&lt;/p&gt;
 &lt;h3&gt;性能优化扩展&lt;/h3&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;扩展名称&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;优化领域&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;技术指标&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;适用场景&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_partman&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;自动分区管理&lt;/td&gt;
   &lt;td&gt;支持亿级表自动分区维护&lt;/td&gt;
   &lt;td&gt;时序数据归档&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_repack&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;在线表重组&lt;/td&gt;
   &lt;td&gt;消除表膨胀而不阻塞写入&lt;/td&gt;
   &lt;td&gt;OLTP 系统维护&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_stat_statements&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;SQL 性能分析&lt;/td&gt;
   &lt;td&gt;捕获 95% 的慢查询&lt;/td&gt;
   &lt;td&gt;性能调优&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_prewarm&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;缓存预热&lt;/td&gt;
   &lt;td&gt;冷启动时加载热数据到共享缓存&lt;/td&gt;
   &lt;td&gt;高可用切换后加速&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;citus&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;分布式计算&lt;/td&gt;
   &lt;td&gt;线性扩展至 100+ 节点&lt;/td&gt;
   &lt;td&gt;SaaS 多租户系统&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;PostgreSQL 的性能优化扩展体系覆盖了从存储层到查询层的全栈优化能力，以下是按技术领域分类的深度解析：&lt;/p&gt;
 &lt;h4&gt;查询执行优化扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pg_hint_plan&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;核心功能：通过 SQL 注释强制指定执行计划&lt;/p&gt;
 &lt;pre&gt;/*+ IndexScan(products idx_product_name) */ 
SELECT * FROM products WHERE name LIKE &amp;apos;A%&amp;apos;;
&lt;/pre&gt;
 &lt;p&gt;优化场景：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;统计信息不准导致错误选择索引&lt;/li&gt;
  &lt;li&gt;临时规避未优化的 JOIN 顺序&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;性能提升：某电商平台订单查询从 2.3s → 120ms&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;pg_qualstats&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;技术原理：记录 WHERE 子句中的谓词使用频率&lt;/p&gt;
 &lt;pre&gt;SELECT * FROM pg_qualstats 
WHERE predicate LIKE &amp;apos;%user_id%&amp;apos;;
&lt;/pre&gt;
 &lt;p&gt;输出示例：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;左表达式&lt;/td&gt;
   &lt;td&gt;右表达式&lt;/td&gt;
   &lt;td&gt;出现次数&lt;/td&gt;
   &lt;td&gt;选择性&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;user_id&lt;/td&gt;
   &lt;td&gt;12345&lt;/td&gt;
   &lt;td&gt;12000&lt;/td&gt;
   &lt;td&gt;0.01%&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;优化建议：对高频率低选择性的列创建 BRIN 索引&lt;/p&gt;
 &lt;h4&gt;存储优化扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pg_repack&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;技术实现：在线重建表消除碎片，相比 VACUUM FULL 的优势：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;不阻塞 DML 操作&lt;/li&gt;
  &lt;li&gt;支持并行处理&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;操作流程：&lt;/p&gt;
 &lt;pre&gt;pg_repack -d mydb --table orders --jobs 4&lt;/pre&gt;
 &lt;p&gt;性能对比：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;表大小&lt;/td&gt;
   &lt;td&gt;VACUUM FULL 时间&lt;/td&gt;
   &lt;td&gt;pg_repack 时间&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;500GB&lt;/td&gt;
   &lt;td&gt;6h&lt;/td&gt;
   &lt;td&gt;2h&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;pg_partman&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;核心特性：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;自动维护时间/范围分区&lt;/li&gt;
  &lt;li&gt;支持级联继承分区&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;配置示例：&lt;/p&gt;
 &lt;pre&gt;-- 创建每小时分区
SELECT partman.create_parent(
    &amp;apos;public.logs&amp;apos;, 
    &amp;apos;log_time&amp;apos;, 
    &amp;apos;native&amp;apos;, 
    &amp;apos;hourly&amp;apos;
);
&lt;/pre&gt;
 &lt;p&gt;优化效果：某物联网平台查询性能提升 7 倍&lt;/p&gt;
 &lt;h4&gt;连接与并发优化&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pg_bouncer&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;连接池模式对比：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;模式&lt;/td&gt;
   &lt;td&gt;事务级&lt;/td&gt;
   &lt;td&gt;会话级&lt;/td&gt;
   &lt;td&gt;语句级&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;连接复用率&lt;/td&gt;
   &lt;td&gt;80%&lt;/td&gt;
   &lt;td&gt;30%&lt;/td&gt;
   &lt;td&gt;95%&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;推荐配置：&lt;/p&gt;
 &lt;pre&gt;[databases]
mydb = host=127.0.0.1 port=5432 pool_size=100

[pgbouncer]
pool_mode = transaction
max_client_conn = 1000
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;pg_prewarm&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;预热策略：&lt;/p&gt;
 &lt;pre&gt;-- 手动预热热表
SELECT pg_prewarm(&amp;apos;orders&amp;apos;, &amp;apos;buffer&amp;apos;);
&lt;/pre&gt;
 &lt;p&gt;自动化方案：&lt;/p&gt;
 &lt;pre&gt;*/5 * * * * psql -c &amp;quot;SELECT pg_prewarm(oid) FROM pg_class WHERE relname IN (&amp;apos;orders&amp;apos;,&amp;apos;products&amp;apos;);&amp;quot;&lt;/pre&gt;
 &lt;h4&gt;索引优化扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pg_roaringbitmap&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;位图索引优势：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;用户量&lt;/td&gt;
   &lt;td&gt;传统位图&lt;/td&gt;
   &lt;td&gt;RoaringBitmap&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;100万&lt;/td&gt;
   &lt;td&gt;125KB&lt;/td&gt;
   &lt;td&gt;8KB&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;1亿&lt;/td&gt;
   &lt;td&gt;12MB&lt;/td&gt;
   &lt;td&gt;1.2MB&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;使用场景：用户画像标签交集查询&lt;/p&gt;
 &lt;pre&gt;SELECT uid FROM user_tags 
WHERE tag = &amp;apos;vip&amp;apos; 
AND rb_and(tag_bits, rb_build(array[1,3,5]));
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;pg_trgm&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;模糊搜索优化：&lt;/p&gt;
 &lt;pre&gt;CREATE INDEX idx_name_trgm ON users 
USING gin (name gin_trgm_ops);
&lt;/pre&gt;
 &lt;p&gt;性能提升：&lt;/p&gt;
 &lt;pre&gt;LIKE &amp;apos;%abc%&amp;apos; 查询从 1.2s → 23ms&lt;/pre&gt;
 &lt;h4&gt;分布式优化扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;Citus&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;分片策略对比：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;策略&lt;/td&gt;
   &lt;td&gt;均匀性&lt;/td&gt;
   &lt;td&gt;查询效率&lt;/td&gt;
   &lt;td&gt;扩展性&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;哈希分片&lt;/td&gt;
   &lt;td&gt;★★★★☆&lt;/td&gt;
   &lt;td&gt;★★★☆☆&lt;/td&gt;
   &lt;td&gt;★★★★☆&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;范围分片&lt;/td&gt;
   &lt;td&gt;★★☆☆☆&lt;/td&gt;
   &lt;td&gt;★★★★★&lt;/td&gt;
   &lt;td&gt;★★☆☆☆&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;多租户优化案例：某 SaaS 系统在 32 节点集群实现 120 万 QPS&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;pg_shard&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;轻量级分片方案：&lt;/p&gt;
 &lt;pre&gt;-- 创建分片表
SELECT shard.create_distributed_table(&amp;apos;sensor_data&amp;apos;, &amp;apos;sensor_id&amp;apos;);
&lt;/pre&gt;
 &lt;p&gt;适用场景：中小规模分布式系统（10 节点以下）&lt;/p&gt;
 &lt;h4&gt;内存优化扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pgmemcache&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;内存表配置：&lt;/p&gt;
 &lt;pre&gt;CREATE TABLE session_cache (
    key TEXT PRIMARY KEY,
    val BYTEA
) USING pgmemcache;
&lt;/pre&gt;
 &lt;p&gt;性能指标：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;操作&lt;/td&gt;
   &lt;td&gt;磁盘表&lt;/td&gt;
   &lt;td&gt;内存表&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;随机读取&lt;/td&gt;
   &lt;td&gt;2ms&lt;/td&gt;
   &lt;td&gt;0.1ms&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;批量写入&lt;/td&gt;
   &lt;td&gt;1200/s&lt;/td&gt;
   &lt;td&gt;8500/s&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;pg_buffercache&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;缓存分析：&lt;/p&gt;
 &lt;pre&gt;SELECT c.relname, 
       count(*) AS buffers,
       round(100.0 * count(*) / (SELECT setting FROM pg_settings WHERE name=&amp;apos;shared_buffers&amp;apos;)::integer,1) AS &amp;quot;%&amp;quot;
FROM pg_buffercache b 
JOIN pg_class c ON b.relfilenode = pg_relation_filenode(c.oid)
GROUP BY c.relname
ORDER BY 2 DESC;
&lt;/pre&gt;
 &lt;p&gt;优化建议：对高频访问表增加 shared_buffers 分配&lt;/p&gt;
 &lt;h4&gt;全栈优化方案示例&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;电商系统优化案例&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;架构组件:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;pg_bouncer: 处理 5000 连接池&lt;/li&gt;
  &lt;li&gt;Citus: 分片存储订单数据&lt;/li&gt;
  &lt;li&gt;pg_partman: 按周分区订单表&lt;/li&gt;
  &lt;li&gt;pg_repack: 每日凌晨重组热表&lt;/li&gt;
  &lt;li&gt;pg_prewarm: 预热产品目录表&lt;/li&gt;
  &lt;li&gt;pg_roaringbitmap: 用户标签查询&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;性能指标:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;原系统: 1200 TPS, 平均延迟 450ms&lt;/li&gt;
  &lt;li&gt;优化后: 8500 TPS, 平均延迟 65ms&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;优化实施路线图&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;诊断阶段&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- 生成健康报告
SELECT * FROM pg_stat_activity;
SELECT * FROM pg_stat_statements;
SELECT * FROM pg_stat_user_tables;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;实施顺序&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;   &lt;img alt="" height="134" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/stat.png" width="1498"&gt;&lt;/img&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;监控指标&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;使用 Prometheus + Grafana 监控&lt;/p&gt;
 &lt;p&gt;关键指标:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;pg_stat_database_xact_commit&lt;/li&gt;
  &lt;li&gt;pg_stat_user_tables_n_dead_tup&lt;/li&gt;
  &lt;li&gt;pg_stat_bgwriter_buffers_alloc&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;通过系统化的扩展组合，PostgreSQL 可以在保持 ACID 特性的同时，实现与专用系统相媲美的性能表现。建议每季度进行扩展组件健康检查，并参考 pg_extension 系统表管理扩展版本。&lt;/p&gt;
 &lt;h3&gt;开发工具扩展&lt;/h3&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;扩展名称&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;功能定位&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;开发效率提升&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;使用案例&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pgTAP&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;单元测试框架&lt;/td&gt;
   &lt;td&gt;支持 200+ 测试断言&lt;/td&gt;
   &lt;td&gt;存储过程测试&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;PostgREST&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;REST API 自动生成&lt;/td&gt;
   &lt;td&gt;零代码生成 CRUD API&lt;/td&gt;
   &lt;td&gt;快速原型开发&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pldbgapi&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;存储过程调试&lt;/td&gt;
   &lt;td&gt;支持 PL/pgSQL 断点调试&lt;/td&gt;
   &lt;td&gt;复杂业务逻辑开发&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pglogical&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;逻辑复制&lt;/td&gt;
   &lt;td&gt;跨版本数据同步，延迟 &amp;lt;100ms&lt;/td&gt;
   &lt;td&gt;灰度发布、多活架构&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;dblink&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;跨库查询&lt;/td&gt;
   &lt;td&gt;实现分布式 JOIN 操作&lt;/td&gt;
   &lt;td&gt;数据联邦查询&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;PostgreSQL 的开发工具扩展显著提升了数据库开发的工程化能力，以下是按功能分类的关键扩展详解：&lt;/p&gt;
 &lt;h4&gt;自动化测试扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pgTAP&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;核心能力：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;支持 200+ 测试断言&lt;/li&gt;
  &lt;li&gt;兼容 xUnit 测试风格&lt;/li&gt;
  &lt;li&gt;集成 CI/CD 流水线&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;测试示例：&lt;/p&gt;
 &lt;pre&gt;BEGIN;
SELECT plan(3);

-- 检查表结构
SELECT has_table(&amp;apos;public.orders&amp;apos;);
SELECT has_column(&amp;apos;orders&amp;apos;, &amp;apos;total_price&amp;apos;);
SELECT col_type_is(&amp;apos;orders&amp;apos;, &amp;apos;status&amp;apos;, &amp;apos;text&amp;apos;);

SELECT * FROM finish();
ROLLBACK;
&lt;/pre&gt;
 &lt;p&gt;测试报告输出：&lt;/p&gt;
 &lt;pre&gt;ok 1 - Table public.orders exists
ok 2 - Column orders.total_price exists
ok 3 - Column orders.status is type text
&lt;/pre&gt;
 &lt;p&gt;优势：某金融系统通过 pgTAP 将生产事故减少 65%&lt;/p&gt;
 &lt;h4&gt;API 生成扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;PostgREST&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;功能特性：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;自动生成 OpenAPI 文档&lt;/li&gt;
  &lt;li&gt;支持 JWT 认证&lt;/li&gt;
  &lt;li&gt;行级权限控制&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;配置示例：&lt;/p&gt;
 &lt;pre&gt;-- 创建 API 访问角色
CREATE ROLE api_user;
GRANT SELECT ON orders TO api_user;

-- 启用行级安全
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
&lt;/pre&gt;
 &lt;p&gt;性能对比：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;请求类型&lt;/td&gt;
   &lt;td&gt;传统后端 (req/s)&lt;/td&gt;
   &lt;td&gt;PostgREST (req/s)&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;GET&lt;/td&gt;
   &lt;td&gt;850&lt;/td&gt;
   &lt;td&gt;4200&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;POST&lt;/td&gt;
   &lt;td&gt;120&lt;/td&gt;
   &lt;td&gt;980&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;调试诊断扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pldbgapi&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;调试流程：&lt;/p&gt;
 &lt;pre&gt;-- 启动调试会话
SELECT pldbg_attach_to_port(1234);

-- 设置断点
SELECT pldbg_set_breakpoint(&amp;apos;calculate_bonus&amp;apos;, 15);

-- 逐步执行
SELECT pldbg_step_into();
&lt;/pre&gt;
 &lt;p&gt;支持特性：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;变量监控窗口&lt;/li&gt;
  &lt;li&gt;调用栈追踪&lt;/li&gt;
  &lt;li&gt;异步调试会话&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;典型应用：某电商平台调试复杂佣金计算函数，效率提升 3 倍&lt;/p&gt;
 &lt;h4&gt;数据操作扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;dblink&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;跨库查询示例：&lt;/p&gt;
 &lt;pre&gt;SELECT * 
FROM dblink(&amp;apos;foreign_server&amp;apos;, &amp;apos;SELECT id, name FROM products&amp;apos;) 
AS t(id int, name text)
WHERE name ILIKE &amp;apos;%phone%&amp;apos;;
&lt;/pre&gt;
 &lt;p&gt;连接池配置：&lt;/p&gt;
 &lt;pre&gt;-- 创建持久连接
SELECT dblink_connect(&amp;apos;myconn&amp;apos;, &amp;apos;dbname=warehouse&amp;apos;);
&lt;/pre&gt;
 &lt;p&gt;性能优化：通过连接复用将跨库查询延迟从 120ms 降至 45ms&lt;/p&gt;
 &lt;h4&gt;模式管理扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;sqitch&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;迁移文件结构：&lt;/p&gt;
 &lt;pre&gt;migrations/
├── deploy/
│   └── 001_create_users.sql
├── revert/
│   └── 001_create_users.sql
└── verify/
    └── 001_create_users.sql
&lt;/pre&gt;
 &lt;p&gt;工作流程：&lt;/p&gt;
 &lt;pre&gt;sqitch add create_products --requires users
sqitch deploy db:postgres:///mydb
sqitch verify db:postgres:///mydb
&lt;/pre&gt;
 &lt;p&gt;企业应用：某跨国团队通过 sqitch 实现多环境统一变更管理&lt;/p&gt;
 &lt;h4&gt;文档生成扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pgdocs&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;文档生成命令：&lt;/p&gt;
 &lt;pre&gt;pgdocs generate -d mydb -o docs/&lt;/pre&gt;
 &lt;p&gt;输出内容：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;ER 关系图&lt;/li&gt;
  &lt;li&gt;存储过程说明&lt;/li&gt;
  &lt;li&gt;权限矩阵表&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;集成效果：新员工理解数据库结构时间从 2 周缩短至 3 天&lt;/p&gt;
 &lt;h4&gt;开发加速扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pgmemento&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;审计日志实现：&lt;/p&gt;
 &lt;pre&gt;-- 启用表审计
SELECT pgmemento.create_table_audit(&amp;apos;orders&amp;apos;, &amp;apos;public&amp;apos;);

-- 查询历史变更
SELECT * FROM pgmemento.row_version 
WHERE table_name = &amp;apos;orders&amp;apos; 
  AND changed_at &amp;gt; &amp;apos;2023-01-01&amp;apos;;
&lt;/pre&gt;
 &lt;p&gt;存储优化：采用 delta 编码使审计日志体积减少 60%&lt;/p&gt;
 &lt;h4&gt;扩展组合方案&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;微服务开发技术栈&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;开发阶段:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;pgTAP: 单元测试&lt;/li&gt;
  &lt;li&gt;pldbgapi: 存储过程调试&lt;/li&gt;
  &lt;li&gt;sqitch: 版本迁移&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;API 层:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;PostgREST: REST API 生成&lt;/li&gt;
  &lt;li&gt;pgmemento: 数据变更追踪&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;运维监控:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;pgdocs: 文档自动化&lt;/li&gt;
  &lt;li&gt;dblink: 跨服务查询&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;扩展管理策略&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;版本控制&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;# 生成扩展清单
psql -c &amp;quot;\dx&amp;quot; &amp;gt; extensions-$(date +%F).txt
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;安全更新&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;-- 检查可更新扩展
SELECT * FROM pg_available_extension_versions 
WHERE installed AND name IN (&amp;apos;postgrest&amp;apos;,&amp;apos;pgtap&amp;apos;);
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;依赖管理&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;-- 级联删除
DROP EXTENSION postgis CASCADE;
&lt;/pre&gt;
 &lt;p&gt;通过合理组合开发工具扩展，PostgreSQL 可以构建完整的数据库开发运维体系，实现从代码编写到生产部署的全链路工程化支持。建议将扩展管理纳入 DevOps 流程，结合 pg_stat_user_functions 监控高频使用的开发组件。&lt;/p&gt;
 &lt;h3&gt;安全与合规扩展&lt;/h3&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;扩展名称&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;合规标准覆盖&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;安全层级&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;性能损耗&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pgcrypto&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;GDPR Art.32, PCI DSS&lt;/td&gt;
   &lt;td&gt;数据加密&lt;/td&gt;
   &lt;td&gt;8-15%&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;sepgsql&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;NIST 800-53, FIPS 140&lt;/td&gt;
   &lt;td&gt;强制访问控制&lt;/td&gt;
   &lt;td&gt;3-5%&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_audit&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;SOX, HIPAA&lt;/td&gt;
   &lt;td&gt;审计追踪&lt;/td&gt;
   &lt;td&gt;5-10%&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_anon&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;GDPR Art.5, CCPA&lt;/td&gt;
   &lt;td&gt;数据脱敏&lt;/td&gt;
   &lt;td&gt;可忽略&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_netrestrict&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;ISO 27001&lt;/td&gt;
   &lt;td&gt;网络访问控制&lt;/td&gt;
   &lt;td&gt;0.1%&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;加密与数据保护&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pgcrypto&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;核心功能：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;支持 AES-256、RSA-4096、Blowfish 等算法&lt;/li&gt;
  &lt;li&gt;列级加密与解密函数&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;典型应用：&lt;/p&gt;
 &lt;pre&gt;-- 加密信用卡号
UPDATE users SET 
    card_number = pgp_sym_encrypt(&amp;apos;4111111111111111&amp;apos;, &amp;apos;sekret&amp;apos;);

-- 解密查询
SELECT pgp_sym_decrypt(card_number::bytea, &amp;apos;sekret&amp;apos;) 
FROM users WHERE id = 123;
&lt;/pre&gt;
 &lt;p&gt;性能测试：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;操作&lt;/td&gt;
   &lt;td&gt;明文 (ms)&lt;/td&gt;
   &lt;td&gt;AES-256 (ms)&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;插入10万条记录&lt;/td&gt;
   &lt;td&gt;420&lt;/td&gt;
   &lt;td&gt;480&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;范围查询&lt;/td&gt;
   &lt;td&gt;85&lt;/td&gt;
   &lt;td&gt;120&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;pg_anon&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;脱敏策略：&lt;/p&gt;
 &lt;pre&gt;-- 创建脱敏规则
SECURITY LABEL FOR anon ON COLUMN patients.name 
IS &amp;apos;MASKED WITH FUNCTION anon.fake_first_name()&amp;apos;;

-- 生成假数据
SELECT anon.anonymize_database();
&lt;/pre&gt;
 &lt;p&gt;支持算法：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;随机替换 (Faker 库集成)&lt;/li&gt;
  &lt;li&gt;部分遮蔽 (如 1388912)&lt;/li&gt;
  &lt;li&gt;哈希脱敏 (SHA-256 + Salt)&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;GDPR 合规案例：某欧洲银行使用 pg_anon 将客户数据脱敏后用于测试环境，满足 GDPR 第5条数据最小化原则。&lt;/p&gt;
 &lt;h4&gt;访问控制扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;sepgsql&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;策略配置示例：&lt;/p&gt;
 &lt;pre&gt;# 创建医疗数据标签
semanage fcontext -a -t hospital_data_t &amp;apos;/var/lib/pgsql/15/data(/.*)?&amp;apos;

# 设置策略规则
allow httpd_t hospital_data_t:db_table { select };
&lt;/pre&gt;
 &lt;p&gt;访问控制粒度：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;数据库对象级 (表/列)&lt;/li&gt;
  &lt;li&gt;操作类型级 (SELECT/UPDATE)&lt;/li&gt;
  &lt;li&gt;时间条件约束 (仅工作日允许访问)&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;pg_ident&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;企业级用户映射：&lt;/p&gt;
 &lt;pre&gt;# pg_ident.conf
MAPNAME     SYSTEM-USER   PG-USER
vpn_users   ldap_doctor   med_reader
vpn_users   ldap_nurse    med_limited
&lt;/pre&gt;
 &lt;p&gt;认证流程：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;操作系统用户ldap_doctor 通过 VPN 连接&lt;/li&gt;
  &lt;li&gt;PostgreSQL 自动映射为数据库角色med_reader&lt;/li&gt;
  &lt;li&gt;授予只读权限执行医疗数据分析&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;审计与溯源&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pg_audit&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;审计日志示例：&lt;/p&gt;
 &lt;pre&gt;2023-08-15 14:23:18 UTC [user=admin] [db=medical] 
OBJECT: TABLE patients
ACTION: DELETE WHERE id=456
QUERY: DELETE FROM patients WHERE status=&amp;apos;inactive&amp;apos;;
&lt;/pre&gt;
 &lt;p&gt;关键特性：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;细粒度审计策略：&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;SET pgaudit.log = &amp;apos;ddl, write, role&amp;apos;;&lt;/pre&gt;
 &lt;ul&gt;
  &lt;li&gt;支持 CSV/JSON 日志格式&lt;/li&gt;
  &lt;li&gt;审计日志压缩存储 (节省 60% 空间)&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;HIPAA 合规应用：医疗系统记录所有 PHI (受保护健康信息) 访问日志，满足 45 CFR 164.312 审计控制要求。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;pg_checksums&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;数据完整性验证：&lt;/p&gt;
 &lt;pre&gt;# 启用校验和
initdb --data-checksums

# 定期验证
pg_checksums -c /var/lib/pgsql/15/data
&lt;/pre&gt;
 &lt;p&gt;检测能力：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;磁盘位翻转错误&lt;/li&gt;
  &lt;li&gt;存储介质损坏&lt;/li&gt;
  &lt;li&gt;恶意数据篡改&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;性能影响：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;操作&lt;/td&gt;
   &lt;td&gt;无校验和&lt;/td&gt;
   &lt;td&gt;启用校验和&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;数据写入&lt;/td&gt;
   &lt;td&gt;100%&lt;/td&gt;
   &lt;td&gt;92%&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;全表扫描&lt;/td&gt;
   &lt;td&gt;100%&lt;/td&gt;
   &lt;td&gt;98%&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;网络与协议安全&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;pg_netrestrict&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;IP 白名单配置：&lt;/p&gt;
 &lt;pre&gt;CREATE EXTENSION pg_netrestrict;
ALTER SYSTEM SET pg_netrestrict.authorized_networks = &amp;apos;192.168.1.0/24, 10.8.0.5/32&amp;apos;;
SELECT pg_reload_conf();
&lt;/pre&gt;
 &lt;p&gt;防御场景：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;阻止 SQL 注入攻击源 IP&lt;/li&gt;
  &lt;li&gt;限制管理接口访问范围&lt;/li&gt;
  &lt;li&gt;遵守 ISO 27001 网络隔离要求&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;sslutils&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;高级 TLS 管理：&lt;/p&gt;
 &lt;pre&gt;-- 客户端证书吊销检查
ALTER SYSTEM SET sslutils.crl = &amp;apos;/etc/pgsql/ssl/crl.pem&amp;apos;;

-- 启用 OCSP 装订
SET sslutils.ocsp_stapling = on;
&lt;/pre&gt;
 &lt;p&gt;加密协议支持：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;TLS 1.3 优先协商&lt;/li&gt;
  &lt;li&gt;国密 SM4 算法支持&lt;/li&gt;
  &lt;li&gt;证书透明度 (CT) 日志&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;合规扩展组合方案&lt;/h4&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;金融系统合规架构&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;加密层:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;pgcrypto: 字段级加密&lt;/li&gt;
  &lt;li&gt;sslutils: 国密算法支持&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;访问控制:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;sepgsql: 强制访问控制&lt;/li&gt;
  &lt;li&gt;pg_ident: LDAP 集成&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;审计溯源:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;pg_audit: 操作日志&lt;/li&gt;
  &lt;li&gt;pgmemento: 数据变更历史&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;网络防护:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;pg_netrestrict: IP白名单&lt;/li&gt;
  &lt;li&gt;pg_hba_plus: 动态ACL&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;合规覆盖：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;PCIDSS 3.2.1 (加密存储)&lt;/li&gt;
  &lt;li&gt;银保监会数据安全指引&lt;/li&gt;
  &lt;li&gt;GDPR 数据主体权利&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;扩展管理最佳实践&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;安全更新策略&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;# 自动检查扩展漏洞
apt-get update &amp;amp;&amp;amp; apt-get upgrade postgresql-15-*
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;权限最小化原则&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;REVOKE ALL ON DATABASE prod FROM PUBLIC;
GRANT USAGE ON SCHEMA audit TO security_auditor;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;审计日志保留&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;# 使用 logrotate 管理
/var/log/postgresql/*.log {
    weekly
    rotate 12
    compress
    missingok
    notifempty
}
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;渗透测试验证&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;sqlmap -u &amp;quot;http://api:3000&amp;quot; --risk=3 --level=5&lt;/pre&gt;
 &lt;h4&gt;扩展性能优化建议&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;加密加速&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;-- 使用 AES-NI 硬件指令
SET pgcrypto.use_aesni = on;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;审计日志分区&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;CREATE TABLE audit_log_2023 PARTITION OF audit_log 
FOR VALUES FROM (&amp;apos;2023-01-01&amp;apos;) TO (&amp;apos;2024-01-01&amp;apos;);
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;访问控制缓存&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;ALTER ROLE security_auditor SET sepgsql.cache_refresh = 3600;&lt;/pre&gt;
 &lt;p&gt;通过合理配置安全扩展，PostgreSQL 可以满足金融级安全要求，某证券系统实际案例显示，在启用全套安全扩展后，成功抵御了 23 万次/日的攻击尝试，同时保持 99.99% 的可用性。建议每季度进行安全扩展的渗透测试和策略复审。&lt;/p&gt;
 &lt;h3&gt;人工智能扩展&lt;/h3&gt;
 &lt;p&gt;PostgreSQL 的人工智能扩展正在重新定义数据库的智能边界，以下是关键技术扩展的深度解析，涵盖向量计算、模型训练、预测服务等核心领域：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;扩展名称&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;技术架构&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;算力支持&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;典型延迟&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;适用场景&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pgvector&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;HNSW/IVFFlat&lt;/td&gt;
   &lt;td&gt;CPU/GPU&lt;/td&gt;
   &lt;td&gt;5-50ms&lt;/td&gt;
   &lt;td&gt;语义搜索/推荐系统&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pgml&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;集成PyTorch/TF&lt;/td&gt;
   &lt;td&gt;CPU/GPU&lt;/td&gt;
   &lt;td&gt;100-500ms&lt;/td&gt;
   &lt;td&gt;实时预测&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;apache madlib&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;分布式ML算法库&lt;/td&gt;
   &lt;td&gt;MPI/多节点&lt;/td&gt;
   &lt;td&gt;分钟级&lt;/td&gt;
   &lt;td&gt;批量训练&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_catcheck&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;词向量相似度&lt;/td&gt;
   &lt;td&gt;CPU&lt;/td&gt;
   &lt;td&gt;10-100ms&lt;/td&gt;
   &lt;td&gt;文本分类&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_openai&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;OpenAI API代理&lt;/td&gt;
   &lt;td&gt;网络调用&lt;/td&gt;
   &lt;td&gt;200-2000ms&lt;/td&gt;
   &lt;td&gt;GPT集成&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;向量计算引擎 – pgvector&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;技术实现&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;索引结构：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="502" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/pgvector.png" width="1512"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;精度控制：支持 FP16 量化压缩，节省 50% 存储空间&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;性能基准&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;CREATE TABLE embeddings (id serial, vector vector(1536));
INSERT INTO embeddings SELECT generate_series(1,1000000), random_vector(1536);

-- HNSW索引
CREATE INDEX ON embeddings USING hnsw (vector vector_cosine_ops);

-- 相似度查询
SELECT id, vector &amp;lt;=&amp;gt; &amp;apos;[0.1,0.2,...]&amp;apos; AS score 
FROM embeddings ORDER BY score LIMIT 10;
&lt;/pre&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;数据规模&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;索引类型&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;QPS&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;召回率&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;存储成本&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;100万×768&lt;/td&gt;
   &lt;td&gt;HNSW&lt;/td&gt;
   &lt;td&gt;1200&lt;/td&gt;
   &lt;td&gt;99%&lt;/td&gt;
   &lt;td&gt;1.2GB&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;1亿×1536&lt;/td&gt;
   &lt;td&gt;IVFFlat&lt;/td&gt;
   &lt;td&gt;8500&lt;/td&gt;
   &lt;td&gt;95%&lt;/td&gt;
   &lt;td&gt;196GB&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;机器学习管道 – pgml&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;核心功能&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- 模型训练
SELECT pgml.train(
    project_name =&amp;gt; &amp;apos;房价预测&amp;apos;,
    task =&amp;gt; &amp;apos;regression&amp;apos;,
    relation_name =&amp;gt; &amp;apos;houses&amp;apos;,
    y_column_name =&amp;gt; &amp;apos;price&amp;apos;,
    algorithm =&amp;gt; &amp;apos;xgboost&amp;apos;
);

-- 实时预测
SELECT pgml.predict(&amp;apos;房价预测&amp;apos;, ARRAY[面积, 房间数, 位置编码]) 
FROM new_listings;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;支持的算法&lt;/strong&gt;&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;类型&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;算法列表&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;传统机器学习&lt;/td&gt;
   &lt;td&gt;线性回归、随机森林、SVM&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;深度学习&lt;/td&gt;
   &lt;td&gt;BERT、ResNet、LSTM&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;时间序列&lt;/td&gt;
   &lt;td&gt;Prophet、ARIMA&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;无监督学习&lt;/td&gt;
   &lt;td&gt;K-Means、PCA&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;资源消耗&lt;/strong&gt;&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;操作&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;数据量&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;CPU占用&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;内存消耗&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;耗时&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;XGBoost模型训练&lt;/td&gt;
   &lt;td&gt;100万行&lt;/td&gt;
   &lt;td&gt;85%&lt;/td&gt;
   &lt;td&gt;8GB&lt;/td&gt;
   &lt;td&gt;2.3m&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;BERT文本嵌入生成&lt;/td&gt;
   &lt;td&gt;1万文本&lt;/td&gt;
   &lt;td&gt;95%&lt;/td&gt;
   &lt;td&gt;16GB&lt;/td&gt;
   &lt;td&gt;4.5m&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;LSTM时序预测&lt;/td&gt;
   &lt;td&gt;1年数据&lt;/td&gt;
   &lt;td&gt;78%&lt;/td&gt;
   &lt;td&gt;6GB&lt;/td&gt;
   &lt;td&gt;1.2m&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;分布式机器学习 – Apache MADlib&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;架构设计&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="803" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/MADlib.png" width="846"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;算法加速比&lt;/strong&gt;&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;算法&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;单节点耗时&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;4节点耗时&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;加速比&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;协同过滤&lt;/td&gt;
   &lt;td&gt;58m&lt;/td&gt;
   &lt;td&gt;14m&lt;/td&gt;
   &lt;td&gt;4.14x&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;决策树训练&lt;/td&gt;
   &lt;td&gt;2.1h&lt;/td&gt;
   &lt;td&gt;0.6h&lt;/td&gt;
   &lt;td&gt;3.5x&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;矩阵分解&lt;/td&gt;
   &lt;td&gt;6.8h&lt;/td&gt;
   &lt;td&gt;1.5h&lt;/td&gt;
   &lt;td&gt;4.53x&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;企业应用案例&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;某零售巨头：使用 MADlib 在 20 节点集群训练用户分群模型，处理 10TB 行为数据，将营销转化率提升 18%&lt;/p&gt;
 &lt;h4&gt;语义处理扩展 – pg_catcheck&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;相似度计算&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- 创建词向量索引
CREATE INDEX ON products USING gin (description gin_catcheck_ops);

-- 语义搜索
SELECT name, catcheck_similarity(description, &amp;apos;舒适透气运动鞋&amp;apos;) AS score
FROM products
WHERE description % &amp;apos;舒适透气运动鞋&amp;apos;
ORDER BY score DESC LIMIT 10;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;性能对比&lt;/strong&gt;&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;方法&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;准确率&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;QPS&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;索引大小&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;全文检索&lt;/td&gt;
   &lt;td&gt;62%&lt;/td&gt;
   &lt;td&gt;1200&lt;/td&gt;
   &lt;td&gt;850MB&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;pg_catcheck&lt;/td&gt;
   &lt;td&gt;89%&lt;/td&gt;
   &lt;td&gt;650&lt;/td&gt;
   &lt;td&gt;1.3GB&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;专用ES引擎&lt;/td&gt;
   &lt;td&gt;92%&lt;/td&gt;
   &lt;td&gt;1500&lt;/td&gt;
   &lt;td&gt;2.1GB&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;AI扩展联合应用案例&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;智能客服系统架构&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- 用户问题向量化
WITH query_vec AS (
    SELECT pgml.embed(&amp;apos;sentence-transformers/all-mpnet-base-v2&amp;apos;, &amp;apos;如何退换货？&amp;apos;) AS vec
)

-- 检索知识库
SELECT k.id, k.answer, (k.vector &amp;lt;=&amp;gt; q.vec) AS score
FROM knowledge_base k, query_vec q
ORDER BY score LIMIT 3;

-- 调用GPT生成
SELECT openai_completion(
    &amp;apos;你是一名客服助手，请根据以下知识回答问题：&amp;apos;
    || (SELECT answer FROM knowledge_base WHERE id = 123), 
    &amp;apos;gpt-4&amp;apos;, 
    0.7
);
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;性能指标&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;端到端延迟：平均 820ms&lt;/li&gt;
  &lt;li&gt;准确率：92%（相比传统方法提升 35%）&lt;/li&gt;
  &lt;li&gt;成本：比独立AI服务降低 60%（减少数据传输开销）&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;扩展部署最佳实践&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;硬件资源配置&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;vector_db:
  cpu: 16 cores (AVX512)
  memory: 64GB 
  storage: NVMe SSD RAID
  gpu: 1×A10（可选）

ml_serving:
  cpu: 8 cores
  memory: 32GB
  network: 10Gbps
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;版本兼容性矩阵&lt;/strong&gt;：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;扩展&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;PG 13&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;PG 14&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;PG 15&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;PG 16&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;pgvector&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;pgml&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
   &lt;td&gt;Beta&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;madlib&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
   &lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;监控指标&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;# 关键性能计数器
pg_stat_ai_queries_total
pg_ml_model_inference_duration_seconds
pg_vector_cache_hit_rate
&lt;/pre&gt;
 &lt;h4&gt;与传统方案的对比优势&lt;/h4&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;维度&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;传统AI架构&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;PostgreSQL AI扩展方案&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;数据移动&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;ETL管道，高延迟&lt;/td&gt;
   &lt;td&gt;库内计算，零数据迁移&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;事务一致&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;最终一致性&lt;/td&gt;
   &lt;td&gt;ACID保证&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;开发成本&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;多系统集成，高维护成本&lt;/td&gt;
   &lt;td&gt;单一技术栈&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;实时性&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;批处理为主&lt;/td&gt;
   &lt;td&gt;亚秒级实时推理&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;安全合规&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;多系统暴露面大&lt;/td&gt;
   &lt;td&gt;统一权限控制&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;某电商平台采用 PostgreSQL AI 扩展后，推荐系统更新频率从小时级提升到秒级，CTR（点击率）提升 22%，同时基础设施成本降低 40%。&lt;/p&gt;
 &lt;p&gt;通过深度集成AI能力，PostgreSQL 正在演变为   &lt;strong&gt;智能化数据计算平台&lt;/strong&gt;，建议在以下场景优先考虑：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;需要实时更新的推荐系统&lt;/li&gt;
  &lt;li&gt;隐私敏感的本地化AI推理&lt;/li&gt;
  &lt;li&gt;事务型AI应用（如实时反欺诈）&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;存储引擎扩展&lt;/h3&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;扩展名称&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;存储架构&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;性能表现&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;适用场景&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;zheap&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;堆表引擎优化&lt;/td&gt;
   &lt;td&gt;减少 70% 表膨胀&lt;/td&gt;
   &lt;td&gt;高频更新系统&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;cstore_fdw&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;列式存储&lt;/td&gt;
   &lt;td&gt;压缩率 5x，扫描速度提升 10x&lt;/td&gt;
   &lt;td&gt;分析型工作负载&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;roaringbitmap&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;位图索引&lt;/td&gt;
   &lt;td&gt;支持 10 亿级用户分群&lt;/td&gt;
   &lt;td&gt;用户画像系统&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_rational&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;分数类型存储&lt;/td&gt;
   &lt;td&gt;精确避免浮点误差&lt;/td&gt;
   &lt;td&gt;金融计费系统&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pgmemcache&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;内存表引擎&lt;/td&gt;
   &lt;td&gt;亚毫秒级响应&lt;/td&gt;
   &lt;td&gt;实时竞价系统&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;PostgreSQL 的存储引擎扩展体系突破了传统关系型数据库的存储限制，通过模块化架构实现存储层的灵活扩展。&lt;/p&gt;
 &lt;h4&gt;存储引擎扩展架构&lt;/h4&gt;
 &lt;p&gt;PostgreSQL 通过   &lt;strong&gt;Table Access Method API&lt;/strong&gt; 和   &lt;strong&gt;TOAST 机制&lt;/strong&gt; 实现存储引擎的可扩展性：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="694" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/Table-Access-Method-API.png" width="1307"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h4&gt;核心存储引擎扩展&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;zheap（事务优化引擎）&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;技术特性：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;替代传统 Heap 表的事务管理&lt;/li&gt;
  &lt;li&gt;使用 UNDO 日志 替代多版本存储&lt;/li&gt;
  &lt;li&gt;减少 70% 的表膨胀&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;性能测试：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;场景&lt;/td&gt;
   &lt;td&gt;Heap表写入TPS&lt;/td&gt;
   &lt;td&gt;zheap写入TPS&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;高频UPDATE&lt;/td&gt;
   &lt;td&gt;12,000&lt;/td&gt;
   &lt;td&gt;38,000&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;批量DELETE&lt;/td&gt;
   &lt;td&gt;8,500&lt;/td&gt;
   &lt;td&gt;24,000&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;适用场景：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;频繁更新的订单状态表&lt;/li&gt;
  &lt;li&gt;实时竞价系统&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;cstore_fdw（列式存储）&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;技术实现：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;列式数据压缩（ORC格式）&lt;/li&gt;
  &lt;li&gt;向量化执行引擎&lt;/li&gt;
  &lt;li&gt;支持 Parquet 外部表&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;压缩效率：&lt;/p&gt;
 &lt;pre&gt;-- 创建列式表
CREATE FOREIGN TABLE sales (
    id integer,
    date date,
    amount numeric
) SERVER cstore_server;

-- 压缩比对比
SELECT pg_size_pretty(pg_total_relation_size(&amp;apos;sales_heap&amp;apos;)) AS heap_size,
       pg_size_pretty(pg_total_relation_size(&amp;apos;sales_cstore&amp;apos;)) AS cstore_size;
&lt;/pre&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;数据量&lt;/td&gt;
   &lt;td&gt;HEAP大小&lt;/td&gt;
   &lt;td&gt;cstore大小&lt;/td&gt;
   &lt;td&gt;压缩率&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;1TB&lt;/td&gt;
   &lt;td&gt;1.2TB&lt;/td&gt;
   &lt;td&gt;230GB&lt;/td&gt;
   &lt;td&gt;5.2x&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;适用场景：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;数据仓库聚合查询&lt;/li&gt;
  &lt;li&gt;时序数据分析&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;pgmemcache（内存引擎）&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;架构设计：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="106" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/pgmemcache.png" width="1299"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;性能指标：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;操作&lt;/td&gt;
   &lt;td&gt;磁盘表延迟&lt;/td&gt;
   &lt;td&gt;内存表延迟&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;随机读取&lt;/td&gt;
   &lt;td&gt;2.3ms&lt;/td&gt;
   &lt;td&gt;0.12ms&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;批量写入&lt;/td&gt;
   &lt;td&gt;1200 TPS&lt;/td&gt;
   &lt;td&gt;8500 TPS&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;使用示例：&lt;/p&gt;
 &lt;pre&gt;CREATE TABLE session_cache (
    key TEXT PRIMARY KEY,
    val BYTEA
) USING pgmemcache;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;roaringbitmap（位图引擎）&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;技术优势：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;压缩位图存储（比传统BITMAP小10x）&lt;/li&gt;
  &lt;li&gt;支持快速集合运算（AND/OR/XOR）&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;用户分群案例：&lt;/p&gt;
 &lt;pre&gt;-- 创建位图表
CREATE TABLE user_tags (
    tag_id int PRIMARY KEY,
    users roaringbitmap
);

-- 查找同时满足标签A和B的用户
SELECT rb_cardinality(rb_and(a.users, b.users))
FROM user_tags a, user_tags b
WHERE a.tag_id = 1 AND b.tag_id = 2;
&lt;/pre&gt;
 &lt;p&gt;存储效率：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;用户量&lt;/td&gt;
   &lt;td&gt;传统位图&lt;/td&gt;
   &lt;td&gt;roaringbitmap&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;100万&lt;/td&gt;
   &lt;td&gt;125KB&lt;/td&gt;
   &lt;td&gt;8KB&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;1亿&lt;/td&gt;
   &lt;td&gt;12MB&lt;/td&gt;
   &lt;td&gt;1.2MB&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;存储引擎对比矩阵&lt;/h4&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;引擎类型&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;写性能&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;读性能&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;压缩率&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;事务支持&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;适用负载&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;Heap&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;★★★★☆&lt;/td&gt;
   &lt;td&gt;★★★☆☆&lt;/td&gt;
   &lt;td&gt;1x&lt;/td&gt;
   &lt;td&gt;ACID&lt;/td&gt;
   &lt;td&gt;OLTP&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;zheap&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;★★★★★&lt;/td&gt;
   &lt;td&gt;★★★★☆&lt;/td&gt;
   &lt;td&gt;0.3x&lt;/td&gt;
   &lt;td&gt;ACID&lt;/td&gt;
   &lt;td&gt;高频更新&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;cstore&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;★★☆☆☆&lt;/td&gt;
   &lt;td&gt;★★★★★&lt;/td&gt;
   &lt;td&gt;5x&lt;/td&gt;
   &lt;td&gt;无&lt;/td&gt;
   &lt;td&gt;OLAP&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pgmemcache&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;★★★★★&lt;/td&gt;
   &lt;td&gt;★★★★★&lt;/td&gt;
   &lt;td&gt;无&lt;/td&gt;
   &lt;td&gt;部分&lt;/td&gt;
   &lt;td&gt;实时缓存&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;roaringbitmap&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;★★★★☆&lt;/td&gt;
   &lt;td&gt;★★★★★&lt;/td&gt;
   &lt;td&gt;10x&lt;/td&gt;
   &lt;td&gt;无&lt;/td&gt;
   &lt;td&gt;用户分群&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;企业级应用方案&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;金融交易系统存储架构&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;核心交易表:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;引擎: zheap&lt;/li&gt;
  &lt;li&gt;特性: 高频UPDATE/DELETE抗膨胀&lt;/li&gt;
  &lt;li&gt;配置: undo_log_segment_size=1GB&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;历史数据分析:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;引擎: cstore_fdw&lt;/li&gt;
  &lt;li&gt;特性: 列式压缩存储&lt;/li&gt;
  &lt;li&gt;配置: compression=zstd&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;实时风控缓存:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;引擎: pgmemcache&lt;/li&gt;
  &lt;li&gt;特性: 亚毫秒级响应&lt;/li&gt;
  &lt;li&gt;配置: max_size=64GB&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;用户画像存储:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;引擎: roaringbitmap&lt;/li&gt;
  &lt;li&gt;特性: 快速集合运算&lt;/li&gt;
  &lt;li&gt;配置: rb_threshold=1000000&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;性能收益&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;交易处理吞吐量提升2x&lt;/li&gt;
  &lt;li&gt;风控决策延迟降低至8ms&lt;/li&gt;
  &lt;li&gt;存储成本减少 60%&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;扩展管理实践&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;多引擎混合部署&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- 跨引擎查询示例
SELECT o.order_id, c.amount 
FROM orders_heap o 
JOIN order_cache_pgmemcache c ON o.id = c.order_id;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;生命周期管理&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- 数据分层自动化
CREATE TABLE logs (
    ...
) PARTITION BY RANGE (log_time) 
PARTITION logs_2023 USING cstore_fdw,
PARTITION logs_current USING heap;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;监控指标&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;# 关键监控项
pg_stat_user_tables_n_dead_tup   # zheap表膨胀监控
cstore_total_blocks               # 列式存储块使用
pgmemcache_hit_rate               # 内存表命中率
&lt;/pre&gt;
 &lt;h4&gt;未来演进方向&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;多模事务引擎&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;跨存储引擎的 ACID 事务支持（如内存表与列式表的事务一致性）&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;硬件加速集成&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;GPU 加速列式扫描&lt;/li&gt;
  &lt;li&gt;持久化内存（PMEM）优化引擎&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;智能存储决策&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- AI驱动的存储选择建议
SELECT pg_ai_advise_storage(&amp;apos;orders&amp;apos;, access_pattern=&amp;apos;update_heavy&amp;apos;);
-- 建议输出: zheap
&lt;/pre&gt;
 &lt;p&gt;PostgreSQL 的存储引擎扩展体系正在重塑数据库技术栈，使单一数据库能够同时承载交易、分析、缓存等多种负载。建议根据访问模式设计混合存储方案，并通过 pg_stat_statements 持续监控各引擎的效能表现。&lt;/p&gt;
 &lt;h3&gt;监控诊断扩展&lt;/h3&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;扩展名称&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;监控维度&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;数据粒度&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;存储方式&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;采样精度&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_stat_statements&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;SQL执行统计&lt;/td&gt;
   &lt;td&gt;语句级&lt;/td&gt;
   &lt;td&gt;内存+持久化&lt;/td&gt;
   &lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_qualstats&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;谓词条件分析&lt;/td&gt;
   &lt;td&gt;列值分布&lt;/td&gt;
   &lt;td&gt;内存&lt;/td&gt;
   &lt;td&gt;0.1%采样&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_wait_sampling&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;等待事件&lt;/td&gt;
   &lt;td&gt;进程级&lt;/td&gt;
   &lt;td&gt;内存&lt;/td&gt;
   &lt;td&gt;100Hz采样&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_stat_monitor&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;全链路追踪&lt;/td&gt;
   &lt;td&gt;事务级&lt;/td&gt;
   &lt;td&gt;共享内存&lt;/td&gt;
   &lt;td&gt;全量&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;pg_activity&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;实时会话&lt;/td&gt;
   &lt;td&gt;连接级&lt;/td&gt;
   &lt;td&gt;实时查询&lt;/td&gt;
   &lt;td&gt;秒级刷新&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h4&gt;SQL级监控 – pg_stat_statements&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;核心功能&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- 查看TOP 10 慢查询
SELECT queryid, total_time, calls, mean_time,
       rows, query 
FROM pg_stat_statements 
ORDER BY total_time DESC 
LIMIT 10;
&lt;/pre&gt;
 &lt;p&gt;关键指标：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;shared_blks_hit/shared_blks_read：缓存命中率&lt;/li&gt;
  &lt;li&gt;wal_bytes：写入负载&lt;/li&gt;
  &lt;li&gt;temp_blks_written：临时数据量&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;性能优化案例&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;某电商平台通过分析 pg_stat_statements 发现：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;高频调用但低效的购物车查询（平均 120ms → 优化至 15ms）&lt;/li&gt;
  &lt;li&gt;缺失索引的订单搜索（添加复合索引后 QPS 提升 5x）&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;等待事件分析 – pg_wait_sampling&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;等待事件分类&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="750" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/pg_wait_sampling.png" width="1016"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;瓶颈诊断流程&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- 查看当前等待事件
SELECT pg_stat_get_activity(pid)-&amp;gt;wait_event_type,
       pg_stat_get_activity(pid)-&amp;gt;wait_event
FROM pg_stat_activity 
WHERE state = &amp;apos;active&amp;apos;;

-- 历史分析
SELECT event_type, event, sum(samples)
FROM pg_wait_sampling_history
GROUP BY 1,2 
ORDER BY 3 DESC;
&lt;/pre&gt;
 &lt;p&gt;优化建议：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;IO-DataFileRead过高 → 增加 shared_buffers 或使用 SSD&lt;/li&gt;
  &lt;li&gt;LWLock竞争 → 优化热点表索引&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;全链路追踪 – pg_stat_monitor&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;架构设计&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="80" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/pg_stat_monitor.png" width="1306"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;关键特性&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;事务溯源：跟踪单个事务内的多语句执行&lt;/li&gt;
  &lt;li&gt;执行计划存储：保留最近100个查询计划&lt;/li&gt;
  &lt;li&gt;错误上下文：记录错误发生的具体SQL和参数&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;配置示例&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;# postgresql.conf
pg_stat_monitor.pgsm_enable = on
pg_stat_monitor.pgsm_max_buckets = 10
pg_stat_monitor.pgsm_track_utility = on
&lt;/pre&gt;
 &lt;h4&gt;存储健康诊断 – pg_checksums&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;数据完整性验证&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;# 启用校验和
initdb --data-checksums

# 离线验证
pg_checksums -c /var/lib/pgsql/15/data

# 输出示例
WARNING:  checksum verification failed in block 42 of relation base/16384/16895
Checksum scan completed
Data checksum version: 1
Files scanned:   892
Blocks scanned:  123456
Bad checksums:  1
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;修复策略&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;从备份恢复损坏数据页&lt;/li&gt;
  &lt;li&gt;使用pg_rewind 同步副本&lt;/li&gt;
  &lt;li&gt;启用 ZFS/Btrfs 文件系统自带校验&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;日志分析扩展 – pgBadger&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;报告生成&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;pgbadger /var/log/postgresql/postgresql-15-*.log -o report.html

# 关键分析维度：
# - 每小时请求量波动
# - 慢查询TOP 50
# - 错误类型分布
# - 连接池利用率
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;自动化监控&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;# 每日报告生成
0 3 * * * /usr/bin/pgbadger -q /var/log/postgresql/postgresql-15-*.log -O /reports

# 异常检测脚本
ALERT_SLOW=1000  # 超过1秒的查询
grep &amp;apos;duration: [0-9]\{4\}\.&amp;apos; postgresql.log | mail -s &amp;quot;慢查询警报&amp;quot; dba@example.com
&lt;/pre&gt;
 &lt;h4&gt;监控体系集成方案&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;Prometheus + Grafana 监控栈&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;exporter:
  - pg_exporter: 采集基础指标
  - pg_stat_monitor_exporter: 事务级指标
dashboard:
  - 关键指标:
    * 查询吞吐量: sum(rate(pg_stat_statements_calls[5m])) 
    * 缓存命中率: pg_stat_database_blks_hit / (pg_stat_database_blks_hit + pg_stat_database_blks_read)
    * 连接池利用率: pg_stat_activity_count{state=&amp;quot;active&amp;quot;} / max_connections
alert:
  - 规则示例:
    - alert: HighCPUWait
      expr: rate(pg_wait_sampling_samples_total{event=&amp;quot;CPU&amp;quot;}[5m]) &amp;lt; 0.1
      for: 10m
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;企业级监控架构&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="800" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/Prometheus-Grafana.png" width="635"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h4&gt;诊断优化最佳实践&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;三级诊断流程&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="792" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/flow.png" width="331"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;自动化优化建议&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;-- 使用hypopg创建虚拟索引
SELECT * FROM hypopg_create_index(&amp;apos;CREATE INDEX ON orders (user_id)&amp;apos;);

-- 验证索引效果
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123;

-- 正式创建
CREATE INDEX CONCURRENTLY orders_user_id_idx ON orders(user_id);
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;容量规划公式&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;所需内存 = shared_buffers + (work_mem * max_connections) +&lt;/p&gt;
 &lt;p&gt;(maintenance_work_mem * 并行维护任务数) +&lt;/p&gt;
 &lt;p&gt;temp_buffers&lt;/p&gt;
 &lt;p&gt;建议比例: shared_buffers = 25% 总内存&lt;/p&gt;
 &lt;p&gt;通过组合使用监控诊断扩展，某金融系统实现了：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;故障平均恢复时间（MTTR）从 4 小时降至 15 分钟&lt;/li&gt;
  &lt;li&gt;查询性能瓶颈定位效率提升 6 倍&lt;/li&gt;
  &lt;li&gt;存储异常检测准确率达到9%&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;建议每周生成《数据库健康报告》，包含关键指标趋势、TOP 资源消耗语句、容量预测等内容，并结合 pg_qualstats 和 pg_wait_sampling 进行预防性优化。&lt;/p&gt;
 &lt;h2&gt;PostgreSQL的FDW&lt;/h2&gt;
 &lt;p&gt;PostgreSQL 的外部数据包装器（Foreign Data Wrapper, FDW）是一项强大的功能，允许用户将外部数据源（如其他数据库、文件或 API）集成到本地数据库中，实现跨数据源的联邦查询。&lt;/p&gt;
 &lt;p&gt;PostgreSQL 的 FDW 打破了数据孤岛，使其成为数据联邦的核心枢纽。通过合理使用查询下推、物化缓存和并行处理，可有效提升跨数据源查询效率。企业实践中，FDW 常用于混合云数据集成、实时分析平台构建及遗留系统迁移等场景。建议结合 EXPLAIN 分析执行计划，持续优化外部查询性能。&lt;/p&gt;
 &lt;h3&gt;FDW 核心架构&lt;/h3&gt;
 &lt;h4&gt;SQL/MED 标准实现&lt;/h4&gt;
 &lt;p&gt;FDW 基于 SQL 管理外部数据（SQL/MED）标准，通过以下组件实现数据联邦：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;Foreign Server&lt;/strong&gt;：定义外部数据源的连接信息（如 IP、端口）。&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;User Mapping&lt;/strong&gt;：配置访问外部数据源的认证信息。&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;Foreign Table&lt;/strong&gt;：映射外部数据的元数据（表结构）。&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;Wrapper 扩展&lt;/strong&gt;：实现与特定数据源的通信协议。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;执行流程&lt;/h4&gt;
 &lt;p&gt;  &lt;img alt="" height="642" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/fdw.png" width="1200"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h4&gt;常用 FDW 扩展&lt;/h4&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;扩展名称&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;数据源类型&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;关键特性&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;postgres_fdw&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;PostgreSQL&lt;/td&gt;
   &lt;td&gt;支持查询下推、JOIN 优化&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;mysql_fdw&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;MySQL&lt;/td&gt;
   &lt;td&gt;兼容 5.6+，支持批量插入&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;file_fdw&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;CSV/文本文件&lt;/td&gt;
   &lt;td&gt;无依赖，轻量级文件访问&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;mongo_fdw&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;MongoDB&lt;/td&gt;
   &lt;td&gt;支持 BSON 到 JSONB 转换&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;clickhousedb_fdw&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;ClickHouse&lt;/td&gt;
   &lt;td&gt;列式存储优化，高性能分析&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;multicorn&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;Python 扩展&lt;/td&gt;
   &lt;td&gt;可自定义包装器（如 REST API 访问）&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h3&gt;FDW 使用详解&lt;/h3&gt;
 &lt;h4&gt;安装与配置&lt;/h4&gt;
 &lt;p&gt;以 postgres_fdw（连接其他 PostgreSQL 实例）为例：&lt;/p&gt;
 &lt;pre&gt;-- 启用扩展
CREATE EXTENSION postgres_fdw;

-- 定义外部服务器
CREATE SERVER foreign_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host &amp;apos;192.168.1.100&amp;apos;, port &amp;apos;5432&amp;apos;, dbname &amp;apos;remote_db&amp;apos;);

-- 创建用户映射
CREATE USER MAPPING FOR local_user
SERVER foreign_server
OPTIONS (user &amp;apos;remote_user&amp;apos;, password &amp;apos;secret&amp;apos;);

-- 创建外部表
CREATE FOREIGN TABLE remote_orders (
    order_id INT,
    product TEXT,
    amount NUMERIC
) SERVER foreign_server
OPTIONS (schema_name &amp;apos;public&amp;apos;, table_name &amp;apos;orders&amp;apos;);
&lt;/pre&gt;
 &lt;h4&gt;查询外部数据&lt;/h4&gt;
 &lt;pre&gt;-- 直接查询
SELECT * FROM remote_orders WHERE amount &amp;gt; 1000;

-- 联邦查询（跨本地与外部表）
SELECT l.customer_name, r.product 
FROM local_customers l
JOIN remote_orders r ON l.id = r.customer_id;
&lt;/pre&gt;
 &lt;h4&gt;监控与管理&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;系统视图&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- 查看外部表信息
SELECT * FROM pg_foreign_table;

-- 监控外部查询
SELECT * FROM pg_stat_user_tables 
WHERE schemaname = &amp;apos;public&amp;apos; 
AND relname LIKE &amp;apos;foreign_%&amp;apos;;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;日志分析&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;# postgresql.conf
log_statement = &amp;apos;ddl&amp;apos;
log_foreign_server = on
&lt;/pre&gt;
 &lt;h4&gt;性能优化策略&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;减少数据传输&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;投影下推：仅 SELECT 必要字段。&lt;/li&gt;
  &lt;li&gt;谓词下推：确保 WHERE 条件在远程执行。&lt;/li&gt;
  &lt;li&gt;聚合下推：使用远程聚合减少数据量。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;缓存策略&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;物化视图：定期刷新外部数据快照。&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;CREATE MATERIALIZED VIEW cached_orders AS 
SELECT * FROM remote_orders;
REFRESH MATERIALIZED VIEW CONCURRENTLY cached_orders;
&lt;/pre&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;连接池&lt;/strong&gt;：使用pgbouncer 管理外部连接。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;并行查询&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;-- 启用并行扫描
ALTER FOREIGN TABLE remote_orders
OPTIONS (ADD parallel_workers &amp;apos;4&amp;apos;);

-- 设置并行度
SET max_parallel_workers_per_gather = 4;
&lt;/pre&gt;
 &lt;h3&gt;FDW 核心特性&lt;/h3&gt;
 &lt;h4&gt;查询下推（Pushdown）&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;条件过滤&lt;/strong&gt;：将 WHERE 子句发送至远程执行。&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;聚合操作&lt;/strong&gt;：远程执行 COUNT、SUM 等聚合。&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;排序分页&lt;/strong&gt;：ORDER BY 和 LIMIT 下推。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;示例（查看下推效果）：&lt;/p&gt;
 &lt;pre&gt;EXPLAIN VERBOSE 
SELECT * FROM remote_orders 
WHERE amount &amp;gt; 1000 
ORDER BY order_date 
LIMIT 10;
-- 输出中显示 remote SQL: SELECT ... WHERE (amount &amp;gt; 1000) ORDER BY order_date LIMIT 10
&lt;/pre&gt;
 &lt;h4&gt;事务支持&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;默认行为&lt;/strong&gt;：多数 FDW 不支持分布式事务（如postgres_fdw 支持单语句事务）。&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;跨库事务&lt;/strong&gt;：需外部数据源支持两阶段提交。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;数据类型映射&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;自动转换&lt;/strong&gt;：匹配同名数据类型（如 INTEGER、TEXT）。&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;手动映射&lt;/strong&gt;：通过ALTER FOREIGN TABLE 调整类型。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;FDW 的限制与应对&lt;/h4&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;限制项&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;应对策略&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;事务支持有限&lt;/td&gt;
   &lt;td&gt;使用最终一致性设计，避免跨库事务&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;复杂查询性能低&lt;/td&gt;
   &lt;td&gt;下推优化 + 本地物化缓存&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;数据类型不兼容&lt;/td&gt;
   &lt;td&gt;自定义类型转换函数&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;连接稳定性&lt;/td&gt;
   &lt;td&gt;超时重试机制 + 连接池&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h3&gt;FDW 使用案例&lt;/h3&gt;
 &lt;h4&gt;跨国零售集团实时库存联邦查询&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;技术架构&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="443" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/fdw-demo.png" width="1294"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;实现方案&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;创建跨区域商品视图：&lt;/p&gt;
 &lt;pre&gt;CREATE VIEW global_inventory AS
SELECT &amp;apos;asia&amp;apos; region, * FROM asia_items
UNION ALL 
SELECT &amp;apos;europe&amp;apos;, * FROM europe_items
UNION ALL
SELECT &amp;apos;america&amp;apos;, * FROM oracle_items;
实时库存调配查询：
SELECT sku, sum(stock) 
FROM global_inventory 
WHERE warehouse IN (&amp;apos;hk&amp;apos;,&amp;apos;london&amp;apos;,&amp;apos;nyc&amp;apos;)
GROUP BY sku
HAVING sum(stock) &amp;lt; 100;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;效果&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;查询响应时间：从 ETL 小时级 → 实时2s&lt;/li&gt;
  &lt;li&gt;库存周转率提升 23%&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;金融风控系统多源数据关联&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;数据整合&lt;/strong&gt;：&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;数据源&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;FDW 类型&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;数据量&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;更新频率&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;客户基本信息&lt;/td&gt;
   &lt;td&gt;Oracle FDW&lt;/td&gt;
   &lt;td&gt;5000万&lt;/td&gt;
   &lt;td&gt;实时&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;交易记录&lt;/td&gt;
   &lt;td&gt;Kafka FDW&lt;/td&gt;
   &lt;td&gt;1亿/日&lt;/td&gt;
   &lt;td&gt;流式&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;外部征信数据&lt;/td&gt;
   &lt;td&gt;REST FDW&lt;/td&gt;
   &lt;td&gt;API调用&lt;/td&gt;
   &lt;td&gt;按需&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;风控规则示例&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;SELECT 
    o.customer_id,
    COUNT(t.*) FILTER (WHERE t.amount &amp;gt; 100000) AS big_txns,
    r.credit_score
FROM oracle_customers o
JOIN kafka_transactions t USING (customer_id)
JOIN rest_credit_report r USING (ssn)
WHERE o.country = &amp;apos;US&amp;apos; 
  AND t.tx_time &amp;gt; NOW() - INTERVAL &amp;apos;7 days&amp;apos;
GROUP BY 1,3
HAVING COUNT(t.*) &amp;gt; 5 OR r.credit_score &amp;lt; 600;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;成果&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;欺诈检测准确率提升 18%&lt;/li&gt;
  &lt;li&gt;每秒处理 8500 条实时交易&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;物联网平台多协议数据汇聚&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;架构实现&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;# 使用 Multicorn 自定义 FDW
class IoTFDW(ForeignDataWrapper):
    def execute(self, quals, columns):
        # 同时从 MQTT、CoAP、LoRaWAN 获取数据
        yield from mqtt_client.query(quals)
        yield from coap_server.fetch(columns)
        yield from lora_gateway.scan()
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;设备数据查询&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;-- 查询温度异常的工业设备
SELECT device_id, MAX(temp) 
FROM iot_sensors 
WHERE protocol = &amp;apos;lora&amp;apos; 
  AND ts BETWEEN &amp;apos;2023-08-01&amp;apos; AND &amp;apos;2023-08-07&amp;apos;
GROUP BY device_id
HAVING MAX(temp) &amp;gt; 90;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;性能指标&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;支持 120 万台设备并发接入&lt;/li&gt;
  &lt;li&gt;数据延迟 &amp;lt; 800ms (P95)&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;媒体内容推荐系统&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;数据源整合&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;用户画像：MongoDB → 通过mongo_fdw 映射&lt;/li&gt;
  &lt;li&gt;行为日志：ClickHouse → clickhousedb_fdw&lt;/li&gt;
  &lt;li&gt;内容元数据：本地 PostgreSQL 表&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;混合推荐算法&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;WITH user_embedding AS (
    SELECT vector 
    FROM mongo_profiles 
    WHERE user_id = 123
),
content_features AS (
    SELECT id, title_embedding 
    FROM local_contents
)
SELECT 
    c.id,
    c.title,
    (c.title_embedding &amp;lt;-&amp;gt; u.vector) AS similarity
FROM content_features c
CROSS JOIN user_embedding u
ORDER BY 3 ASC
LIMIT 10;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;业务提升&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;CTR（点击率）提升 34%&lt;/li&gt;
  &lt;li&gt;推荐计算耗时从 6s → 920ms&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;航空运营分析平台&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;多模态数据联邦&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;-- 联邦查询示例
SELECT 
    f.flight_no,
    w.wind_speed,
    m.maintenance-&amp;gt;&amp;apos;last_check&amp;apos; AS last_maint,
    AVG(passenger_count) OVER (
        PARTITION BY route 
        ORDER BY dep_time 
        ROWS 7 PRECEDING
    ) AS avg_passengers
FROM postgres_fdw_flights f
JOIN s3_fdw_weather w 
  ON f.dep_airport = w.station_id 
 AND f.dep_time BETWEEN w.start AND w.end
JOIN mongo_fdw_maintenance m 
  ON f.aircraft_id = m.aircraft-&amp;gt;&amp;gt;&amp;apos;id&amp;apos;
WHERE f.status = &amp;apos;completed&amp;apos;;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;数据规模&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;实时处理 4000+ 航班/天&lt;/li&gt;
  &lt;li&gt;关联 10TB 历史气象数据&lt;/li&gt;
  &lt;li&gt;查询性能：复杂分析2s (vs 原 ETL 方案 25 分钟)&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;游戏玩家跨服对战系统&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;技术方案&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;每个游戏分区使用独立 PostgreSQL 实例&lt;/li&gt;
  &lt;li&gt;通过postgres_fdw 建立跨服视图：&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;CREATE FOREIGN TABLE jp_players (...) SERVER jp_node;
CREATE FOREIGN TABLE na_players (...) SERVER na_node;

-- 全服玩家排行榜
SELECT region, player_id, score 
FROM jp_players 
UNION ALL
SELECT region, player_id, score
FROM na_players
ORDER BY score DESC 
LIMIT 100;
&lt;/pre&gt;
 &lt;ul&gt;
  &lt;li&gt;实时跨服匹配：&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;SELECT 
    a.player_id AS p1,
    b.player_id AS p2,
    ABS(a.skill_level - b.skill_level) AS diff 
FROM global_players a
JOIN global_players b 
  ON a.region &amp;lt;&amp;gt; b.region 
 AND a.game_mode = b.game_mode
WHERE a.status = &amp;apos;waiting&amp;apos; 
  AND b.status = &amp;apos;waiting&amp;apos;
ORDER BY diff
LIMIT 100;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;成果&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;匹配延迟从 6s → 320ms&lt;/li&gt;
  &lt;li&gt;跨服对战参与率提升 41%&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;政府政务数据开放平台&lt;/h4&gt;
 &lt;p&gt;  &lt;strong&gt;安全架构&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="406" src="http://www.biaodianfu.com/wp-content/uploads/2025/04/fdw-2.png" width="1302"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;行级安全控制&lt;/strong&gt;：&lt;/p&gt;
 &lt;pre&gt;-- 创建安全视图
CREATE VIEW citizen_data AS
SELECT * FROM fdw_census 
WHERE city = current_setting(&amp;apos;user.city&amp;apos;);

-- 列级脱敏
CREATE FOREIGN TABLE fdw_tax (
    ssn TEXT,
    income NUMERIC,
    mask_ssn TEXT OPTIONS (mask &amp;apos;partial(0,4,&amp;apos;&amp;apos;XXXX&amp;apos;&amp;apos;)&amp;apos;)
) SERVER tax_server;

-- 查询示例
SELECT mask_ssn, income 
FROM fdw_tax 
WHERE income &amp;gt; 100000;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;成效&lt;/strong&gt;：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;数据开放种类从 15 类 → 127 类&lt;/li&gt;
  &lt;li&gt;跨部门查询响应速度提升 18 倍&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;关键成功要素&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;查询下推优化：通过EXPLAIN VERBOSE 验证 80% 以上条件过滤在源端执行&lt;/li&gt;
  &lt;li&gt;混合存储策略：热数据缓存（物化视图）+ 冷数据直连&lt;/li&gt;
  &lt;li&gt;连接池管理：使用pgbouncer 控制外部连接数在 50 以内&lt;/li&gt;
  &lt;li&gt;类型转换优化：为 JSONB 字段创建 GIN 索引加速查询&lt;/li&gt;
  &lt;li&gt;安全隔离：为每个 FDW 创建单独角色和权限&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;性能对比数据&lt;/h4&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;td&gt;    &lt;strong&gt;场景&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;传统ETL方案&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;FDW联邦查询&lt;/strong&gt;&lt;/td&gt;
   &lt;td&gt;    &lt;strong&gt;提升倍数&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;跨库JOIN(千万级)&lt;/td&gt;
   &lt;td&gt;12min&lt;/td&gt;
   &lt;td&gt;8.5s&lt;/td&gt;
   &lt;td&gt;85x&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;实时数据更新&lt;/td&gt;
   &lt;td&gt;小时级延迟&lt;/td&gt;
   &lt;td&gt;亚秒级&lt;/td&gt;
   &lt;td&gt;3600x&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;开发维护成本&lt;/td&gt;
   &lt;td&gt;15人月/年&lt;/td&gt;
   &lt;td&gt;3人月/年&lt;/td&gt;
   &lt;td&gt;5x&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;这些案例展现了 FDW 在构建现代数据架构中的核心价值：消除数据孤岛，释放数据流动性，同时保持查询的实时性与一致性。建议在实施时结合 pg_stat_activity 监控外部查询，并通过 pg_statio_user_tables 分析 IO 瓶颈，持续优化联邦查询性能。&lt;/p&gt;
 &lt;p&gt;参考链接：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;a href="https://pigsty.io/zh/blog/pg/pg-eat-db-world/"&gt;PostgreSQL正在吞噬数据库世界 | Pigsty&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://medium.com/@fengruohang/postgres-is-eating-the-database-world-157c204dcfc4"&gt;Postgres is eating the database world | by Vonng | Medium&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://ossrank.com/cat/368-postgresql-extension"&gt;PostgreSQL Ecosystem – OSSRank&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://github.com/Vonng/pigsty/discussions/333"&gt;Call for New PostgreSQL Extensions Vonng/pigsty · Discussion #333 · GitHub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://gist.github.com/joelonsql/e5aa27f8cc9bd22b8999b7de8aee9d47"&gt;1000+ PostgreSQL EXTENSIONs GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;div&gt;

  &lt;strong&gt;相关文章:&lt;/strong&gt;  &lt;ol&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/sql-date-and-time-functions.html" rel="bookmark" title="SQL &amp;#26085;&amp;#26399;/&amp;#26102;&amp;#38388;&amp;#22788;&amp;#29702;&amp;#20989;&amp;#25968;"&gt;SQL 日期/时间处理函数&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/hive-sql-guide.html" rel="bookmark" title="Hive SQL&amp;#31995;&amp;#32479;&amp;#21270;&amp;#23398;&amp;#20064;"&gt;Hive SQL系统化学习&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/spark-sql.html" rel="bookmark" title="Spark SQL &amp;#31995;&amp;#32479;&amp;#21270;&amp;#23398;&amp;#20064;"&gt;Spark SQL 系统化学习&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>器→工具 工具软件 postgresql</category>
      <guid isPermaLink="true">https://itindex.net/detail/63001-%E6%95%B0%E6%8D%AE%E5%BA%93-%E6%9C%AA%E6%9D%A5-postgresql</guid>
      <pubDate>Mon, 07 Apr 2025 20:44:25 CST</pubDate>
    </item>
    <item>
      <title>Python地理数据分析工具MovingPandas</title>
      <link>https://itindex.net/detail/62944-python-%E5%9C%B0%E7%90%86-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90</link>
      <description>&lt;p&gt;MovingPandas 是一个用于分析轨迹数据的 Python 库。它在处理和分析移动对象的时空数据方面非常强大，适用于地理信息系统（GIS）、时空数据分析和可视化等领域。它是在热门的地理数据处理库 GeoPandas 的基础上构建的，GeoPandas 本身是建立在Pandas数据处理库之上的。MovingPandas 旨在提供高效、易于使用的工具，以便分析和处理包含位置信息的时间序列数据。MovingPandas使得研究移动模式、路径分析、时空聚类等任务变得更加高效和直观。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="719" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/MovingPandas.png" width="977"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;核心功能：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;轨迹数据表示。MovingPandas 使用 GeoPandas GeoDataFrames 来表示轨迹数据。每条轨迹由一系列带有时间戳的点组成，形成一条时空路径。&lt;/li&gt;
  &lt;li&gt;轨迹分割。可以根据时间间隔、距离阈值等条件将轨迹分割成多个子轨迹。这对于处理长轨迹或者在某些关键事件发生前后进行分析非常有用。&lt;/li&gt;
  &lt;li&gt;轨迹特征提取。提供了多种方法来计算轨迹的特征，比如速度、加速度、方向变化等。这些特征在进行模式识别和行为分析时非常有用。&lt;/li&gt;
  &lt;li&gt;轨迹聚类。支持基于轨迹的聚类分析，可以识别出类似移动模式的轨迹群体。常用的聚类方法包括基于密度的聚类（DBSCAN）、分层聚类等。&lt;/li&gt;
  &lt;li&gt;轨迹可视化。通过与 Matplotlib 和 Folium 等库的集成，MovingPandas 能够提供强大的轨迹数据可视化功能，包括静态和交互式地图。&lt;/li&gt;
  &lt;li&gt;时空聚合。支持时空聚合分析，比如计算某个区域在特定时间段内的平均速度、轨迹数量等。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;MovingPandas的使用&lt;/h2&gt;
 &lt;h3&gt;MovingPandas的安装&lt;/h3&gt;
 &lt;p&gt;MovingPandas作者推荐在Python 3.7及以上环境下安装。请确保你的Python版本符合这一要求。如果你已经安装了Anaconda，可以使用conda命令来安装MovingPandas及其依赖包。&lt;/p&gt;
 &lt;pre&gt;conda install -c conda-forge movingpandas&lt;/pre&gt;
 &lt;p&gt;MovingPandas同样可以使用pip进行安装，但是不推荐，主要原因是其依赖环境较为复杂，使用pip安装可能会出现依赖项缺失或版本冲突的问题。因此，推荐使用conda进行安装。&lt;/p&gt;
 &lt;h3&gt;MovingPandas接口详解&lt;/h3&gt;
 &lt;h4&gt;MovingPandas.Trajectory对象&lt;/h4&gt;
 &lt;p&gt;在 MovingPandas 中，Trajectory 类是核心组件之一，主要用于表示和处理单个轨迹。Trajectory 对象是一个时间序列的集合，其中每个数据点代表轨迹上的一个位置，包含了位置信息（经纬度或其他地理空间参考）、时间戳和其他可能的属性（如速度、方向等）。因此，一个 Trajectory 对象是连续移动的点组成的线，这些点按照时间顺序排列。&lt;/p&gt;
 &lt;p&gt;Trajectory 对象的主要特性：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;时间索引：Trajectory 对象的索引通常是时间戳，这使得基于时间的查询和操作变得直观和高效。&lt;/li&gt;
  &lt;li&gt;空间位置：每个时间点对应一个空间位置，这通常是通过经纬度坐标表示的。&lt;/li&gt;
  &lt;li&gt;其他属性：除了时间和位置，还可以包含其他相关的数据列，如速度、加速度、方向等，这些信息对于分析移动行为至关重要。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;创建 Trajectory 对象通常涉及几个步骤，首先你可能需要有一个包含时空数据的pandas DataFrame。这个DataFrame应该至少包含三列：表示时间戳的列（通常会被设置为索引）、表示X坐标的列（如经度）、表示Y坐标的列（如纬度）。然后，你可以使用 MovingPandas 提供的函数或方法（如TrajectoryCollection.from_geodataframe()）来创建一个或多个 Trajectory 对象。&lt;/p&gt;
 &lt;p&gt;class movingpandas.Trajectory(df, traj_id, traj_id_col=None, obj_id=None, t=None, x=None, y=None, crs=’epsg:4326′, parent=None)&lt;/p&gt;
 &lt;p&gt;参数说明：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;df：具有GeoPandas的geometry坐标列和时间戳索引的GeoDataFrame，或Pandas的DataFrame。必填参数。&lt;/li&gt;
  &lt;li&gt;traj_id：任意类型，表示轨迹的唯一标识符。必填参数。&lt;/li&gt;
  &lt;li&gt;obj_id：任意类型，表示移动物体的唯一标识符。默认为 None。&lt;/li&gt;
  &lt;li&gt;t：表示包含时间戳的列名，默认为 None。&lt;/li&gt;
  &lt;li&gt;x：表示包含x坐标的列名，使用Pandas的DataFrame需指定。默认为 None。&lt;/li&gt;
  &lt;li&gt;y：表示包含y坐标的列名，使用Pandas的DataFrame需指定。默认为 None。&lt;/li&gt;
  &lt;li&gt;crs：表示 x/y 坐标的坐标参考系统。默认为 “epsg:4326″，即 WGS84。&lt;/li&gt;
  &lt;li&gt;parent：一个Trajectory 对象，表示父轨迹。默认为 None。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;基本信息与操作&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;copy(): 返回轨迹对象的一个副本。&lt;/li&gt;
  &lt;li&gt;drop(**kwargs) 方法用于从数据集中删除满足特定条件的行或列。&lt;/li&gt;
  &lt;li&gt;plot(self, *args, **kwargs): 绘制轨迹。&lt;/li&gt;
  &lt;li&gt;explore(*args, **kwargs) 方法用于以交互方式可视化和分析数据，支持多种参数和选项以定制显示。&lt;/li&gt;
  &lt;li&gt;is_latlon() 方法用于判断轨迹数据是否采用经纬度坐标系。&lt;/li&gt;
  &lt;li&gt;is_valid() 方法用于检查轨迹数据是否有效，例如是否包含必要的字段和合理的坐标。&lt;/li&gt;
  &lt;li&gt;size() 方法用于返回轨迹中包含的定位点数量。&lt;/li&gt;
  &lt;li&gt;get_crs() 方法用于获取当前地理数据集的坐标参考系统（CRS），返回一个描述该坐标系的对象或信息。&lt;/li&gt;
  &lt;li&gt;to_crs(self, crs): 转换轨迹的坐标参考系统。&lt;/li&gt;
  &lt;li&gt;get_column_names() 方法用于获取数据集中的所有列名，返回一个包含列名的列表。这个方法通常用于快速查看数据集的结构或在进行数据处理时动态获取列名。&lt;/li&gt;
  &lt;li&gt;get_direction_col() 方法用于获取表示方向数据的列，这些数据通常以角度或方位形式存储。&lt;/li&gt;
  &lt;li&gt;get_distance_col() 方法用于获取表示距离数据的列，这些数据通常用于计算或分析两点之间的距离。&lt;/li&gt;
  &lt;li&gt;get_speed_col() 方法用于获取表示对象速度的列名。&lt;/li&gt;
  &lt;li&gt;get_timedelta_col() 方法用于获取表示时间增量的列名。&lt;/li&gt;
  &lt;li&gt;get_traj_id_col() 方法用于获取表示轨迹标识符的列名。&lt;/li&gt;
  &lt;li&gt;get_geom_col() 方法用于获取表示几何数据的列，该列通常包含地理空间信息，如点、线或多边形。&lt;/li&gt;
  &lt;li&gt;get_angular_difference_col() 方法用于获取包含角度差异的列，这些差异通常用于分析方向或角度变化。&lt;/li&gt;
  &lt;li&gt;to_point_gdf(self): 返回包含轨迹点的GeoDataFrame。&lt;/li&gt;
  &lt;li&gt;to_line_gdf(columns=None) 方法用于将轨迹数据转换为 GeoDataFrame 格式的线条几何数据，可以选择包含特定的列。&lt;/li&gt;
  &lt;li&gt;to_linestring() 方法用于将轨迹数据转换为 LineString 对象，表示轨迹的线条几何形状。&lt;/li&gt;
  &lt;li&gt;to_linestringm_wkt() 方法用于将轨迹数据转换为包含 ZM（高程和度量）信息的 WKT（Well-Known Text）格式的 LineStringM 字符串。&lt;/li&gt;
  &lt;li&gt;to_mf_json(datetime_to_str=True, temporal_columns=None) 方法用于将轨迹数据转换为 Moving Features JSON 格式，可以选择将日期时间转换为字符串，并指定时间相关的列。&lt;/li&gt;
  &lt;li&gt;to_point_gdf(return_orig_tz=False) 方法将轨迹数据转换为 GeoDataFrame 格式的点几何数据，可以选择返回原始时区的时间。&lt;/li&gt;
  &lt;li&gt;to_traj_gdf(wkt=False, agg=False) 方法将轨迹数据转换为 GeoDataFrame 格式，可以选择生成 WKT 格式的几何数据或进行聚合处理。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;轨迹分析与聚合统计&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;get_bbox(self): 返回轨迹的范围 (bounding box)。&lt;/li&gt;
  &lt;li&gt;get_start_location(self): 返回轨迹的起始位置。&lt;/li&gt;
  &lt;li&gt;get_end_location(self): 返回轨迹的结束位置。&lt;/li&gt;
  &lt;li&gt;get_start_time() 方法用于获取时间序列数据或对象轨迹的起始时间。&lt;/li&gt;
  &lt;li&gt;get_end_time() 方法用于获取某个事件或过程的结束时间，通常返回一个时间戳或日期时间对象。&lt;/li&gt;
  &lt;li&gt;get_max(column) 方法用于获取指定列 column 中的最大值。&lt;/li&gt;
  &lt;li&gt;get_min(column) 方法用于获取指定列 column 中的最小值。&lt;/li&gt;
  &lt;li&gt;get_position_at(t, method=’interpolated’) 方法用于获取在时间点 t 处的对象位置，默认使用插值方法来计算位置。&lt;/li&gt;
  &lt;li&gt;get_row_at(t, method=’nearest’) 方法用于获取在时间点 t 附近的对象所在的行，默认使用最近邻方法来选择行。&lt;/li&gt;
  &lt;li&gt;get_length(units=(None, None, None, None)) 方法用于计算并获取几何对象的长度，可以接受多个单位参数来指定长度的测量单位。&lt;/li&gt;
  &lt;li&gt;get_mcp() 方法用于获取某个对象的最小凸包 (Minimum Convex Polygon, MCP)，通常用于地理空间分析中确定一组点的最小包围区域。&lt;/li&gt;
  &lt;li&gt;add_direction(self, overwrite=False): 计算并添加方向信息到轨迹数据中。&lt;/li&gt;
  &lt;li&gt;get_direction() 方法用于计算和获取两个地理点之间的方向或方位角，通常以度数表示。&lt;/li&gt;
  &lt;li&gt;get_duration(self): 返回轨迹的总时长。&lt;/li&gt;
  &lt;li&gt;add_distance(overwrite=False, name=’distance’, units=None)：计算并添加轨迹数据中相邻点之间的距离信息。&lt;/li&gt;
  &lt;li&gt;add_acceleration(self, overwrite=False, name=’acceleration’): 计算并添加加速度信息到轨迹数据中。&lt;/li&gt;
  &lt;li&gt;add_speed(self, overwrite=False): 计算并添加速度信息到轨迹数据中。&lt;/li&gt;
  &lt;li&gt;add_angular_difference(overwrite=False, name=’angular_difference’)：计算并添加轨迹中相邻点之间的角度差异信息到轨迹数据中。&lt;/li&gt;
  &lt;li&gt;add_timedelta(overwrite=False, name=’timedelta’) ：计算并添加轨迹数据中相邻点之间的时间差信息。&lt;/li&gt;
  &lt;li&gt;add_traj_id(overwrite=False) 方法用于为轨迹数据添加或覆盖轨迹ID列，以标识相同轨迹中的所有点。&lt;/li&gt;
  &lt;li&gt;get_segment_between(t1, t2) 方法用于获取在时间点 t1 和 t2 之间的对象轨迹或数据段。&lt;/li&gt;
  &lt;li&gt;get_linestring_between(t1, t2, method=’interpolated’) 方法用于生成并获取在时间点 t1 和 t2 之间的一条线串，默认使用插值方法。&lt;/li&gt;
  &lt;li&gt;get_sampling_interval() 方法用于获取时间序列数据中的采样时间间隔。&lt;/li&gt;
  &lt;li&gt;hausdorff_distance(other, units=(None, None, None, None)) 方法用于计算当前轨迹与另一个轨迹之间的Hausdorff距离，并允许指定单位。&lt;/li&gt;
  &lt;li&gt;hvplot(*args, **kwargs) 方法用于使用hvPlot库创建高度可定制的图形和可视化。&lt;/li&gt;
  &lt;li&gt;hvplot_pts(*args, **kwargs) 方法用于使用hvPlot库对地理点数据进行可视化并创建交互式图形。&lt;/li&gt;
  &lt;li&gt;interpolate_position_at(t) 方法用于在给定时间 t 处插值并返回轨迹的位置。&lt;/li&gt;
  &lt;li&gt;intersection(feature, point_based=False) 方法用于计算轨迹与给定地理特征的交集，并可以选择基于点的方式进行计算。&lt;/li&gt;
  &lt;li&gt;intersects(polygon) 方法用于判断轨迹是否与指定的多边形区域相交。&lt;/li&gt;
  &lt;li&gt;clip(self, polygon): 按多边形裁剪轨迹。&lt;/li&gt;
  &lt;li&gt;apply_offset_minutes(column, offset) 方法用于将指定列的时间值按给定的分钟数进行偏移调整。&lt;/li&gt;
  &lt;li&gt;apply_offset_seconds(column, offset) 方法用于将指定列的时间值按给定的秒数进行偏移调整。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;MovingPandas.TrajectoryCollection对象&lt;/h4&gt;
 &lt;p&gt;TrajectoryCollection 类是 MovingPandas 中用于表示多条轨迹的集合。它允许用户以集合的形式操作多条轨迹，支持对这些轨迹的批量处理和分析。&lt;/p&gt;
 &lt;p&gt;可以通过传递一系列 Trajectory 对象来创建一个 TrajectoryCollection。每个 Trajectory 对象代表一条轨迹，包含了时间和位置的信息。&lt;/p&gt;
 &lt;p&gt;class movingpandas.TrajectoryCollection(data, traj_id_col=None, obj_id_col=None, t=None, x=None, y=None, crs=’epsg:4326′, min_length=0, min_duration=None)&lt;/p&gt;
 &lt;p&gt;参数说明：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;data (list[Trajectory] 或 GeoDataFrame 或 DataFrame) – 包含 Trajectory 对象的列表，或一个包含轨迹 ID、点几何列和时间戳索引的 GeoDataFrame。&lt;/li&gt;
  &lt;li&gt;traj_id_col (string) – 包含轨迹 ID 的 GeoDataFrame 列名。&lt;/li&gt;
  &lt;li&gt;obj_id_col (string) – 包含移动对象 ID 的 GeoDataFrame 列名。&lt;/li&gt;
  &lt;li&gt;t (string) – 包含时间戳的 DataFrame 列名。&lt;/li&gt;
  &lt;li&gt;x (string) – 包含 x 坐标的 DataFrame 列名。&lt;/li&gt;
  &lt;li&gt;y (string) – 包含 y 坐标的 DataFrame 列名。&lt;/li&gt;
  &lt;li&gt;crs (string) – x/y 坐标的坐标参考系 (CRS)。&lt;/li&gt;
  &lt;li&gt;min_length (numeric) – 期望的轨迹最小长度。长度使用 CRS 单位计算，若 CRS 是地理坐标系（例如 EPSG:4326 WGS84），则长度以米为单位计算。（较短的轨迹将被丢弃。）&lt;/li&gt;
  &lt;li&gt;min_duration (timedelta) – 期望的轨迹最短持续时间。（较短的轨迹将被丢弃。）&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;相比MovingPandas.Trajectory多了一些方法：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;filter(predicate): 根据给定条件过滤轨迹集合。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;MovingPandas.TrajectoryCollectionAggregator对象&lt;/h4&gt;
 &lt;p&gt;MovingPandas.TrajectoryCollectionAggregator 是 MovingPandas 库中的一个类，主要用于对轨迹集合进行聚合操作。通过对轨迹数据进行空间和时间上的聚合，可以帮助用户有效地分析和总结移动模式。&lt;/p&gt;
 &lt;p&gt;class movingpandas.TrajectoryCollectionAggregator(traj_collection, max_distance, min_distance, min_stop_duration, min_angle=45)&lt;/p&gt;
 &lt;p&gt;参数说明&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;traj_collection (TrajectoryCollection) – 要进行聚合的 TrajectoryCollection 对象。&lt;/li&gt;
  &lt;li&gt;max_distance (float) – 重要点之间的最大距离（距离使用 CRS 单位计算，若 CRS 是地理坐标系，例如 EPSG:4326 WGS84，则距离以米为单位计算）。&lt;/li&gt;
  &lt;li&gt;min_distance (float) – 重要点之间的最小距离。&lt;/li&gt;
  &lt;li&gt;min_stop_duration (datetime.timedelta) – 停止检测所需的最短持续时间。&lt;/li&gt;
  &lt;li&gt;min_angle (float) – 提取重要点的最小角度。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;相关方法：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;get_clusters_gdf() 方法返回一个 GeoDataFrame，其中包含聚合后的轨迹数据的簇（clusters）。&lt;/li&gt;
  &lt;li&gt;get_flows_gdf() 方法返回一个 GeoDataFrame，其中包含聚合后的轨迹数据的流动（flows）信息。&lt;/li&gt;
  &lt;li&gt;get_significant_points_gdf() 方法返回一个 GeoDataFrame，其中包含从轨迹数据中提取的显著点（significant points）。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;MovingPandas.TrajectoryCleaner对象&lt;/h4&gt;
 &lt;p&gt;MovingPandas.TrajectoryCleaner 是 MovingPandas 库中的一个类，专门用于清理轨迹数据。清理操作可以帮助去除数据中的噪声、填补缺失值以及进行其他预处理步骤，确保轨迹数据的质量和一致性。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;IqrCleaner(traj) 是一个类，用于基于四分位数范围 (IQR) 方法来清理轨迹数据中的异常值。&lt;/li&gt;
  &lt;li&gt;OutlierCleaner(traj) 是一个类，用于通过多种方法识别和清理轨迹数据中的离群点（异常值）。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;MovingPandas.TrajectoryGeneralizer对象&lt;/h4&gt;
 &lt;p&gt;MovingPandas.TrajectoryGeneralizer 是 MovingPandas 库中的一个类，用于对轨迹数据进行简化和概括。通过轨迹数据的概括，可以减少数据量，提高处理效率，并且在某些应用场景下有助于更清晰地展示轨迹特征。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;TrajectoryGeneralizer(traj) 是一个类，用于通过多种算法对轨迹数据进行简化和概括，以减少数据量并提高处理效率。&lt;/li&gt;
  &lt;li&gt;DouglasPeuckerGeneralizer(traj) 是一个类，专门使用 Douglas-Peucker 算法对轨迹数据进行简化，保留主要特征点以减少数据量。&lt;/li&gt;
  &lt;li&gt;MinDistanceGeneralizer(traj) 是一个类，用于根据最小距离间隔对轨迹数据进行简化，移除距离变化小于指定阈值的点。&lt;/li&gt;
  &lt;li&gt;MinTimeDeltaGeneralizer(traj) 是一个类，用于根据最小时间间隔对轨迹数据进行简化，移除时间间隔小于指定阈值的点。&lt;/li&gt;
  &lt;li&gt;TopDownTimeRatioGeneralizer(traj) 是一个类，用于通过时间比率算法对轨迹数据进行简化，保留关键时间点以减少数据量。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;MovingPandas.TrajectorySmoother对象&lt;/h4&gt;
 &lt;p&gt;MovingPandas.TrajectorySmoother 是一个类，用于对轨迹数据进行平滑处理。轨迹平滑通常是为了减少由于数据采集误差和噪声导致的轨迹抖动和异常点，从而得到更加平滑和准确的轨迹线条。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;KalmanSmootherCV(traj) 是一个类，用于使用常速模型（Constant Velocity Model）的卡尔曼滤波算法对轨迹数据进行平滑处理，以减少噪声和抖动。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;MovingPandas.TrajectorySplitter对象&lt;/h4&gt;
 &lt;p&gt;MovingPandas.TrajectorySplitter 是一个类，用于将轨迹数据根据特定条件进行分割。这在处理长时间、多段的轨迹数据时特别有用，比如在分析车辆行驶路径、运动员运动轨迹或动物迁徙路径时，可以根据特定的规则将连续的轨迹分割成多个部分，以便进行更细致的分析。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;TrajectorySplitter(traj) 是一个类，用于根据指定的条件（如距离、时间或速度）对轨迹数据进行分割，生成多个段以便更细致的分析。&lt;/li&gt;
  &lt;li&gt;TemporalSplitter(traj) 是一个类，用于根据时间间隔对轨迹数据进行分割，将轨迹分成多个时间段以便更细致的时间序列分析。&lt;/li&gt;
  &lt;li&gt;ObservationGapSplitter(traj) 是一个类，用于根据观测数据中的时间间隙对轨迹进行分割，当连续观测点之间的时间间隔超过指定阈值时，将轨迹分割成多个部分。&lt;/li&gt;
  &lt;li&gt;SpeedSplitter(traj) 是一个类，用于根据速度阈值对轨迹数据进行分割，当轨迹点的速度超过指定阈值时，将轨迹分割成多个部分。&lt;/li&gt;
  &lt;li&gt;StopSplitter(traj) 是一个类，用于根据停留点（长时间停留的点）对轨迹数据进行分割，将轨迹分成移动段和停留段以便更细致的分析。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;MovingPandas.TrajectoryStopDetector对象&lt;/h4&gt;
 &lt;p&gt;TrajectoryStopDetector 通过分析轨迹点的时空属性来识别停留点。它会检查一个轨迹对象中的每个点，并根据设定的阈值参数（如最小速度、最小停留时间和最小停留距离等）来鉴定轨迹中是否存在停留段。&lt;/p&gt;
 &lt;p&gt;class movingpandas.TrajectoryStopDetector(traj, n_threads=1)&lt;/p&gt;
 &lt;p&gt;方法介绍：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;get_stop_points(max_diameter, min_duration) 是 TrajectoryStopDetector 类中的方法，用于根据最大停留直径和最小持续时间来识别和提取轨迹数据中的停留点，并返回包含这些停留点的 GeoDataFrame。&lt;/li&gt;
  &lt;li&gt;get_stop_segments(max_diameter, min_duration) 是 TrajectoryStopDetector 类中的方法，用于根据最大停留直径和最小持续时间来识别和提取轨迹中的停留段，并返回包含这些停留段的列表。&lt;/li&gt;
  &lt;li&gt;get_stop_time_ranges(max_diameter, min_duration) 是 TrajectoryStopDetector 类中的方法，用于根据最大停留直径和最小持续时间来识别停留时间范围，并返回停留时间段的列表。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;MovingPandas使用实例&lt;/h2&gt;
 &lt;h3&gt;准备工作&lt;/h3&gt;
 &lt;p&gt;  &lt;strong&gt;加载需要的库&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;import pandas as pd
import geopandas as gpd
import movingpandas as mpd
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import folium
import bokeh.io
bokeh.io.output_notebook()
from holoviews import opts
opts.defaults(opts.Overlay(active_tools=[&amp;quot;wheel_zoom&amp;quot;], frame_width=500, frame_height=400))
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;加载数据&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;df = pd.read_excel(&amp;quot;driver_log.xlsx&amp;quot;)

# 将DataFrame 转换为 GeoDataFrame
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.lon, df.lat), crs=&amp;apos;EPSG:4326&amp;apos;)

# 将GeoDataFrame转化为TrajectoryCollection对象
tc = mpd.TrajectoryCollection(gdf, traj_id_col=&amp;apos;session_id&amp;apos;, obj_id_col = &amp;apos;driver_no&amp;apos;, t=&amp;apos;log_time&amp;apos;)
# 过滤某个司机的轨迹
df[&amp;apos;driver_no&amp;apos;].value_counts()
df[&amp;apos;driver_no&amp;apos;].value_counts().plot(kind=&amp;apos;bar&amp;apos;, figsize=(15,3))
driver_tc = tc.filter(&amp;apos;driver_no&amp;apos;, &amp;apos;DR202407021504081000000&amp;apos;)

# 展示司机轨迹
driver_tc.plot()
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="413" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/driver_traj.png" width="450"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;# 获取单个轨迹
my_traj = driver_tc.trajectories[0]

# 展示单个轨迹
traj_plot = my_traj.hvplot(title=&amp;quot;Trajectory {}&amp;quot;.format(my_traj.id),line_width=7.0, tiles=&amp;quot;CartoLight&amp;quot;, color=&amp;quot;slategray&amp;quot;)
traj_plot
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="636" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/my_traj.png" width="815"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;停留点检测&lt;/h3&gt;
 &lt;p&gt;  &lt;strong&gt;针对单轨迹停留点检测&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;detector = mpd.TrajectoryStopDetector(my_traj)
## 检测停留的时间（这里检测5分钟位移100米以内）
stop_time_ranges = detector.get_stop_time_ranges(min_duration=timedelta(seconds=300), max_diameter=100)
## 检测停留的时间
for stop_time in stop_time_ranges:
    print(stop_time)
## 检测停留点
stop_points = detector.get_stop_points(min_duration=timedelta(seconds=300), max_diameter=100)
stop_points
## 展示停留点
stop_point_plot = traj_plot * stop_points.hvplot(geo=True, size=&amp;quot;duration_s&amp;quot;, color=&amp;quot;deeppink&amp;quot;)
stop_point_plot
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="631" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/stop-point.png" width="817"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 停留点信息
stop_points_gdf = gpd.GeoDataFrame(stop_points, geometry=&amp;quot;geometry&amp;quot;, crs=&amp;quot;EPSG:4326&amp;quot;)
stop_points_gdf
## 使用folium展示停留点
# m = my_traj.explore(color=&amp;quot;blue&amp;quot;,style_kwds={&amp;quot;weight&amp;quot;: 4},name=&amp;quot;Trajectory&amp;quot;)
# stop_points_gdf.explore(m=m,color=&amp;quot;red&amp;quot;,style_kwds={&amp;quot;style_function&amp;quot;: lambda x: {&amp;quot;radius&amp;quot;: x[&amp;quot;properties&amp;quot;][&amp;quot;duration_s&amp;quot;] / 10 }},name=&amp;quot;Stop points&amp;quot;)
# folium.TileLayer(&amp;quot;OpenStreetMap&amp;quot;).add_to(m)
# folium.LayerControl().add_to(m)
# m
## 停留轨迹
stop_segments = detector.get_stop_segments(min_duration=timedelta(seconds=60), max_diameter=100)
stop_segments.to_traj_gdf()
## 停留轨迹
stop_segment_plot = stop_point_plot * stop_segments.hvplot(line_width=7.0, tiles=None, color=&amp;quot;orange&amp;quot;)
stop_segment_plot
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="629" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/stop_segment.png" width="811"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 使用folium绘图
# m = my_traj.explore(
#     color=&amp;quot;blue&amp;quot;,
#     popup=True,
#     style_kwds={&amp;quot;weight&amp;quot;: 4},
#     name=&amp;quot;Trajectory&amp;quot;,
# )

# stop_segments.explore(
#     m=m,
#     color=&amp;quot;orange&amp;quot;,
#     popup=True,
#     style_kwds={&amp;quot;weight&amp;quot;: 4},
#     name=&amp;quot;Stop segments&amp;quot;,
# )

# stop_points_gdf.explore(
#     m=m,
#     color=&amp;quot;red&amp;quot;,
#     tooltip=&amp;quot;stop_id&amp;quot;,
#     popup=True,
#     marker_kwds={&amp;quot;radius&amp;quot;: 3},
#     name=&amp;quot;Stop points&amp;quot;,
# )

# folium.TileLayer(&amp;quot;CartoDB positron&amp;quot;).add_to(m)
# folium.LayerControl().add_to(m)

# m

## 行驶线路
split = mpd.StopSplitter(my_traj).split(min_duration=timedelta(seconds=300), max_diameter=100)
split.to_traj_gdf()
## 可视化行驶线路
split.explore(column=&amp;quot;session_id&amp;quot;, tiles=&amp;quot;CartoDB positron&amp;quot;, style_kwds={&amp;quot;weight&amp;quot;: 4})

## 整体可视化
stop_segment_plot + split.hvplot(title=&amp;quot;Trajectory {} split at stops&amp;quot;.format(my_traj.id),line_width=7.0,tiles=&amp;quot;CartoLight&amp;quot;)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="457" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/stop_segment_plot.png" width="1058"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;轨迹合集的经停点检测&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;## 停留点检测
detector = mpd.TrajectoryStopDetector(driver_tc)
stop_points = detector.get_stop_points(min_duration=timedelta(seconds=300), max_diameter=100)
stop_points
## 停留点可视化
ax = driver_tc.plot(figsize=(7, 7))
stop_points.plot(ax=ax, color=&amp;quot;red&amp;quot;)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="486" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/TrajectoryStopDetector.png" width="603"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 使用folium可视化
## 使用方folium可视化
# m = driver_tc.explore(
#     column=&amp;quot;session_id&amp;quot;,
#     popup=True,
#     style_kwds={&amp;quot;weight&amp;quot;: 4},
#     name=&amp;quot;Trajectories&amp;quot;,
# )

# stop_points.explore(
#     m=m,
#     color=&amp;quot;red&amp;quot;,
#     tooltip=&amp;quot;stop_id&amp;quot;,
#     popup=True,
#     marker_kwds={&amp;quot;radius&amp;quot;: 5},
#     name=&amp;quot;Stop points&amp;quot;,
# )

# folium.TileLayer(&amp;quot;CartoDB positron&amp;quot;).add_to(m)
# folium.LayerControl().add_to(m)

# m
&lt;/pre&gt;
 &lt;h3&gt;速度计算&lt;/h3&gt;
 &lt;pre&gt;## 单轨迹增加速度
my_traj.add_speed(overwrite=True,units=(&amp;quot;km&amp;quot;, &amp;quot;h&amp;quot;))
my_traj.df.head()

## 展示速度
my_traj.plot(column=&amp;quot;speed&amp;quot;, linewidth=5, capstyle=&amp;apos;round&amp;apos;, legend=True)
# my_traj.hvplot(c=&amp;apos;speed&amp;apos;, clim=(0,20), line_width=7.0, tiles=&amp;apos;CartoLight&amp;apos;, cmap=&amp;apos;Viridis&amp;apos;, colorbar=True)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="404" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/speed.png" width="546"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 添加方向
my_traj.add_direction(overwrite=True)
my_traj.df.head()

## 添加时差
my_traj.add_timedelta(overwrite=True)
my_traj.df.head()

## 添加距离
my_traj.add_distance(overwrite=True, name=&amp;quot;distance (km)&amp;quot;, units=&amp;quot;m&amp;quot;)
my_traj.df.head()

## 添加加速度
my_traj.add_acceleration(overwrite=True, name=&amp;quot;acceleration (mph/s)&amp;quot;, units=(&amp;quot;mi&amp;quot;, &amp;quot;h&amp;quot;, &amp;quot;s&amp;quot;))
my_traj.df.head()

## 轨迹集增加速度
driver_tc.add_speed(overwrite=True,units=(&amp;quot;km&amp;quot;, &amp;quot;h&amp;quot;))
driver_tc.plot(column=&amp;apos;speed&amp;apos;, linewidth=5, capstyle=&amp;apos;round&amp;apos;, legend=True, vmax=20)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="418" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/speed2.png" width="534"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;提取位置&lt;/h3&gt;
 &lt;pre&gt;## 获取起点与终点
ax = my_traj.plot()
gpd.GeoSeries(my_traj.get_start_location()).plot(ax=ax, color=&amp;apos;blue&amp;apos;)
gpd.GeoSeries(my_traj.get_end_location()).plot(ax=ax, color=&amp;apos;red&amp;apos;)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="417" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/location.png" width="574"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 获取特定时间点的位置
t = datetime(2024,7,3,9,30,0)
print(my_traj.get_position_at(t, method=&amp;quot;nearest&amp;quot;))
print(my_traj.get_position_at(t, method=&amp;quot;interpolated&amp;quot;))
print(my_traj.get_position_at(t, method=&amp;quot;ffill&amp;quot;)) # from the previous row
print(my_traj.get_position_at(t, method=&amp;quot;bfill&amp;quot;)) # from the following row

point = my_traj.get_position_at(t, method=&amp;quot;interpolated&amp;quot;)
ax = my_traj.plot()
gpd.GeoSeries(point).plot(ax=ax, color=&amp;apos;red&amp;apos;, markersize=100)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="417" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/time-point.png" width="574"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 获取特定时间区间的位置
segment = my_traj.get_segment_between(datetime(2024,7,3,9,10,0), datetime(2024,7,3,9,30,0))
print(segment)
ax = my_traj.plot()
segment.plot(ax=ax, color=&amp;apos;red&amp;apos;, linewidth=5)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="446" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/segment.png" width="542"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 获取特定区域内的轨迹
from shapely.geometry import Polygon

xmin, xmax, ymin, ymax = 104.135, 104.137, 30.642, 30.643
polygon = Polygon([(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin), (xmin, ymin)])
intersections = my_traj.clip(polygon)
ax = my_traj.plot()
gpd.GeoSeries(polygon).plot(ax=ax, color=&amp;apos;lightgray&amp;apos;)
intersections.plot(ax=ax, color=&amp;apos;red&amp;apos;, linewidth=5, capstyle=&amp;apos;round&amp;apos;)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="446" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/intersections.png" width="542"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;导出轨迹&lt;/h3&gt;
 &lt;pre&gt;## 返回 GeoDataFrame
driver_tc.to_point_gdf()
driver_tc.to_line_gdf()
driver_tc.to_traj_gdf(wkt=True) # 生成wkt格式的聚合

# 聚合数据
driver_tc.add_speed(overwrite=True,units=(&amp;quot;km&amp;quot;, &amp;quot;h&amp;quot;))
driver_tc.to_traj_gdf(agg={&amp;apos;speed&amp;apos;:[&amp;apos;min&amp;apos;, &amp;apos;max&amp;apos;,&amp;apos;mode&amp;apos;]})

# 导出数据
export_gdf = driver_tc.to_traj_gdf(agg={&amp;apos;speed&amp;apos;:[&amp;apos;min&amp;apos;, &amp;apos;max&amp;apos;,&amp;apos;mode&amp;apos;]})
export_gdf.to_file(&amp;quot;temp.gpkg&amp;quot;, layer=&amp;apos;trajectories&amp;apos;, driver=&amp;quot;GPKG&amp;quot;)
gpd.read_file(&amp;apos;temp.gpkg&amp;apos;).plot()
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="413" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/export_gdf.png" width="450"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;轨迹分割&lt;/h3&gt;
 &lt;pre&gt;## 数据准备
my_traj.add_speed(overwrite=True,units=(&amp;quot;km&amp;quot;, &amp;quot;h&amp;quot;))
my_traj.plot(column=&amp;apos;speed&amp;apos;, vmax=20, linewidth=5, capstyle=&amp;apos;round&amp;apos;, figsize=(9,3), legend=True )
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="308" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/my_traj.plot_.png" width="455"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 根据观测数据中的时间间隙对轨迹进行分割
split = mpd.ObservationGapSplitter(my_traj).split(gap=timedelta(minutes=1))
split.to_traj_gdf()
fig, axes = plt.subplots(nrows=1, ncols=len(split), figsize=(19,4))
for i, traj in enumerate(split):
    traj.plot(ax=axes[i], linewidth=5.0, capstyle=&amp;apos;round&amp;apos;, column=&amp;apos;speed&amp;apos;, vmax=20)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="288" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/split.png" width="1047"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 根据停留点（长时间停留的点）对轨迹数据进行分割
split = mpd.StopSplitter(my_traj).split(max_diameter=10, min_duration=timedelta(minutes=1), min_length=20)
split.to_traj_gdf()
fig, axes = plt.subplots(nrows=1, ncols=len(split), figsize=(19,4))
for i, traj in enumerate(split):
    traj.plot(ax=axes[i], linewidth=5.0, capstyle=&amp;apos;round&amp;apos;, column=&amp;apos;speed&amp;apos;, vmax=20)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="269" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/split2.png" width="1055"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 根据速度阈值对轨迹数据进行分割
split = mpd.SpeedSplitter(my_traj).split(speed=0, duration=timedelta(minutes=1))
split.to_traj_gdf()
fig, axes = plt.subplots(nrows=1, ncols=len(split), figsize=(19,4))
for i, traj in enumerate(split):
    traj.plot(ax=axes[i], linewidth=5.0, capstyle=&amp;apos;round&amp;apos;, column=&amp;apos;speed&amp;apos;, vmax=20)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="284" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/split3.png" width="1031"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;轨迹抽稀&lt;/h3&gt;
 &lt;pre&gt;## 展示原始轨迹
plot_defaults = {&amp;apos;linewidth&amp;apos;:5, &amp;apos;capstyle&amp;apos;:&amp;apos;round&amp;apos;, &amp;apos;figsize&amp;apos;:(9,3), &amp;apos;legend&amp;apos;:True}
my_traj.add_speed(overwrite=True,units=(&amp;quot;km&amp;quot;, &amp;quot;h&amp;quot;))
my_traj.plot(column=&amp;apos;speed&amp;apos;, vmax=20, **plot_defaults)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="308" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/plot_defaults.png" width="455"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 使用 Douglas-Peucker 算法对轨迹数据进行简化
dp_generalized  = mpd.DouglasPeuckerGeneralizer(my_traj).generalize(tolerance=0.0001)
dp_generalized.plot(column=&amp;apos;speed&amp;apos;, vmax=20, **plot_defaults)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="308" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/dp_generalized.png" width="448"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;print(&amp;apos;Original length: %s&amp;apos;%(my_traj.get_length()))
print(&amp;apos;Generalized length: %s&amp;apos;%(dp_generalized.get_length()))

## 根据最小时间间隔对轨迹数据进行简化
time_generalized = mpd.MinTimeDeltaGeneralizer(my_traj).generalize(tolerance=timedelta(minutes=3))
time_generalized.plot(column=&amp;apos;speed&amp;apos;, vmax=20, **plot_defaults)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="308" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/time_generalized.png" width="448"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 通过时间比率算法对轨迹数据进行简化
tdtr_generalized = mpd.TopDownTimeRatioGeneralizer(my_traj).generalize(tolerance=0.001)
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(19,4))
tdtr_generalized.plot(ax=axes[0], column=&amp;apos;speed&amp;apos;, vmax=20, **plot_defaults)
dp_generalized.plot(ax=axes[1], column=&amp;apos;speed&amp;apos;, vmax=20, **plot_defaults)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="344" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/tdtr_generalized.png" width="1198"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(19,4))
tdtr_generalized.plot(ax=axes[0], column=&amp;apos;speed&amp;apos;, vmax=20, **plot_defaults)
time_generalized.plot(ax=axes[1], column=&amp;apos;speed&amp;apos;, vmax=20, **plot_defaults)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="344" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/tdtr_generalized.plot_.png" width="1199"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;平滑轨迹&lt;/h3&gt;
 &lt;pre&gt;split = mpd.ObservationGapSplitter(my_traj).split(gap=timedelta(minutes=1))
smooth = mpd.KalmanSmootherCV(split).smooth(process_noise_std=0.1, measurement_noise_std=10)
hvplot_defaults = {&amp;apos;tiles&amp;apos;:&amp;apos;CartoLight&amp;apos;, &amp;apos;frame_height&amp;apos;:320, &amp;apos;frame_width&amp;apos;:320, &amp;apos;cmap&amp;apos;:&amp;apos;Viridis&amp;apos;, &amp;apos;colorbar&amp;apos;:True}
kwargs = {**hvplot_defaults, &amp;apos;line_width&amp;apos;:4}
(split.hvplot(title=&amp;apos;Original Trajectories&amp;apos;, **kwargs) +  smooth.hvplot(title=&amp;apos;Smooth Trajectories&amp;apos;, **kwargs))
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="378" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/smooth.png" width="733"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;kwargs = {**hvplot_defaults, &amp;apos;c&amp;apos;:&amp;apos;speed&amp;apos;, &amp;apos;line_width&amp;apos;:7, &amp;apos;clim&amp;apos;:(0,20)}
(split.trajectories[1].hvplot(title=&amp;apos;Original Trajectory&amp;apos;, **kwargs) + smooth.trajectories[1].hvplot(title=&amp;apos;Smooth Trajectory&amp;apos;, **kwargs))
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="380" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/split.trajectories.png" width="846"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;traj = split.trajectories[1]

cleaned = traj.copy()
cleaned = mpd.OutlierCleaner(cleaned).clean(alpha=2)

smoothed = mpd.KalmanSmootherCV(cleaned).smooth(process_noise_std=0.1, measurement_noise_std=10)
    
(traj.hvplot(title=&amp;apos;Original Trajectory&amp;apos;, **kwargs) + 
 cleaned.hvplot(title=&amp;apos;Cleaned Trajectory&amp;apos;, **kwargs) + 
 smoothed.hvplot(title=&amp;apos;Cleaned &amp;amp; Smoothed Trajectory&amp;apos;, **kwargs))
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="386" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/smoothed.png" width="1301"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;轨迹聚类和分类&lt;/h3&gt;
 &lt;pre&gt;## 查看数据
driver_tc.explore(column=&amp;quot;session_id&amp;quot;, cmap=&amp;quot;plasma&amp;quot;, style_kwds={&amp;quot;weight&amp;quot;: 4})
## 根据最小距离间隔对轨迹数据进行简化
generalized = mpd.MinDistanceGeneralizer(driver_tc).generalize(tolerance=100)
generalized.to_traj_gdf()

## 对轨迹进行聚合操作
aggregator = mpd.TrajectoryCollectionAggregator(
    generalized,
    max_distance=1000,
    min_distance=100,
    min_stop_duration=timedelta(minutes=10),
)

## 提取显著点
pts = aggregator.get_significant_points_gdf()
pts.hvplot(geo=True, tiles=&amp;quot;OSM&amp;quot;)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="634" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/pts.png" width="819"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 获取聚合轨迹的簇
clusters = aggregator.get_clusters_gdf()
(pts.hvplot(geo=True, tiles=&amp;quot;OSM&amp;quot;) * clusters.hvplot(geo=True, color=&amp;quot;red&amp;quot;))
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="638" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/clusters.png" width="815"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 使用folium绘制
# m = pts.explore(marker_kwds={&amp;quot;radius&amp;quot;: 3}, name=&amp;quot;Significant points&amp;quot;)
# clusters.explore(m=m, color=&amp;quot;red&amp;quot;, marker_kwds={&amp;quot;radius&amp;quot;: 3}, name=&amp;quot;Cluster centroids&amp;quot;)
# folium.TileLayer(&amp;quot;CartoDB positron&amp;quot;).add_to(m)
# folium.LayerControl().add_to(m)
# m

## 获取聚合后的轨迹数据的流动
flows = aggregator.get_flows_gdf()
(flows.hvplot(geo=True, hover_cols=[&amp;quot;weight&amp;quot;], line_width=dim(&amp;quot;weight&amp;quot;) * 7, color=&amp;quot;#1f77b3&amp;quot;,tiles=&amp;quot;CartoLight&amp;quot;) * clusters.hvplot(geo=True, color=&amp;quot;red&amp;quot;, size=dim(&amp;quot;n&amp;quot;)))
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="626" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/flows.png" width="829"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 使用Folium绘制
# m = flows.explore(style_kwds={&amp;quot;weight&amp;quot;: 5},name=&amp;quot;Flows&amp;quot;)
# clusters.explore( m=m,color=&amp;quot;red&amp;quot;,style_kwds={&amp;quot;style_function&amp;quot;: lambda x: {&amp;quot;radius&amp;quot;: x[&amp;quot;properties&amp;quot;][&amp;quot;n&amp;quot;]}}, name=&amp;quot;Clusters&amp;quot;)
# folium.TileLayer(&amp;quot;OpenStreetMap&amp;quot;).add_to(m)
# folium.LayerControl().add_to(m)
# m
&lt;/pre&gt;
 &lt;h3&gt;距离计算&lt;/h3&gt;
 &lt;pre&gt;## 选择2个轨迹
my_traj = driver_tc.trajectories[3]
toy_traj = driver_tc.trajectories[1]
## 呈现数据
ax = my_traj.plot()
toy_traj.plot(ax=ax, color=&amp;apos;red&amp;apos;)
&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" height="343" src="https://www.biaodianfu.com/wp-content/uploads/2024/10/toy_traj.plot_.png" width="565"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;## 计算记录
print(f&amp;apos;Distance: {toy_traj.distance(my_traj)} meters&amp;apos;) # 返回最短距离
print(f&amp;apos;Hausdorff distance: {toy_traj.hausdorff_distance(my_traj):.2f} meters&amp;apos;) # 返回Hausdorff距离
&lt;/pre&gt;
 &lt;p&gt;Hausdorff距离可以理解为：对于集合A 中的每个点，计算它到集合B的最近距离，然后在这些距离中找到最大值；反过来对于集合 B 中的每个点，计算它到集合A 的最近距离，然后在这些距离中找到最大值。Hausdorff距离是这两个最大值中的较大者。&lt;/p&gt;
 &lt;p&gt;参考链接：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;a href="https://github.com/movingpandas/movingpandas"&gt;movingpandas/movingpandas: Movement trajectory classes and functions built on top of GeoPandas (github.com)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://movingpandas.org/"&gt;MovingPandas | A Python library for movement data exploration and analysis&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://movingpandas.org/examples.html"&gt;Tutorials | MovingPandas&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://movingpandas.readthedocs.io/en/main/"&gt;MovingPandas Documentation — MovingPandas main documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;div&gt;

  &lt;h3&gt;相关文章:&lt;/h3&gt;  &lt;ol&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/seaborn.html" rel="bookmark" title="Python&amp;#25968;&amp;#25454;&amp;#21487;&amp;#35270;&amp;#21270;&amp;#20043;Seaborn"&gt;Python数据可视化之Seaborn&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/learn-css.html" rel="bookmark" title="CSS&amp;#20307;&amp;#31995;&amp;#21270;&amp;#23398;&amp;#20064;"&gt;CSS体系化学习&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/arima.html" rel="bookmark" title="&amp;#26102;&amp;#38388;&amp;#24207;&amp;#21015;&amp;#39044;&amp;#27979;&amp;#20043;ARIMA"&gt;时间序列预测之ARIMA&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>器→工具 工具软件 开源项目 GIS</category>
      <guid isPermaLink="true">https://itindex.net/detail/62944-python-%E5%9C%B0%E7%90%86-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90</guid>
      <pubDate>Wed, 09 Oct 2024 19:54:20 CST</pubDate>
    </item>
    <item>
      <title>开源可视化报表工具：Superset</title>
      <link>https://itindex.net/detail/62903-%E5%BC%80%E6%BA%90-%E5%8F%AF%E8%A7%86%E5%8C%96-%E5%B7%A5%E5%85%B7</link>
      <description>&lt;h2&gt;Superset简介&lt;/h2&gt;
 &lt;p&gt;Superset 是一个开源的数据可视化和数据探索平台，最初由 Airbnb 开发，后来成为了 Apache 软件基金会的顶级项目。它支持各种类型的数据源，如数据库和 SQL 引擎，并提供了一个易于使用的界面来创建和共享仪表板和图表。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="528" src="https://www.biaodianfu.com/wp-content/uploads/2024/01/superset-1.jpg" width="780"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;主要特点包括：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;数据可视化: Superset 提供了丰富的图表库，支持从简单的折线图和条形图到更复杂的地理信息系统 (GIS) 可视化等。&lt;/li&gt;
  &lt;li&gt;数据探索: 用户可以通过 Superset 的 SQL 编辑器执行查询，探索数据，并将结果可视化。&lt;/li&gt;
  &lt;li&gt;仪表板: 可以将多个图表组合成仪表板，为数据分析提供全面视图。&lt;/li&gt;
  &lt;li&gt;安全性和权限管理: Superset 支持细粒度的访问控制，允许管理员定义用户和角色，控制对数据和功能的访问。&lt;/li&gt;
  &lt;li&gt;易于集成: 作为一个开源工具，Superset 可以与多种数据源和其他数据工具集成。&lt;/li&gt;
  &lt;li&gt;自定义和扩展: 用户可以根据需要自定义图表和界面，并且可以开发新的可视化插件。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;Superset 适用于数据分析师和开发人员，帮助他们快速有效地探索和可视化数据，从而做出更好的数据驱动决策。&lt;/p&gt;
 &lt;p&gt;看板示例：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="447" src="https://www.biaodianfu.com/wp-content/uploads/2024/01/superset-2.jpg" width="780"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;拖拽式看板编辑器：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="414" src="https://www.biaodianfu.com/wp-content/uploads/2024/01/superset-3.jpg" width="780"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;SQL编辑器：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="546" src="https://www.biaodianfu.com/wp-content/uploads/2024/01/sql-lab.jpg" width="780"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;Superset架构&lt;/h2&gt;
 &lt;p&gt;Apache Superset 是一款开源的数据可视化和数据探索平台，它的架构设计允许用户轻松地进行数据分析并创建交互式的仪表板。Superset的架构主要由以下几个核心组件构成：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="464" src="https://www.biaodianfu.com/wp-content/uploads/2024/01/superset-4-1.png" width="780"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Web服务器&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Flask：Superset使用Flask作为其Web框架，处理HTTP请求和渲染界面。&lt;/li&gt;
  &lt;li&gt;Gunicorn：在生产环境中，通常使用Gunicorn作为WSGI HTTP服务器来运行Flask应用。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;SQL查询引擎&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;SQLAlchemy：Superset通过SQLAlchemy与数据源进行交互，它支持多种数据库。&lt;/li&gt;
  &lt;li&gt;Pandas：在某些情况下，Superset会使用Pandas库来处理数据。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;数据库&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;元数据数据库：存储Superset的配置信息、仪表板定义、数据源定义等。&lt;/li&gt;
  &lt;li&gt;缓存数据库：用于缓存数据，提高查询性能。Redis和Memcached是常用的选项。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;前端&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;React &amp;amp; JavaScript：Superset的前端主要使用React框架结合JavaScript开发，用于实现用户界面的交互和动态展示。&lt;/li&gt;
  &lt;li&gt;js：图表的渲染利用了D3.js库，提供丰富的可视化选项。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;安全性&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;认证与授权：Superset提供灵活的认证选项（如LDAP、OAuth、数据库等）和基于角色的访问控制（RBAC）。&lt;/li&gt;
  &lt;li&gt;数据安全：支持数据级别的安全控制，确保用户只能访问授权的数据。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;扩展性&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;插件系统：Superset支持自定义插件，允许用户扩展新的可视化类型或其他功能。&lt;/li&gt;
  &lt;li&gt;API：提供REST API，支持与其他系统的集成。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;任务调度器&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Celery：用于执行后台任务，如异步查询和发送报告。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;Superset功能扩展&lt;/h2&gt;
 &lt;p&gt;拓展Apache Superset主要涉及添加新的可视化类型、增强现有功能、集成更多数据源等方面。&lt;/p&gt;
 &lt;p&gt;开发自定义可视化插件&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Superset支持通过插件机制添加新的图表和可视化类型。&lt;/li&gt;
  &lt;li&gt;可以使用React和JavaScript开发新的可视化组件。&lt;/li&gt;
  &lt;li&gt;开发完成后，将插件包含在Superset的配置中，使其成为可用的可视化类型。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;集成更多数据源&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Superset通过SQLAlchemy与数据源进行交互，可以添加对新数据库的支持。&lt;/li&gt;
  &lt;li&gt;通过添加相应的数据库驱动和SQLAlchemy方言，可以实现新的数据库支持。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;增强现有功能&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;对Superset的源代码进行修改，可以增强或改变现有功能。&lt;/li&gt;
  &lt;li&gt;包括改进用户界面、增加新的数据处理功能、优化性能等。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;使用API进行集成&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Superset提供了REST API，可以用来与其他系统集成。&lt;/li&gt;
  &lt;li&gt;例如，可以通过API自动化仪表板的创建、更新数据源等。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;安全性和认证的定制&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;可以定制Superset的安全性和认证机制，如集成企业的单点登录（SSO）系统。&lt;/li&gt;
  &lt;li&gt;修改认证流程以支持LDAP、OAuth等。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;使用和配置Celery任务调度器&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;使用Celery来优化和管理后台任务，如数据刷新、报告发送等。&lt;/li&gt;
  &lt;li&gt;可以定制Celery的配置以满足特定的性能和规模需求。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;参考链接：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;a href="https://superset.apache.org/"&gt;Welcome | Superset (apache.org)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://github.com/apache/superset"&gt;GitHub – apache/superset: Apache Superset is a Data Visualization and Data Exploration Platform&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://github.com/amancevice/docker-superset"&gt;GitHub – amancevice/docker-superset: Docker image for Airbnb’s Superset&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;div&gt;

  &lt;h3&gt;相关文章:&lt;/h3&gt;  &lt;ol&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/docker-jupyterhub.html" rel="bookmark" title="Docker&amp;#23433;&amp;#35013;&amp;#22810;&amp;#29992;&amp;#25143;&amp;#29256;JupyterHub"&gt;Docker安装多用户版JupyterHub&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/hive-udf.html" rel="bookmark" title="Hive UDF&amp;#30340;&amp;#24320;&amp;#21457;&amp;#31616;&amp;#20171;"&gt;Hive UDF的开发简介&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/microsoft-rest-api-guidelines.html" rel="bookmark" title="Microsoft REST API Guidelines&amp;#20013;&amp;#25991;&amp;#32763;&amp;#35793;"&gt;Microsoft REST API Guidelines中文翻译&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>器→工具 工具软件 BI</category>
      <guid isPermaLink="true">https://itindex.net/detail/62903-%E5%BC%80%E6%BA%90-%E5%8F%AF%E8%A7%86%E5%8C%96-%E5%B7%A5%E5%85%B7</guid>
      <pubDate>Thu, 04 Jan 2024 12:54:55 CST</pubDate>
    </item>
    <item>
      <title>用友“吓”跌停：华为为何做起了ERP？</title>
      <link>https://itindex.net/detail/62690-%E8%B7%8C%E5%81%9C-%E5%8D%8E%E4%B8%BA-erp</link>
      <description>&lt;img src="https://img.huxiucdn.com/article/cover/202303/20/214241863090.jpg"&gt;&lt;/img&gt;  &lt;p&gt;虎嗅注：据第一财经报道，有消息称，任正非近日在公司专家座谈会上表示，华为将在4月举办MetaERP宣誓。或受此影响，3月20日，用友网络开盘快速跌停，成交额30.35亿元。用友工作人员回应称，市场对此消息有一定过度解读。从行业角度看，ERP产品的发展成熟至少需要三到五年时间积累，就当前的竞争格局来看，华为相关产品更多是公司内部自用。用友与华为是战略级合作伙伴。&lt;/p&gt; &lt;p&gt;同日金蝶国际股价下跌18.77%。金蝶国际回应21世纪经济报道，金蝶是华为的深度战略合作伙伴，华为采用了金蝶的苍穹平台，华为的全球人力资源系统是金蝶与华为共建的。&lt;/p&gt; &lt;p&gt;本文来自微信公众号：  &lt;a href="http://mp.weixin.qq.com/s?__biz=MzI0MjU2NTA1Mg==&amp;mid=2247565968&amp;idx=2&amp;sn=3f1a79cc7148faec63f9a6f3be4ce50d&amp;chksm=e979e843de0e6155a41b54e37f384446dc41b807cf413eaa1a8508e506ddb91dbbd91b05630e#rd" rel="nofollow" target="_blank"&gt;财经十一人 （ID：caijingEleven）&lt;/a&gt;，作者：吴俊宇、谢丽容，原文标题：《除了应对美国断供，华为自研基础软件还为什么》，题图来自：视觉中国&lt;/p&gt; &lt;p&gt;自2019年起被美国政府连续多轮限制至今，华为按照“一切都需要靠自己”的新逻辑，走在既定的节奏上。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;3月19日，华为创始人任正非在华为“难题揭榜”火花奖专家座谈会上提到，华为用自己的操作系统、数据库、编译器和语言，  &lt;strong&gt;做出了自己的管理系统MetaERP软件。&lt;/strong&gt;MetaERP是华为内部业务资源管理软件，经历了华为全球各部门的应用实战、公司总账使用年度结算的考验。&lt;/p&gt; &lt;p&gt;ERP（企业资源管理）软件覆盖企业管理方方面面，包括供应链、采购、销售、订单、发货、库存、财务、客户关系、人力资源等。&lt;/p&gt; &lt;p&gt;ERP软件只是华为这三年来在基础软件领域的突破性成果之一。在基础软件开发工具方面，华为三年间完成13000+颗器件的替代开发、4000+电路板的反复换板开发。阶段性克服美国政府断供带来的生存问题。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;自研软件业务是华为2023年的重点突破方向之一。&lt;/strong&gt;《财经十一人》了解到，华为自研软件业务主要聚焦基础软件，尤其是基础软件中的平台软件。这延续了华为在根技术领域的投入。华为用自己的基础软件，做出了自己的管理系统MetaERP软件，这意味着，华为目前在基础软件四大领域（操作系统、数据库、中间件、编程工具）全部实现了自主可控。&lt;/p&gt; &lt;p&gt;MetaERP作为平台软件，竞争对手是Oracle、SAP这类高端ERP软件的市场。多位专业人士的判断是，华为自研MetaERP，目的是实现国产化突围，做大国内软件生态，而不是与合作伙伴分食应用软件市场。Oracle、SAP做大，依靠庞大的软件实施伙伴，MetaERP能走多远也将取决于这个因素。&lt;/p&gt; &lt;p&gt;对于行业来说，中国软件产业十多年来处于“大而不强”的状态，  &lt;strong&gt;现阶段需要有大公司亲自下场培育生态。&lt;/strong&gt;国内企业软件公司普遍规模有限，如金蝶、用友年营收不超过100亿元，云订阅收入大于1亿美元的软件公司不超过五家。&lt;/p&gt; &lt;p&gt;任正非说，华为现在还处于困难时期，但在前进的道路上并没有停步。2022年华为的研发经费是238亿美元，几年后随着利润增多，在前沿探索上还会继续加大投入。&lt;/p&gt; &lt;p&gt;据了解，华为打算将MetaERP和一批设计工具向外部开放使用，公开给社会应用。&lt;/p&gt; &lt;h3&gt;聚焦基础软件  &lt;br /&gt;&lt;/h3&gt; &lt;p&gt;中国软件产业长期存在  &lt;strong&gt;“重应用轻基础”&lt;/strong&gt;的问题。具体表现为，偏重应用软件（财务、审计、税务、客户管理、办公协同等）的开发，忽略基础软件（操作系统、数据库、中间件、编程工具）的研发。&lt;/p&gt; &lt;p&gt;这带来的结果是，中国软件产业收入规模位居全球第三，  &lt;strong&gt;但在基础软件领域，中国收入规模仅位居全球第六，&lt;/strong&gt;甚至低于日本、韩国、俄罗斯。&lt;/p&gt; &lt;p&gt;  &lt;img height="1243" src="https://img.huxiucdn.com/article/content/202303/20/194629583714.png" width="1000"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;中国软件行业协会在2022年11月发布的《中国软件根技术发展白皮书》显示，2020年全球软件产业业务收入约10万亿美元。规模前七的国家和地区分别是：美国27000亿美元、欧洲21000万亿美元、中国8000亿美元、日本7000亿美元、印度3500亿美元、韩国3000亿美元、俄罗斯3000亿美元。&lt;/p&gt; &lt;p&gt;但在基础软件（操作系统、数据库、中间件、编程工具）领域，美国收入规模为8100亿美元，占全球该领域业务收入60%以上。欧洲2100亿美元、日本700亿美元、韩国450亿美元、俄罗斯450亿美元，中国仅为360亿美元。&lt;/p&gt; &lt;p&gt;中国在基础软件四大方向进展不一，  &lt;strong&gt;数据库和中间件目前已经有相对成熟的国产替代产品，但操作系统和编程工具目前均高度依赖国际企业。&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;  &lt;img height="736" src="https://img.huxiucdn.com/article/content/202303/20/194630556187.png" width="952"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;操作系统市场方面，微软的Windows、苹果的MacOS两大桌面操作系统全球份额超过90%；谷歌的Android、苹果的iOS两大移动操作系统全球市场份额也超过90%。国产桌面操作系统均以开源Linux系统修改而来，国内市场份额不超过5%。&lt;/p&gt; &lt;p&gt;编程工具市场方面，微软旗下的Visual Studio、JetBrain公司旗下的IntelliJ IDEA占据集成开发环境（IDE）市场的主要份额。集成开发工具是开发软件的软件。一位软件开发技术人士对《财经十一人》表示，  &lt;strong&gt;微软在软件市场之所以强，一大原因就是，全世界的开发者都基于微软的软件工具研发软件，&lt;/strong&gt;  &lt;strong&gt;开发结束后再把代码贡献到微软收购的Github代码托管平台。&lt;/strong&gt;这意味着软件开发的工具、标准、创意都在微软生态上。&lt;/p&gt; &lt;p&gt;数据库市场方面，Oracle、微软、IBM是全球三大主导企业。IDC最新数据显示，Oracle在全球关系型数据库中份额约为42%的市场份额，微软为24%，IBM为13%。然而，数据库是目前国产基础软件领域替代最快、替代最好的领域。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;中国数据库市场相对活跃，国产替代速度还在加快。&lt;/strong&gt;目前国内云计算厂商都推出了自研数据库产品，如华为的GaussDB、阿里云PolarDB、腾讯云CynosDB。国内还有数百家基于开源数据库MySQL的国产数据库，典型企业友武汉达梦、人大金仓、南大通用、神州通用等信创四小龙。第三方市场分析机构Gartner预测，2025年中国分析型数据库市场海外厂商占比将只剩下30%，交易型数据库市场海外厂商份额也只会剩下50%。&lt;/p&gt; &lt;p&gt;中间件市场，微软、IBM、Oracle、SAP以及Salesforce均是典型企业。有软件技术人士对《财经十一人》表示，狭义的中间件指支持应用开发和集成的平台。由于企业业务和云、中台等技术结合越来越紧密，中间件角色变得愈加模糊。Oracle、SAP、Salesforce这类平台软件同时充当了企业资源管理、应用开发集成的功能。  &lt;strong&gt;华为此次推出的MetaERP也可以被视为这类平台软件。&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;华为目前在基础软件四大领域目前进展各有不同。&lt;/p&gt; &lt;p&gt;中间件、数据库是华为对外开放寻找商业化的重点领域。华为的GaussDB数据库目前在金融、政务领域已经有成熟的商业化路径。MetaERP作为平台软件，瞄准ERP软件。一种解释是，MetaERP和Oracle、SAP这类高端ERP软件的定位是一致的，目的在于满足国内大型企业内部资源管理的需求。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;ERP软件与其说是一套软件，不如说是一套软件化的管理制度。&lt;/strong&gt;它覆盖企业管理方方面面，包括供应链、采购、销售、订单、发货、库存、财务、客户关系、人力资源等。MetaERP满足的是中国企业本土化的管理诉求。Oracle、SAP做大，依靠的是庞大软件实施伙伴，MetaERP能走多远也将取决于这个因素。&lt;/p&gt; &lt;p&gt;操作系统、编程工具这两个被长期垄断的领域，华为此前给出了备胎方案。在操作系统方向，华为布局了两个产品，鸿蒙和欧拉。鸿蒙面向智能终端、物联网终端和工业终端；欧拉面向服务器、边缘计算、云以及嵌入式设备。编程工具方向，华为对外开放了华为云软件开发生产线 CodeArts。不过，  &lt;strong&gt;上述备胎方案目前都处于起步阶段，生态规模有限，仍有较长的路要走。&lt;/strong&gt;&lt;/p&gt; &lt;h3&gt;做厚软件生态&lt;/h3&gt; &lt;p&gt;从更长远的眼光来看，华为推出MetaERP的另一个目的在于，做厚平台软件，做大软件生态。补足国内软件生态中平台软件不够强壮的短板。&lt;/p&gt; &lt;p&gt;中国企业软件行业一直以来的尴尬是，中国很难产生类似Salesforce、Oracle、SAP这样的大型软件厂商。上述三家企业软件公司最近一个财年的营收分别为314亿美元、424亿美元、329亿美元。市值分别为1849亿美元、2302亿美元、1365亿美元。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;中国目前没有软件营收超过100亿元的上市公司，软件公司市值几乎都低于1000亿元。&lt;/strong&gt;一位中国云厂商高管、企业软件投资人同时对《财经十一人》表示，2020年美国市场ARR大于1亿美元的软件企业至少有140家。但国内ARR（Annual Recurring Revenue，年度经常性收入，或SaaS云上订阅收入）大于1亿美元的企业不到10家，ARR大于3亿美元的企业为零。&lt;/p&gt; &lt;p&gt;中国IT支出结构中，软件的占比也长期低于世界平均水平。研究机构Gartner 2022年数据显示，2021年全球IT支出结构是，硬件占比19%、服务占比28%、软件占比14%。当年中国IT支出结构是，硬件占31%、服务占15%、软件占4%。硬件支出远大于软件，被认为是中国企业软件市场长不大的重要因素。&lt;/p&gt; &lt;p&gt;  &lt;img height="700" src="https://img.huxiucdn.com/article/content/202303/20/194631048922.png" width="685"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;中国企业软件市场太过分散，目前以中小企业软件厂商为主。大公司长期不愿意下场，主要包含两个因素：一是国内IT支出结构，软件长期占比不足，大公司担心市场空间不足；二是云厂商下场做企业软件，容易抢走中小软件厂商的蛋糕，导致生态缺乏信任。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;过去几年，中国云厂商始终坚持“被集成”的原则。&lt;/strong&gt;云厂商和软件厂商之间界限分明，云厂商只做基础设施，软件厂商负责上层应用。其逻辑是让利合作伙伴，进而带动整个生态的飞轮效应。&lt;/p&gt; &lt;p&gt;这其实也是华为、亚马逊AWS的早期成功经验。华为企业业务早期让利集成商、渠道商、软件伙伴销售产品，成为国内最大的IT解决方案商。亚马逊AWS不触碰上层应用，而是交由SaaS企业负责，进而成为全球最大的云厂商。&lt;/p&gt; &lt;p&gt;然而在国内软件市场，这种策略目前看起来效果有限。一位头部云厂商技术人士解释，美国软件市场，云厂商、平台软件厂商、中小软件厂商这三层蛋糕行业格局很明显。亚马逊、微软、谷歌三家头部云厂商，Oracle、Salesforce、SAP、Adobe乃至IBM这些平台软件厂商，以及数百家上层应用软件，每一层的生态都很完善且力量相对均衡。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;但在中国，中小软件厂商太小，平台软件厂商太少，应用底座不够稳固。中小软件厂商带不动底层资源消耗，因此需要大公司补足平台软件这个环节。&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;有行业资深技术人士分析认为，大公司做好平台软件，需要扮演两个角色：一是帮助中小软件厂商做好开发平台、集成平台，二是为中小软件厂商带来大客户资源。在他看来，  &lt;strong&gt;云厂商迟早会进入平台软件市场。&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;有管理咨询公司数字化业务合伙人对《财经十一人》表示，中国软件市场的格局中，大公司既要做云基础设施，还要做平台软件。相比亚马逊AWS这类云厂商，行业定位会变得更厚、更重。&lt;/p&gt; &lt;h3&gt;软件开发工具自主的价值  &lt;br /&gt;&lt;/h3&gt; &lt;p&gt;近十年华为的研发费用投了大概8450亿元，有很大一部分的比例是投给软件的。MetaERP之外，  &lt;strong&gt;华为在应对软件开发工具断供的自主化方面做了部署。&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;软件的开发工具是根技术，一个软件生态必须要有生产软件的工具。即便是硬件制造，也需要软件开发工具的支撑。&lt;/p&gt; &lt;p&gt;以近年来大众所关注的芯片制造为例。光刻机用于芯片生产的光刻工艺，而光刻工艺又是芯片生产流程中最关键的一步，所以光刻机作为光刻技术的载体，是芯片制造不可或缺的关键生产工具之一。一台先进的光刻机，甚至可能影响一个国家的芯片产业发展进程。&lt;/p&gt; &lt;p&gt;软件的研发也类似于芯片制造。在软件开发过程中，同样需要许多类似光刻机的关键开发工具，它们是软件开发的前沿技术载体，是软件产品生产中不可或缺的基础。&lt;/p&gt; &lt;p&gt;如果缺少软件开发工具，整个软件产业的生存基础就会受到直接挑战。如同缺了操作系统，所有软件服务就无法运行；缺了数据库，所有应用数据就没有地方可以存放。缺了软件开发工具，所有软件应用就没办法进行开发和创新。&lt;/p&gt; &lt;p&gt;在软件开发工具方面，  &lt;strong&gt;大量中国软件企业直接购买美国商用工具，国产软件工具链大量依靠开源技术包装而成，&lt;/strong&gt;一旦受到国外制裁，开源技术平台被禁用，将会直接导致业务停摆。全球范围内软件开发工具的核心厂商主要包括Microsoft、Jetbrains、Perforce、Atlassian、Adobe等，共占有市场份额约45%，此外还有Oracle 、Synopsys和Axure Software、Sparx Systems、 Trident Inforsol 等一批主要厂商。中国仍缺少匹配的类型公司，只有有限的自主工具。&lt;/p&gt; &lt;p&gt;进一步看，  &lt;strong&gt;现代软件开发已越来越多采用云上开发模式。&lt;/strong&gt;在敏感与核心的软件中，如使用美国服务器与相关平台（Github、Gitlab）等，开发代码则需传递到美国服务器，数据生产、存储、传输、访问、使用、销毁等过程是否安全，并不可控，无法确认数据处理过程的保密性、完整性等。如发生极端情况，相关敏感数据可能被查看和利用，包括应用的关键信息，产品是否有漏洞等。&lt;/p&gt; &lt;p&gt;自2019年软件被陆续断供后，华为不再寄望于美国政府放松限制，确定了新的思路——采用自己研发加联合合作伙伴一起研发的策略，来实现自给自足，保障研发工具的连续性。范围涉及硬件（X86-&amp;gt;ARM）、操作系统（Linux/Windows-&amp;gt;欧拉）、数据库（Oracle-&amp;gt;RDS）、中间件、应用软件改造五个大类的全栈自研替换，涉及几百个组件的替换，千万行代码的测试验证。&lt;/p&gt; &lt;p&gt;2022年12月开始，华为连续发布了11款软硬件开发工具和服务，华为自身的产品线研发，已经切换到自己的工具上。构筑起了一套涵盖软件开发全流程、全环节的软件开发生产线。&lt;/p&gt; &lt;p&gt;这其中，部分软件已经通过华为云对外提供服务，华为的思路很清晰，  &lt;strong&gt;这些设计软件华为自用的同时，也开放给其他企业使用。&lt;/strong&gt;华为相关人士透露，华为近期还与伙伴发布一系列硬件开发工具软件，实现硬件工具的自给自足。&lt;/p&gt; &lt;p&gt;2022年8月13日，美国商务部发布新规，对EDA软件、超宽禁带半导体材料、压力增益燃烧（PGC）等四项技术实施新的出口管制，相关禁令生效日期为2022年8月15日。&lt;/p&gt; &lt;p&gt;作为芯片设计软件，EDA可以进行超大规模集成电路芯片的功能设计、物理设计、验证等。  &lt;strong&gt;EDA本身极其复杂，对于实现芯片自主化具有非常重大的意义。&lt;/strong&gt;实现了EDA工具自主化，就能够基本达成半导体自主化的先决条件。&lt;/p&gt; &lt;p&gt;从业务领域看，EDA是芯片核心设计软件，首当其冲在情理之中。被制裁风险较小的是信息管理类工具，如需求管理、测试管理；风险比较大的是代码仓、制品仓、检查等与出包强相关的工具。即，越是核心的工具被制裁的风险越大。&lt;/p&gt; &lt;p&gt;华为近三年来在基础软件方面的补课和追赶对中国软件产业，乃至整个数字化生态有警示意义。&lt;/p&gt; &lt;p&gt;我们需要面对的现实是，从底层芯片到操作系统、根技术、开发工具和各类应用软件服务，美国的数字化生态体系已经“枝繁叶茂”，  &lt;strong&gt;而中国的软件产业经过多年发展和追赶，已基本构建了相对完整的结构脉络，但总体能力仍十分孱弱。&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;国产芯片、国产操作系统、国产基础软件以及国产软件生态构成了中国数字化大生态的核心骨骼。每一个技术都联系紧密，环环相扣。底层是芯片、中间是操作系统、数据库、中间件等，上层是大量的应用和服务。软件自主研发，首先要适配操作系统和硬件环境。&lt;/p&gt; &lt;p&gt;这是一条极其难走又不得不走的路，基础软件只是其中的一个环节。&lt;/p&gt; &lt;p&gt;本文来自微信公众号：  &lt;a href="http://mp.weixin.qq.com/s?__biz=MzI0MjU2NTA1Mg==&amp;mid=2247565968&amp;idx=2&amp;sn=3f1a79cc7148faec63f9a6f3be4ce50d&amp;chksm=e979e843de0e6155a41b54e37f384446dc41b807cf413eaa1a8508e506ddb91dbbd91b05630e#rd" rel="nofollow" target="_blank"&gt;财经十一人 （ID：caijingEleven）&lt;/a&gt;，作者：吴俊宇、谢丽容&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>用友 华为 企业ERP 国产软件 华为应用市场</category>
      <guid isPermaLink="true">https://itindex.net/detail/62690-%E8%B7%8C%E5%81%9C-%E5%8D%8E%E4%B8%BA-erp</guid>
      <pubDate>Mon, 20 Mar 2023 23:01:00 CST</pubDate>
    </item>
    <item>
      <title>使用Excel搭建推荐系统</title>
      <link>https://itindex.net/detail/62488-excel-%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F</link>
      <description>&lt;p&gt;在上一篇  &lt;a href="https://www.biaodianfu.com/spreadsheets-and-excel.html"&gt;重新认识Excel&lt;/a&gt;的文章中，提到了Excel无所不能，然后就想到了曾经看到的这篇关于如何使用Excel搭建推荐引擎的文章。于是找了出来做了下简单的翻译（只翻译了重点部分）。&lt;/p&gt;
 &lt;p&gt;在互联网上有无限的货架空间，找到你想看的东西可能会让人筋疲力尽。幸运的是，与决策疲劳作斗争是 Netflix 的工作……而且他们很擅长。太擅长了。他们神奇地向您推荐完美的电影，这样您的眼睛就会一直盯着管子，他们会把您的拖延变成周末沙发上的狂欢。该死的，Netflix。你的秘诀是什么？你怎么这么了解我们？“魔法”非常简单，本教程使用分步电子表格揭示了其中的秘密。&lt;/p&gt;
 &lt;p&gt;尽管自Netflix Prize 竞赛以来有大量关于推荐系统的论文或视频，但大多数要么 (A) 技术太高，初学者无法使用，要么 (B) 水平太高，不实用。&lt;/p&gt;
 &lt;p&gt;在这篇文章中，我们将从头开始构建一个电影推荐系统，其中包含简单的英语解释和可以在 Excel 中遵循的分步公式。所有梯度下降推导都是手工计算的，您可以使用 Excel 下拉过滤器来微调模型的超参数并增强您的理解。&lt;/p&gt;
 &lt;h2&gt;学习内容&lt;/h2&gt;
 &lt;ul&gt;
  &lt;li&gt;构建帮助赢得 100 万美元 Netflix 奖金的算法版本 SVD++ 背后的确切步骤。&lt;/li&gt;
  &lt;li&gt;机器如何实际学习（梯度下降）。即使您从未告诉过 Netflix，也可以观看 Netflix 了解您的电影品味。&lt;/li&gt;
  &lt;li&gt;超参数调优。了解如何调整模型输入 （学习率、L2 正则化、# of epochs、权重初始化）以获得更好的预测。&lt;/li&gt;
  &lt;li&gt;模型评估和可视化。了解训练数据和测试数据之间的区别，如何防止过度拟合，并了解如何可视化模型的特征。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;在简要介绍了推荐系统之后，我将通过以下 4 个部分来构建一个模型来预测少数好莱坞明星的电影评分。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;第一部分：模型概览&lt;/li&gt;
  &lt;li&gt;第二部分：观看魔法秀（权重初始化和训练）&lt;/li&gt;
  &lt;li&gt;第三部分：魔法揭秘（梯度下降、导数）。我将逐步讲解机器学习魔法背后的数学，我将使用实数作为例子代入批量梯度下降的公式（不会使用“宏”或者Excel求解器之类的东西隐藏细节）。&lt;/li&gt;
  &lt;li&gt;第四部分：模型评估和可视化&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;推荐系统简介&lt;/h2&gt;
 &lt;p&gt;电影推荐系统可以简化为两大类：协同过滤（询问密友）和基于内容的过滤（标签匹配）&lt;/p&gt;
 &lt;h3&gt;协同过滤&lt;/h3&gt;
 &lt;p&gt;协同过滤基于类似行为进行推荐。&lt;/p&gt;
 &lt;p&gt;如果Ross和Rachel过去喜欢类似的东西，那么我们将Rachel喜欢而Ross没看过的电影向Ross推荐。你可以将他们看成是“协同”过滤网络货架上的噪音的“品味分身”。如果两个用户的评分有强相关性，那么我们就认定这两个用户“相似”。评分可以是隐式的，也可以是显式的：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;隐式（Binging）—— 整个周末，Ross和Rachel都沉溺于老剧《老友记》。尽管他们没人点赞，但我们相当确定他们喜欢《老友记》（以及他们可能有点自恋）。&lt;/li&gt;
  &lt;li&gt;显式（喜欢）—— Ross和Rachel都点了赞。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;协同过滤有两种：近邻方法和潜因子模型（矩阵分解的一种形式）。本文将聚焦一种称为  &lt;a href="https://www.biaodianfu.com/matrix-factorization.html#SVD++"&gt;SVD++&lt;/a&gt;的潜因子模型。&lt;/p&gt;
 &lt;h3&gt;基于内容的过滤&lt;/h3&gt;
 &lt;p&gt;基于你过去喜欢的内容的明确标签（类型、演员，等等），Netflix向你推荐具有类似标签的新内容。&lt;/p&gt;
 &lt;h3&gt;100 万美元的赢家&lt;/h3&gt;
 &lt;p&gt;当数据集足够大时，协同过滤（CF）是电影推荐器中的不二之选。&lt;/p&gt;
 &lt;p&gt;虽然这两个大类之间有无数的混合和变化，但出人意料的是，当CF模型足够好时，加上元数据并没有帮助。这是为什么呢？人会说谎，行动不会。让数据自己说话。人们所说的他们喜欢的东西（用户偏好、调查等）与他们的行为之间存在很大差距。最好让人们的观看行为自己说话。窍门：想要改善Netflix推荐？访问  &lt;a href="http://www.netflix.com/WiViewingActivity"&gt;/WiViewingActivity&lt;/a&gt;清理你的观看记录，移除你不喜欢的项。）&lt;/p&gt;
 &lt;p&gt;2009年，Netflix奖励了一队研究人员一百万美元，这个团队开发了一个算法，将Netflix的预测精确度提升了10%. 尽管获胜算法实际上是超过100种算法的集成，SVD++（一种协同过滤算法）是其中最关键的算法之一，贡献了大多数收益，目前仍在生产环境中使用。&lt;/p&gt;
 &lt;p&gt;我们将创建的SVD++模型（奇异值分解逼近）和Simon Funk的博客文章中提到差不多。这篇不出名的文章是2006年Simon在Netflix竞赛开始时写的，首次提出了SVD++模型。在SVD++模型成功之后，几乎所有的Netflix竞赛参加者都用它。&lt;/p&gt;
 &lt;h3&gt;SVD++ 关键思想&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;“奇异值”（电影评分）可以“分解”或由一组隐藏的潜在因素（用户偏好和电影特征）决定，这些潜在因素直观地代表了类型、演员等。&lt;/li&gt;
  &lt;li&gt;潜在因素可以使用梯度下降和已知的电影评分迭代学习。&lt;/li&gt;
  &lt;li&gt;用户/电影偏见会影响某人的评分，并且也会被学习。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;简单，但功能强大。让我们深入挖掘。&lt;/p&gt;
 &lt;h2&gt;第一部分：模型概览&lt;/h2&gt;
 &lt;h3&gt;数据&lt;/h3&gt;
 &lt;p&gt;博客文章模型使用 30 个虚构评分（5 个用户 x 6 部电影）来简化教程。要在我们进行过程中跟随并试验模型，您可以在  &lt;a href="https://drive.google.com/open?id=1y4X8H56TS6M7AXAU7yIm0EyxhqNUy1sz"&gt;此处&lt;/a&gt;下载电子表格（Excel 或 Google 表格） 。&lt;/p&gt;
 &lt;h3&gt;拆分数据——训练集和测试集&lt;/h3&gt;
 &lt;p&gt;我们将使用25项评价来训练模型，剩下5项评价测试模型的精确度。&lt;/p&gt;
 &lt;p&gt;我们的目标是创建一个在25项已知评价（训练数据）上表现良好的系统，并希望它在5项隐藏（但已知）评价（测试数据）上做出良好的预测。&lt;/p&gt;
 &lt;p&gt;如果我们有更多数据，我们本可以将数据分为3组——训练集（约70%）、验证集（约20%）、测试集（约10%）。&lt;/p&gt;
 &lt;h3&gt;评价预测公式&lt;/h3&gt;
 &lt;p&gt;评价预测是用户/电影特征的矩阵乘法（“点积”）加上用户偏置，再加上电影偏置。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="422" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel1.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;公式为：&lt;/p&gt;
 &lt;p&gt;$$\hat{r}_{i,j}=((u_1 m_1)+(u_2 m_2)+(u_3 m_3)+u_{bias}+m_{bias})$$&lt;/p&gt;
 &lt;p&gt;其中：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;$\hat{r}_{i,j}$表示用户i对电影j的预测评价&lt;/li&gt;
  &lt;li&gt;$u_1$、$u_2$、$u_3$为用户潜因子&lt;/li&gt;
  &lt;li&gt;$m_1$、$m_2$、$m_3$为电影潜因子&lt;/li&gt;
  &lt;li&gt;$u_{bias}$为用户偏置&lt;/li&gt;
  &lt;li&gt;$m_{bias}$为电影偏置&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;用户/电影特征&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;直觉上说，这些特征表示类型、演员、片长、导演、年代等因素。尽管我们并不清楚每项特征代表什么，但是当我们将其可视化后（见第四部分）我们可以凭直觉猜测它们可能代表什么。&lt;/li&gt;
  &lt;li&gt;出于简单性，我使用了3项特征，但实际的模型可能有50、100乃至更多特征。特征过多时，模型将“过拟合/记忆”你的训练数据，难以很好地推广到测试数据的预测上。&lt;/li&gt;
  &lt;li&gt;如果用户的第1项特征（让我们假定它表示“喜剧”）值较高，同时电影的“喜剧”特征的值也很高，那么电影的评价会比较高。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;用户/电影偏置&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;用户偏置取决于评价标准的宽严程度。如果Netflix上所有的平均评分是3.5，而你的所有评分的均值是4.0，那么你的偏置是0.5. 电影偏置同理。如果《泰坦尼克号》的所有用户的评分均值为4.25，那么它的偏置是0.75（= 4.25 – 3.50）。&lt;/p&gt;
 &lt;h3&gt;RMSE —— 评估预测精确度&lt;/h3&gt;
 &lt;p&gt;RMSE = Root Mean Squared Error （均方根误差）&lt;/p&gt;
 &lt;p&gt;RMSE是一个数字，尝试回答以下问题“平均而言，预测评价和实际平均差了几颗星（1-5）？”&lt;/p&gt;
 &lt;p&gt;RMSE越低，意味着预测越准……&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="532" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-2.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;观察：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;我们只在意绝对值差异。相比实际评分高估了1分的预测，和相比实际评分低估了1分的预测，误差相等，均为1。&lt;/li&gt;
  &lt;li&gt;RMSE是误差同数量级的平均，而不是误差绝对值的平均。在我们上面的例子中，误差绝对值的平均是75（1 + 1 + 0.25 = 2.25，2.25 / 3 = 0.75），但RMSE是0.8292. RMSE给较大的误差更高的权重，这很有用，因为我们更不希望有较大的误差。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;超参数调整&lt;/h3&gt;
 &lt;p&gt;通过电子表格的下拉过滤器，可以调整模型的3个超参数。你应该测试下每种超参数，看看它们对误差的影响。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;训练epoch数—— 1个epoch意味着整个训练集都过了一遍&lt;/li&gt;
  &lt;li&gt;学习率—— 控制调整权重/偏置的速度&lt;/li&gt;
  &lt;li&gt;L2（lambda）惩罚因子—— 帮助模型预防过拟合训练数据，以更好地概括未见测试数据。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" height="109" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-3.png" width="324"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;现在，让我们看一场魔法秀，看看模型是如何从随机权重开始，学习最优权重的。&lt;/p&gt;
 &lt;h2&gt;第二部分：观看魔法秀（权重初始化和训练）&lt;/h2&gt;
 &lt;p&gt;观看梯度下降的实际操作感觉就像您在观看 David Blaine 的魔术。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;他到底是怎么知道我会在52张牌中选这张的呢？&lt;/li&gt;
  &lt;li&gt;等等，他刚刚是不是浮空了？&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;最后你深感敬畏，想要知道魔术是如何变的。我会分两步演示，接着揭露魔法背后的数学。&lt;/p&gt;
 &lt;h3&gt;抽一张卡，随便抽一张（权重初始化）&lt;/h3&gt;
 &lt;p&gt;在训练开始，用户/电影特征的权重是随机分配的，接着算法在训练中学习最佳的权重。&lt;/p&gt;
 &lt;p&gt;为了揭示这看起来有多么“疯狂”，我们可以随机猜测数字，然后让计算机学习最佳数字。下面是两种权重初始化方案的比较：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;简单—— 用户特征我随机选择了1、0.2、0.3，剩下的特征都分配0.1.&lt;/li&gt;
  &lt;li&gt;Kaiming He—— 更正式、更好的初始化方法，从高斯分布（“钟形曲线”）中随机抽样作为权重，高斯分布的均值为零，标准差由特征个数决定（细节见后）。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;观赏魔术（查看训练误差）&lt;/h3&gt;
 &lt;p&gt;看看使用以上两种方案学习权重最佳值的效果，从开始（epoch 0）到结束（epoch 50），RMSE训练误差是如何变化的：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1200" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-5.gif" width="1068"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如你所见，两种权重初始化方法在训练结束时都会收敛到类似的“误差”（0.12 与 0.17），但“   &lt;a href="http://www.jefkine.com/deep/2016/08/08/initialization-of-deep-networks-case-of-rectifiers/"&gt;Kaiming He”&lt;/a&gt;方法更快地收敛到较低的误差。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;关键要点：无论我们从哪个权重开始，机器都会随着时间的推移学习到好的值！&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="365" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-6.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;注意：如果你想要试验其他初始化权重，可以在电子表格的“hyperparameters_and_initial_wts”表的G3-J7、N3-Q8单元格中输入你自己的值。权重取值范围为-1到1.&lt;/p&gt;
 &lt;p&gt;想要了解更多关于Kaiming He初始化的内容，请接着读下去；否则，可以直接跳到第3部分学习算法的数学。&lt;/p&gt;
 &lt;h3&gt;Kaiming He权重初始化&lt;/h3&gt;
 &lt;p&gt;权重 = 正态分布随机抽样，分布均值为0，标准差为 (=SquareRoot(2/# of features))&lt;/p&gt;
 &lt;p&gt;电子表格中的值由以下公式得到：=NORMINV(RAND(),0,SQRT(2/3))&lt;/p&gt;
 &lt;p&gt;$$W_l \sim \mathcal{N}(0, \sqrt{\frac{2}{n_l}}) \text{and} \mathbf{b}=0$$&lt;/p&gt;
 &lt;h2&gt;第三部分：魔法揭秘&lt;/h2&gt;
 &lt;p&gt;现在，是时候书呆一点，一步一步地了解梯度下降的数学了。如果你不是真想知道魔法是如何起效的，那么可以跳过这一部分，直接看第4部分。&lt;/p&gt;
 &lt;p&gt;梯度下降是在训练时使用的迭代算法，通过梯度下降更新电影特征、用户偏好的权重和偏置，以做出更好的预测。&lt;/p&gt;
 &lt;p&gt;梯度下降的一般周期为：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;第 1 步 – 定义成本/损失函数以最小化和初始化权重&lt;/li&gt;
  &lt;li&gt;第 2 步 — 计算预测&lt;/li&gt;
  &lt;li&gt;第 3 步 – 计算梯度（相对于每个权重的成本变化）&lt;/li&gt;
  &lt;li&gt;第 4 步——在最小化成本的方向上更新每个权重“一点点地”（学习率）&lt;/li&gt;
  &lt;li&gt;第 5 步 — 重复第 2-4 步&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;你可以访问电子表格的“training”（训练）表，其中第11-16行是更新Tina Fey的第一项用户特征的过程。&lt;/p&gt;
 &lt;p&gt;由于数据集很小，我们将使用批量梯度下降。这意味着我们在训练时将使用整个数据集（在我们的例子中，一个用户的所有电影），而不是像随机梯度下降之类的算法一样每次迭代一个样本（在我们的例子中，一个用户的一部电影），当数据集较大时，随机梯度下降更快。&lt;/p&gt;
 &lt;h3&gt;定义最小化的代价函数&lt;/h3&gt;
 &lt;p&gt;我们将使用下面的公式，我们的目标是找到合适的潜因子（矩阵U、M）的值，以最小化SSE（平方误差之和）加上一个帮助模型提升概括性的L2权重惩罚项。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="529" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-7.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;下面是Excel中的代价函数计算。计算过程忽略了1/2系数，因为它们仅用于梯度下降以简化计算。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="396" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-8.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;L2正则化和过拟合&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;我们加入了权重惩罚（L2正则化或“岭回归”）以防止潜因子值过高。这确保模型没有“过拟合”（也就是记忆）训练数据，否则模型在未见的测试电影上表现不会好。&lt;/p&gt;
 &lt;p&gt;之前，我们没有使用L2正则化惩罚（系数为0）的情况下训练模型，50个epoch后，RMSE训练误差为0.12.&lt;/p&gt;
 &lt;p&gt;但是模型在测试数据上的表现如何呢？&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="402" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-9.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如果我们将 L2 惩罚因子从 0.000 更改为 0.300，我们的模型应该可以更好地概括未见过的测试数据：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="426" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-10.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;计算预测&lt;/h3&gt;
 &lt;p&gt;我们将计算Tina的电影预测。我们将忽略《泰坦尼克号》，因为它在测试数据集中，不在训练数据集中。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="313" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-11.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;计算梯度&lt;/h3&gt;
 &lt;p&gt;目标是找到误差对应于将更新的权重的梯度（“坡度”）。&lt;/p&gt;
 &lt;p&gt;得出梯度之后，稍微将权重“移动一点点”，沿着梯度的反方向“下降”，在对每个权重进行这一操作后，下一epoch的代价应该会低一些。&lt;/p&gt;
 &lt;p&gt;“移动一点点”具体移动多少，取决于学习率。在得到梯度（3.3）之后，会用到学习率。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="238" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-12.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;梯度下降法则：将权重往梯度的反方向移动，以减少误差&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;第1步：计算Tina Fey的第一个潜因子的代价梯度（$u_1$）&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;1.1整理代价目标函数，取代价在Tina Fey的第一个潜因子（$u_1$）上的偏导数。&lt;/p&gt;
 &lt;p&gt;$$\frac{\partial J(cost)}{\partial u_1}=\frac{1}{2} \sum_{(i, j): r(i,)=1}(\hat{r}_{i, j}-r_{i, j})^2+\frac{1}{2} \lambda(\sum_i\left\|u_i\right\|^2+\sum_j\left\|m_j\right\|^2)$$&lt;/p&gt;
 &lt;p&gt;1.2整理预测评价函数，改写为用户潜因子的平方和加上电影潜因子的平方和&lt;/p&gt;
 &lt;p&gt;$$\frac{\partial J}{\partial u_1}=\frac{1}{2} \sum(((u_1 m_1)+(u_2 m_2)+(u_3 m_3)+u_{bias }+m_{bias})-r_{i, j})^2+ \frac{1}{2} \lambda \sum(u_1^2+u_2^2+u_3^2)+\frac{1}{2} \lambda \sum (m_1^2+m_2^2+m_3^2)$$&lt;/p&gt;
 &lt;p&gt;1.3将公式每部分中的$u_1$视为常数，取$u_1$在公式每部分的代价上的偏导数。&lt;/p&gt;
 &lt;p&gt;1.3.1（Part 1 of 3）应用“链式法则”以得到偏导数。链式法则意味着我们将((外层函数的导数)*内层函数)* (内部函数的导数)&lt;/p&gt;
 &lt;p&gt;外层函数的导数：&lt;/p&gt;
 &lt;p&gt;$$\begin{gathered}=\frac{1}{2} \sum(((u_1 m_1)+(u_2 m_2)+(u_3 m_3)+u_{bias}+m_{bias})-r_{i, j})^2 \leftarrow \text { power rule} \\=2 \times \frac{1}{2}(((u_1 m_1)+(u_2 m_2)+(u_3 m_3)+u_{bias}+m_{bias})-r_{i, j})^1 \\=\text { (predicted rating }-\text { actual rating }) \\=(\text { error })\end{gathered}$$&lt;/p&gt;
 &lt;p&gt;内层函数的导数：&lt;/p&gt;
 &lt;p&gt;$$\begin{gathered}=\frac{1}{2} \sum((u_1 m_1)+(u_2 m_2)+(u_3 m_3)+u_{bias}+m_{bias})-r_{i, j} \leftarrow \text {constant rule} \\ ((u_1 m_1)+(0)+(0)+0+0)-0 \\ =m_1 \\ 1.3.1=(\text{error} x m_1)\end{gathered}$$&lt;/p&gt;
 &lt;p&gt;1.3.1（Part 2 of 3）应用“幂法则”以得到偏导数。根据幂法则，指数为2，所以将指数降1，并乘上系数1/2. $u_2$和$u_3$视作常数，变为0.&lt;/p&gt;
 &lt;p&gt;$$\begin{gathered}=\frac{1}{2} \lambda \sum(u_1^2+u_2^2+u_3^2) \\=2 \times \frac{1}{2} \times \lambda(u_1^1+0+0) \\=\lambda \times u_1 \\1.3 .2= (\lambda \times u_1)\end{gathered}$$&lt;/p&gt;
 &lt;p&gt;1.3.3 (Part 3 of 3 ) 应用“常数法则”以得到偏导数。&lt;/p&gt;
 &lt;p&gt;$$\begin{gathered}=\frac{1}{2} \lambda \sum(m_1^2+m_2^2+m_3^2) \\=0\end{gathered}$$&lt;/p&gt;
 &lt;p&gt;由于$u_1$对这些项毫无影响，结果是0。&lt;/p&gt;
 &lt;p&gt;$$1.3.3 =0$$&lt;/p&gt;
 &lt;p&gt;1.4 结合1.3.1、1.3.2、1.3.3得到代价在$u_1$上的偏导数。&lt;/p&gt;
 &lt;p&gt;$$\begin{aligned} \quad \text { Part } 1+\text { Part } 2+\text { Part } 3 \\ \frac{\partial J}{\partial u_1} &amp;amp;=(\text { error } x m_1)+(\lambda \times u_1)+0 \\ &amp;amp;=(\text { error } x m_1)+(\lambda \times u_1)\end{aligned}$$&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;第2步：对训练集中Tina看过的每部电影，利用前面的公式计算梯度，接着计算Tina看过的所有电影的平均梯度。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="509" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-13.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;更新权重&lt;/h3&gt;
 &lt;p&gt;学习Tina的旧$u_1$，学习率($\alpha$)，以及上面计算的平均梯度，更新$u_1$。我们将使用的学习率为0.3。&lt;/p&gt;
 &lt;p&gt;Gradient descent formula:&lt;/p&gt;
 &lt;p&gt;$$New \ u_1= old \ u_1-\alpha (average \ gradient)$$&lt;/p&gt;
 &lt;p&gt;$$New \ u_1=(0.66)-0.3(1.92)$$&lt;/p&gt;
 &lt;p&gt;$$New \ u_1=(0.66)+0.58$$&lt;/p&gt;
 &lt;p&gt;$$New \ u_1=(0.08)$$&lt;/p&gt;
 &lt;p&gt;“training”（训练）表的X11-X16单元格对应上面的计算过程。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="251" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-14.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;你可以看到，电影特征和用户/电影偏置以类似的方式更新。&lt;/p&gt;
 &lt;p&gt;每一个训练epoch更新所有的电影/用户特征及偏置。&lt;/p&gt;
 &lt;h2&gt;第四部分：模型评估和可视化&lt;/h2&gt;
 &lt;p&gt;现在我们已经训练好了模型，让我们可视化电影的2个潜因子。&lt;/p&gt;
 &lt;p&gt;如果我们的模型更复杂，包括10、20、50+潜因子，我们可以使用一种称为“  &lt;a href="https://www.biaodianfu.com/pca.html"&gt;主成分分析（PCA）&lt;/a&gt;”的技术提取出最重要的特征，接着将其可视化。&lt;/p&gt;
 &lt;p&gt;相反，我们的模型仅仅包括3项特征，所以我们将可视化其中的2项特征，基于学习到的特征将每部电影绘制在图像上。绘制图像之后，我们可以解释每项特征“可能代表什么”。&lt;/p&gt;
 &lt;p&gt;从直觉出发，电影特征1可能解释为悲剧与喜剧，而电影特征3可能解释为男性向与女性向。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="735" src="https://www.biaodianfu.com/wp-content/uploads/2022/11/excel-15.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这不是完美的解释，但还算一种合理的解释。《勇士》（warrior）一般归为剧情片，而不是喜剧片。不过其他电影基本符合以上解释。&lt;/p&gt;
 &lt;h2&gt;总结&lt;/h2&gt;
 &lt;p&gt;电影评价由一个电影向量和一个用户向量组成。在你评价了一些电影之后（显式或隐式），推荐系统将利用群体的智慧和你的评价预测你可能喜欢的其他电影。向量（或“潜因子”）的维度取决于数据集的大小，可以通过试错法确定。&lt;/p&gt;
 &lt;p&gt;我鼓励你实际操作下电子表格，看看改变模型的超参数会带来什么改变。&lt;/p&gt;
 &lt;p&gt;参考链接：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;a href="https://towardsdatascience.com/netflix-and-chill-building-a-recommendation-system-in-excel-c69b33c914f4"&gt;Netflix and Chill: Building a Recommendation System in Excel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;div&gt;
  &lt;h3&gt;相关文章:&lt;/h3&gt;  &lt;ol&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/lda-latent-dirichlet-allocation.html" rel="bookmark" title="&amp;#20027;&amp;#39064;&amp;#27169;&amp;#22411;LDA(Latent Dirichlet Allocation)&amp;#21021;&amp;#25506;"&gt;主题模型LDA(Latent Dirichlet Allocation)初探 &lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/learning-to-ranking.html" rel="bookmark" title="&amp;#25490;&amp;#24207;&amp;#20248;&amp;#21270;&amp;#31639;&amp;#27861;Learning to Ranking"&gt;排序优化算法Learning to Ranking &lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/matrix-factorization.html" rel="bookmark" title="&amp;#25512;&amp;#33616;&amp;#31639;&amp;#27861;&amp;#20043;&amp;#30697;&amp;#38453;&amp;#20998;&amp;#35299;"&gt;推荐算法之矩阵分解 &lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>器→工具 工具软件 数据 术→技巧 机器学习</category>
      <guid isPermaLink="true">https://itindex.net/detail/62488-excel-%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F</guid>
      <pubDate>Sun, 13 Nov 2022 23:06:06 CST</pubDate>
    </item>
    <item>
      <title>Linux文件系统inode详解</title>
      <link>https://itindex.net/detail/62362-linux-%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F-inode</link>
      <description>&lt;h2&gt;文件系统&lt;/h2&gt;
 &lt;p&gt;文件系统是操作系统中负责管理持久数据的子系统，说简单点，就是负责把用户的文件存到磁盘硬件中，因为即使计算机断电了，磁盘里的数据并不会丢失，所以可以持久化的保存文件。&lt;/p&gt;
 &lt;p&gt;文件系统的基本数据单位是文件，它的目的是对磁盘上的文件进行组织管理，那组织的方式不同，就会形成不同的文件系统。&lt;/p&gt;
 &lt;p&gt;Linux 最经典的一句话是：「一切皆文件」，不仅普通的文件和目录，就连块设备、管道、socket 等，也都是统一交给文件系统管理的。&lt;/p&gt;
 &lt;p&gt;Linux 文件系统会为每个文件分配两个数据结构：索引节点（index node）和目录项（directory entry），它们主要用来记录文件的元信息和目录层次结构。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="357" src="https://www.biaodianfu.com/wp-content/uploads/2022/08/inode.png" width="480"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;索引节点，也就是inode，用来记录文件的元信息，比如 inode 编号、文件大小、访问权限、创建时间、修改时间、数据在磁盘的位置等等。索引节点是文件的唯一标识，它们之间一一对应，也同样都会被存储在硬盘中，所以索引节点同样占用磁盘空间。&lt;/li&gt;
  &lt;li&gt;目录项，也就是dentry，用来记录文件的名字、索引节点指针以及与其他目录项的层级关联关系。多个目录项关联起来，就会形成目录结构，但它与索引节点不同的是，目录项是由内核维护的一个数据结构，不存放于磁盘，而是缓存在内存。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;由于索引节点唯一标识一个文件，而目录项记录着文件的名，所以目录项和索引节点的关系是多对一，也就是说，一个文件可以有多个目录。比如，硬链接的实现就是多个目录项中的索引节点指向同一个文件。&lt;/p&gt;
 &lt;p&gt;注意，目录也是文件，也是用索引节点唯一标识，和普通文件不同的是，普通文件在磁盘里面保存的是文件数据，而目录文件在磁盘里面保存子目录或文件。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;目录项和目录是一个东西吗？&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;虽然名字很相近，但是它们不是一个东西，目录是个文件，持久化存储在磁盘，而目录项是内核一个数据结构，缓存在内存。&lt;/p&gt;
 &lt;p&gt;如果查询目录频繁从磁盘读，效率会很低，所以内核会把已经读过的目录用目录项这个数据结构缓存在内存，下次再次读到相同的目录时，只需从内存读就可以，大大提高了文件系统的效率。&lt;/p&gt;
 &lt;p&gt;注意，目录项这个数据结构不只是表示目录，也是可以表示文件的。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;文件数据是如何存储在磁盘的呢？&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;磁盘读写的最小单位是扇区，扇区的大小只有 512字节，那么如果数据大于512字节时候，磁盘需要不停地移动磁头来查找数据，我们知道一般的文件很容易超过512字节那么如果把多个扇区合并为一个块，那么磁盘就可以提高效率了。那么磁头一次读取多个扇区就为一个块“block”（Linux上称为块，Windows上称为簇）。所以，文件系统把多个扇区组成了一个逻辑块，每次读写的最小单位就是逻辑块（数据块），Linux 中的逻辑块大小为 4KB，也就是一次性读写 8 个扇区，这将大大提高了磁盘的读写的效率。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="333" src="https://www.biaodianfu.com/wp-content/uploads/2022/08/filesystem.png" width="480"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;文件系统记录的数据，除了其自身外，还有数据的权限信息，所有者等属性，这些信息都保存在inode中，那么谁来记录inode信息和文件系统本身的信息呢，比如说文件系统的格式，inode与data的数量呢？那么就有一个超级区块（supper block）来记录这些信息了。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="601" src="https://www.biaodianfu.com/wp-content/uploads/2022/08/supper-block.png" width="720"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;superblock：记录此 filesystem 的整体信息，包括inode/block的总量、使用量、剩余量， 以及文件系统的格式与相关信息等&lt;/li&gt;
  &lt;li&gt;inode：记录文件的属性信息，可以使用stat命令查看inode信息。&lt;/li&gt;
  &lt;li&gt;block：实际文件的内容，如果一个文件大于一个块时候，那么将占用多个block，但是一个块只能存放一个文件。（因为数据是由inode指向的，如果有两个文件的数据存放在同一个块中，就会乱套了）&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" height="254" src="https://www.biaodianfu.com/wp-content/uploads/2022/08/data.png" width="480"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;node用来指向数据block，那么只要找到inode，再由inode找到block编号，那么实际数据就能找出来了。&lt;/p&gt;
 &lt;p&gt;索引节点是存储在硬盘上的数据，为了加速文件的访问，通常会把索引节点加载到内存中。我们不可能把超级块和索引节点区全部加载到内存，这样内存肯定撑不住，所以只有当需要使用的时候，才将其加载进内存，它们加载进内存的时机是不同的：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;超级块：当文件系统挂载时进入内存；&lt;/li&gt;
  &lt;li&gt;索引节点区：当文件被访问时进入内存；&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;虚拟文件系统&lt;/h2&gt;
 &lt;p&gt;文件系统的种类众多，而操作系统希望对用户提供一个统一的接口，于是在用户层与文件系统层引入了中间层，这个中间层就称为虚拟文件系统（Virtual File System，VFS）。VFS 定义了一组所有文件系统都支持的数据结构和标准接口，这样程序员不需要了解  &lt;a href="https://www.biaodianfu.com/linux-windows-mac-os-file_systems.html"&gt;文件系统&lt;/a&gt;的工作原理，只需要了解 VFS 提供的统一接口即可。在 Linux 文件系统中，用户空间、系统调用、虚拟机文件系统、缓存、文件系统以及存储之间的关系如下图：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="630" src="https://www.biaodianfu.com/wp-content/uploads/2022/08/vfs.png" width="480"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Linux 支持的文件系统也不少，根据存储位置的不同，可以把文件系统分为三类：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;磁盘的文件系统，它是直接把数据存储在磁盘中，比如 Ext 2/3/4、XFS 等都是这类文件系统。&lt;/li&gt;
  &lt;li&gt;内存的文件系统，这类文件系统的数据不是存储在硬盘的，而是占用内存空间，我们经常用到的/proc 和 /sys 文件系统都属于这一类，读写这类文件，实际上是读写内核中相关的数据。&lt;/li&gt;
  &lt;li&gt;网络的文件系统，用来访问其他计算机主机数据的文件系统，比如 NFS、SMB 等等。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;文件系统首先要先挂载到某个目录才可以正常使用，比如 Linux 系统在启动时，会把文件系统挂载到根目录。&lt;/p&gt;
 &lt;p&gt;Linux 采用为分层的体系结构，将用户接口层、文件系统实现和存储设备的驱动程序分隔开，进而兼容不同的文件系统。虚拟文件系统（Virtual File System, VFS）是 Linux 内核中的软件层，它在内核中提供了一组标准的、抽象的文件操作，允许不同的文件系统实现共存，并向用户空间程序提供统一的文件系统接口。下面这张图展示了 Linux 虚拟文件系统的整体结构：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="391" src="https://www.biaodianfu.com/wp-content/uploads/2022/08/vfs-architecture.png" width="640"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;p&gt;从上图可以看出，用户空间的应用程序直接、或是通过编程语言提供的库函数间接调用内核提供的 System Call 接口（如open()、write()等）执行文件操作。System Call 接口再将应用程序的参数传递给虚拟文件系统进行处理。&lt;/p&gt;
 &lt;p&gt;每个文件系统都为 VFS 实现了一组通用接口，具体的文件系统根据自己对磁盘上数据的组织方式操作相应的数据。当应用程序操作某个文件时，VFS 会根据文件路径找到相应的挂载点，得到具体的文件系统信息，然后调用该文件系统的对应操作函数。&lt;/p&gt;
 &lt;p&gt;VFS 提供了两个针对文件系统对象的缓存 INode Cache 和 DEntry Cache，它们缓存最近使用过的文件系统对象，用来加快对 INode 和 DEntry 的访问。Linux 内核还提供了 Buffer Cache 缓冲区，用来缓存文件系统和相关块设备之间的请求，减少访问物理设备的次数，加快访问速度。Buffer Cache 以 LRU 列表的形式管理缓冲区。&lt;/p&gt;
 &lt;p&gt;VFS 的好处是实现了应用程序的文件操作与具体的文件系统的解耦，使得编程更加容易：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;应用层程序只要使用 VFS 对外提供的read()、write()等接口就可以执行文件操作，不需要关心底层文件系统的实现细节；&lt;/li&gt;
  &lt;li&gt;文件系统只需要实现 VFS 接口就可以兼容 Linux，方便移植与维护；&lt;/li&gt;
  &lt;li&gt;无需关注具体的实现细节，就实现跨文件系统的文件操作。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;了解 Linux 文件系统的整体结构后，下面主要分析 Linux VFS 的技术原理。由于文件系统与设备驱动的实现非常复杂，笔者也未接触过这方面的内容，因此文中不会涉及具体文件系统的实现。&lt;/p&gt;
 &lt;h3&gt;VFS 结构&lt;/h3&gt;
 &lt;p&gt;Linux 以一组通用对象的角度看待所有文件系统，每一级对象之间的关系如下图所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="427" src="https://www.biaodianfu.com/wp-content/uploads/2022/08/vfs-object.png" width="640"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;fd 与 file&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;每个进程都持有一个fd[]数组，数组里面存放的是指向file结构体的指针，同一进程的不同fd可以指向同一个file对象；&lt;/p&gt;
 &lt;p&gt;file是内核中的数据结构，表示一个被进程打开的文件，和进程相关联。当应用程序调用open()函数的时候，VFS 就会创建相应的file对象。它会保存打开文件的状态，例如文件权限、路径、偏移量等等。&lt;/p&gt;
 &lt;pre&gt;// https://elixir.bootlin.com/linux/v5.4.93/source/include/linux/fs.h#L936 结构体已删减
struct file {
    struct path                   f_path;
    struct inode                  *f_inode;
    const struct file_operations  *f_op;
    unsigned int                  f_flags;
    fmode_t                       f_mode;
    loff_t                        f_pos;
    struct fown_struct            f_owner;
}

// https://elixir.bootlin.com/linux/v5.4.93/source/include/linux/path.h#L8
struct path {
    struct vfsmount  *mnt;
    struct dentry    *dentry;
}
&lt;/pre&gt;
 &lt;p&gt;从上面的代码可以看出，文件的路径实际上是一个指向 DEntry 结构体的指针，VFS 通过 DEntry 索引到文件的位置。&lt;/p&gt;
 &lt;p&gt;除了文件偏移量f_pos是进程私有的数据外，其他的数据都来自于 INode 和 DEntry，和所有进程共享。不同进程的file对象可以指向同一个 DEntry 和 Inode，从而实现文件的共享。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;DEntry 与 INode&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;Linux文件系统会为每个文件都分配两个数据结构，目录项（DEntry, Directory Entry）和索引节点（INode, Index Node）。&lt;/p&gt;
 &lt;p&gt;DEntry 用来保存文件路径和 INode 之间的映射，从而支持在文件系统中移动。DEntry 由 VFS 维护，所有文件系统共享，不和具体的进程关联。dentry对象从根目录“/”开始，每个dentry对象都会持有自己的子目录和文件，这样就形成了文件树。举例来说，如果要访问”/home/beihai/a.txt”文件并对他操作，系统会解析文件路径，首先从“/”根目录的dentry对象开始访问，然后找到”home/“目录，其次是“beihai/”，最后找到“a.txt”的dentry结构体，该结构体里面d_inode字段就对应着该文件。&lt;/p&gt;
 &lt;pre&gt;// https://elixir.bootlin.com/linux/v5.4.93/source/include/linux/dcache.h#L89 结构体已删减
struct dentry {
    struct dentry *d_parent;     // 父目录
    struct qstr d_name;          // 文件名称
    struct inode *d_inode;       // 关联的 inode
    struct list_head d_child;    // 父目录中的子目录和文件
    struct list_head d_subdirs;  // 当前目录中的子目录和文件
}
&lt;/pre&gt;
 &lt;p&gt;每一个dentry对象都持有一个对应的inode对象，表示 Linux 中一个具体的目录项或文件。INode 包含管理文件系统中的对象所需的所有元数据，以及可以在该文件对象上执行的操作。&lt;/p&gt;
 &lt;pre&gt;// https://elixir.bootlin.com/linux/v5.4.93/source/include/linux/fs.h#L628 结构体已删减
struct inode {
    umode_t                 i_mode;          // 文件权限及类型
    kuid_t                  i_uid;           // user id
    kgid_t                  i_gid;           // group id

    const struct inode_operations    *i_op;  // inode 操作函数，如 create，mkdir，lookup，rename 等
    struct super_block      *i_sb;           // 所属的 SuperBlock

    loff_t                  i_size;          // 文件大小
    struct timespec         i_atime;         // 文件最后访问时间
    struct timespec         i_mtime;         // 文件最后修改时间
    struct timespec         i_ctime;         // 文件元数据最后修改时间（包括文件名称）
    const struct file_operations    *i_fop;  // 文件操作函数，open、write 等
    void                    *i_private;      // 文件系统的私有数据
}
&lt;/pre&gt;
 &lt;p&gt;虚拟文件系统维护了一个 DEntry Cache 缓存，用来保存最近使用的 DEntry，加速查询操作。当调用open()函数打开一个文件时，内核会第一时间根据文件路径到 DEntry Cache 里面寻找相应的 DEntry，找到了就直接构造一个file对象并返回。如果该文件不在缓存中，那么 VFS 会根据找到的最近目录一级一级地向下加载，直到找到相应的文件。期间 VFS 会缓存所有被加载生成的dentry。&lt;/p&gt;
 &lt;p&gt;INode 存储的数据存放在磁盘上，由具体的文件系统进行组织，当需要访问一个 INode 时，会由文件系统从磁盘上加载相应的数据并构造 INode。一个 INode 可能被多个 DEntry 所关联，即相当于为某一文件创建了多个文件路径（通常是为文件建立硬链接）。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;SuperBlock&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;SuperBlock 表示特定加载的文件系统，用于描述和维护文件系统的状态，由 VFS 定义，但里面的数据根据具体的文件系统填充。每个 SuperBlock 代表了一个具体的磁盘分区，里面包含了当前磁盘分区的信息，如文件系统类型、剩余空间等。SuperBlock 的一个重要成员是链表s_list，包含所有修改过的 INode，使用该链表很容易区分出来哪个文件被修改过，并配合内核线程将数据写回磁盘。SuperBlock 的另一个重要成员是s_op，定义了针对其 INode 的所有操作方法，例如标记、释放索引节点等一系列操作。&lt;/p&gt;
 &lt;pre&gt;// https://elixir.bootlin.com/linux/v5.4.93/source/include/linux/fs.h#L1425 结构体已删减
struct super_block {
    struct list_head    s_list;               // 指向链表的指针
    dev_t               s_dev;                // 设备标识符
    unsigned long       s_blocksize;          // 以字节为单位的块大小
    loff_t              s_maxbytes;           // 文件大小上限
    struct file_system_type    *s_type;       // 文件系统类型
    const struct super_operations    *s_op;   // SuperBlock 操作函数，write_inode、put_inode 等
    const struct dquot_operations    *dq_op;  // 磁盘限额函数
    struct dentry        *s_root;             // 根目录
}
&lt;/pre&gt;
 &lt;p&gt;SuperBlock 是一个非常复杂的结构，通过 SuperBlock 我们可以将一个实体文件系统挂载到 Linux 上，或者对 INode 进行增删改查操作。所以一般文件系统都会在磁盘上存储多份 SuperBlock，防止数据意外损坏导致整个分区无法读取。&lt;/p&gt;
 &lt;h3&gt;inode 内容&lt;/h3&gt;
 &lt;p&gt;inode包含很多的文件元信息，但不包含文件名，例如：字节数、属主UserID、属组GroupID、读写执行权限、时间戳等。而文件名存放在目录当中，但Linux系统内部不使用文件名，而是使用inode号码识别文件。对于系统来说文件名只是inode号码便于识别的别称。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;stat&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;查看inode信息&lt;/p&gt;
 &lt;pre&gt;[root@localhost ~]# mkdir test
[root@localhost ~]# echo &amp;quot;this is test file&amp;quot; &amp;gt; test.txt
[root@localhost ~]# stat test.txt
  File: ‘test.txt’
  Size: 18              Blocks: 8          IO Block: 4096   regular file
Device: fd00h/64768d    Inode: 33574994    Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2019-08-28 19:55:05.920240744 +0800
Modify: 2019-08-28 19:55:05.920240744 +0800
Change: 2019-08-28 19:55:05.920240744 +0800
 Birth: -
&lt;/pre&gt;
 &lt;p&gt;三个主要的时间属性：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;ctime：change time是最后一次改变文件或目录（属性）的时间，例如执行chmod，chown等命令。&lt;/li&gt;
  &lt;li&gt;atime：access time是最后一次访问文件或目录的时间。&lt;/li&gt;
  &lt;li&gt;mtime：modify time是最后一次修改文件或目录（内容）的时间。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;file&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;查看文件类型&lt;/p&gt;
 &lt;pre&gt;[root@localhost ~]# file test
test: directory
[root@localhost ~]# file test.txt
test.txt: ASCII text
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;inode 号码&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;表面上，用户通过文件名打开文件，实际上，系统内部将这个过程分为三步：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;系统找到这个文件名对应的inode号码；&lt;/li&gt;
  &lt;li&gt;通过inode号码，获取inode信息；&lt;/li&gt;
  &lt;li&gt;根据inode信息，找到文件数据所在的block，并读出数据。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;其实系统还要根据inode信息，看用户是否具有访问的权限，有就指向对应的数据block，没有就返回权限拒绝。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;ls -i&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;直接查看文件i节点号，也可以通过stat查看文件inode信息查看i节点号。&lt;/p&gt;
 &lt;pre&gt;[root@localhost ~]# ls -i
33574991 anaconda-ks.cfg      2086 test  33574994 test.txt
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;inode 大小&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;inode也会消耗硬盘空间，所以格式化的时候，操作系统自动将硬盘分成两个区域。一个是数据区，存放文件数据；另一个是inode区，存放inode所包含的信息。每个inode的大小，一般是128字节或256字节。通常情况下不需要关注单个inode的大小，而是需要重点关注inode总数。inode总数在格式化的时候就确定了。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;df -i&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;查看硬盘分区的inode总数和已使用情况&lt;/p&gt;
 &lt;pre&gt;[root@localhost ~]# df -i
Filesystem               Inodes IUsed   IFree IUse% Mounted on
/dev/mapper/centos-root 8910848 26029 8884819    1% /
devtmpfs                 230602   384  230218    1% /dev
tmpfs                    233378     1  233377    1% /dev/shm
tmpfs                    233378   487  232891    1% /run
tmpfs                    233378    16  233362    1% /sys/fs/cgroup
/dev/sda1                524288   328  523960    1% /boot
tmpfs                    233378     1  233377    1% /run/user/0
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;文件的读写&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;文件系统在打开一个文件时，要做的有：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;系统找到这个文件名对应的inode：在目录表中查找该文件名对应的项，由此得到该文件相对应的 inode 号&lt;/li&gt;
  &lt;li&gt;通过inode号，获取到磁盘中的inode信息，其中最重要的内容是磁盘地址表&lt;/li&gt;
  &lt;li&gt;通过inode信息中的磁盘地址表，文件系统把分散存放的文件物理块连接成文件的逻辑结构。在磁盘地址表中有 13 个块号，文件将以块号在磁盘地址表中出现的顺序依次读取相应的块。找到文件数据所在的block，读出数据。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;根据以上流程，我们可以发现，inode应该是有一个专门的存储区域的，以方便系统快速查找。事实上，一块磁盘创建的时候，操作系统自动将硬盘分成两个区域：存放文件数据的数据区，与存放inode信息的inode区（inode table）。&lt;/p&gt;
 &lt;p&gt;每个inode的大小一般是128B或者256B。inode节点的总数，在格式化时就给定，一般是每1KB或每2KB就设置一个inode。假定在一块1GB的硬盘中，每个inode节点的大小为128字节，每1KB就设置一个inode，那么inode table的大小就会达到128MB，占整块硬盘的12.8%。&lt;/p&gt;
 &lt;p&gt;也就是说，每个分区的inode总数从格式化之后就固定了，因此有可能会出现存储空间没有占满，但因为小文件太多而耗尽了inode的情况。这个时候就只能清除inode占用高的文件或者目录或修改inode数量了，当然，inode的调整需要重新格式化磁盘，需要确保数据已经得到有效备份后，再进行此操作。&lt;/p&gt;
 &lt;p&gt;这时候又产生了新的问题：文件创建时要为文件分配哪一个inode号呢？即如何保证分配的inode号没有被占用？  &lt;br /&gt;
既然是”是否被占用”的问题，使用位图是最佳方案，像bmap记录block的占用情况一样。标识inode号是否被分配的位图称为inodemap简称为imap。这时要为一个文件分配inode号只需扫描imap即可知道哪一个inode号是空闲的。&lt;/p&gt;
 &lt;p&gt;(位图法就是bitmap的缩写。所谓bitmap，就是用每一位来存放某种状态，适用于大规模数据，但数据状态又不是很多的情况。)  &lt;br /&gt;
类似bmap块位图一样，inode号是预先规划好的。inode号分配后，文件删除也会释放inode号。分配和释放的inode号，像是在一个地图上挖掉一块，用完再补回来一样。  &lt;br /&gt;
imap存在着和bmap和inode table一样需要解决的问题：如果文件系统比较大，imap本身就会很大，每次存储文件都要进行扫描，会导致效率不够高。同样，优化的方式是将文件系统占用的block划分成块组，每个块组有自己的imap范围，以减少检索时间。&lt;/p&gt;
 &lt;p&gt;利用df -i命令可以查看inode数量方面的信息&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;文件的操作&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;系统对文件的操作会可能影响inode：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;复制：创建一个包含全部数据与新inode号的新文件&lt;/li&gt;
  &lt;li&gt;移动：在同一磁盘下移动时，所在目录改变，node号与实际数据存储的块的位置都不会变化。跨磁盘移动当然会删除本磁盘的数据并创建一条新的数据在另一块磁盘中。&lt;/li&gt;
  &lt;li&gt;硬链接： 同一个inode号代表的文件有多个文件名，即可以用不同的文件名访问同一份数据，但是它们指向的inode编号是相同的，并且文件元数据中链接数会增加。不可以对目录创建硬链接。&lt;/li&gt;
  &lt;li&gt;软链接： 软链接的本质是一个链接文件，其中存储的了对另一个文件的指针。所以对一个文件创建软链接，inode号不相同，创建软链接文件的链接数不会增加。可以对目录创建软链接。&lt;/li&gt;
  &lt;li&gt;删除：当删除文件时，会先检查inode中的链接数。如果链接数大于1，就只会删掉一个硬链接，不影响数据。如果链接数等于1，那么这个inode就会被释放掉，对应的inode指向的块也会被标记为空闲的（数据不会被置零，所以硬盘数据被误删除后，若没有新数据写入可恢复）。如果是软链接，原文件被删除后链接文件就变成了悬挂链接（dangling link），无法正常访问了。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;利用inode还可以删除一些文件名中有转义字符或控制字符的文件，最典型的就是开头为减号-的文件。这种无法直接用rm命令来搞，就可以先查出它们的inode编号再删除：   &lt;code&gt;find ./ -inum 10086 -exec rm {} \&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;特有现象&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;由于inode号码与文件名分离，导致一些Unix/Linux系统具备以下几种特有的现象。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;文件名包含特殊字符，可能无法正常删除。这时直接删除inode，能够起到删除文件的作用；   &lt;code&gt;find ./* -inum 节点号 -delete&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;移动文件或重命名文件，只是改变文件名，不影响inode号码；&lt;/li&gt;
  &lt;li&gt;打开一个文件以后，系统就以inode号码来识别这个文件，不再考虑文件名。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;这种情况使得软件更新变得简单，可以在不关闭软件的情况下进行更新，不需要重启。因为系统通过inode号码，识别运行中的文件，不通过文件名。更新的时候，新版文件以同样的文件名，生成一个新的inode，不会影响到运行中的文件。等到下一次运行这个软件的时候，文件名就自动指向新版文件，旧版文件的inode则被回收。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;inode 耗尽故障&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;由于硬盘分区的inode总数在格式化后就已经固定，而每个文件必须有一个inode，因此就有可能发生inode节点用光，但硬盘空间还剩不少，却无法创建新文件。同时这也是一种攻击的方式，所以一些公用的文件系统就要做磁盘限额，以防止影响到系统的正常运行。至于修复，很简单，只要找出哪些大量占用i节点的文件删除就可以了。&lt;/p&gt;
 &lt;h2&gt;硬链接与软连接&lt;/h2&gt;
 &lt;p&gt;Linux系统中有一种比较特殊的文件称之为链接（link）。通俗地说，链接就是从一个文件指向另外一个文件的路径。linux中链接分为俩种，硬链接和软链接。简单来说，硬链接相当于源文件和链接文件在磁盘和内存中共享一个inode，因此，链接文件和源文件有不同的dentry，因此，这个特性决定了硬链接无法跨越文件系统，而且我们无法为目录创建硬链接。软链接和硬链接不同，首先软链接可以跨越文件系统，其次，链接文件和源文件有着不同的inode和dentry，因此，两个文件的属性和内容也截然不同，软链接文件的文件内容是源文件的文件名。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="442" src="https://www.biaodianfu.com/wp-content/uploads/2022/08/hardlink.png" width="640"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;硬链接是多个目录项中的「索引节点」指向一个文件，也就是指向同一个 inode，但是 inode 是不可能跨越文件系统的，每个文件系统都有各自的 inode 数据结构和列表，所以硬链接是不可用于跨文件系统的。由于多个目录项都是指向一个 inode，那么只有删除文件的所有硬链接以及源文件时，系统才会彻底删除该文件。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="389" src="https://www.biaodianfu.com/wp-content/uploads/2022/08/hard-link.png" width="720"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;软链接相当于重新创建一个文件，这个文件有独立的 inode，但是这个文件的内容是另外一个文件的路径，所以访问软链接的时候，实际上相当于访问到了另外一个文件，所以软链接是可以跨文件系统的，甚至目标文件被删除了，链接文件还是在的，只不过指向的文件找不到了而已。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="375" src="https://www.biaodianfu.com/wp-content/uploads/2022/08/soft-link.png" width="720"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;软硬链接实现的原理不同
   &lt;ul&gt;
    &lt;li&gt;硬链接是建立一个目录项，包含文件名和文件的inode，但inode是原来文件的inode号，并不建立其所对应得数据。所以硬链接并不占用inode。&lt;/li&gt;
    &lt;li&gt;软连接也创建一个目录项，也包含文件名和文件的inode，但它的inode指向的并不是原来文件名所指向的数据的inode，而是新建一个inode，并建立数据，数据指向的是原来文件名，所以原来文件名的字符数，即为软连接所占字节数&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;软硬链接所能创建的目标有区别
   &lt;ul&gt;
    &lt;li&gt;因为每个分区各有一套不同的inode表，所以硬链接不能跨分区创建而软连接可以,因为软连接指向的书文件名。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;硬链接不能指向目录
   &lt;ul&gt;
    &lt;li&gt;如果说目录有硬链接那么可能引入死循环，但是你可能会疑问软连接也会陷入循环啊，答案当然不是，因为软连接是存在自己的数据的，可以查看自己的文件属性，既然可以判断出来软连接，那么自然不会陷入循环，并且系统在连续遇到8个符号连接后就停止遍历。但是硬链接可就不行了，因为他的inode号一致，所以就判断不出是硬链接，所以就会陷入死循环了。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;参考链接：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;a href="https://wingsxdu.com/posts/linux/vfs/"&gt;Linux 虚拟文件系统&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://devconnected.com/understanding-hard-and-soft-links-on-linux/"&gt;Understanding Hard and Soft Links on Linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;div&gt;
  &lt;h3&gt;相关文章:&lt;/h3&gt;  &lt;ol&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/hello-world.html" rel="bookmark" title="C&amp;#35821;&amp;#35328;&amp;#20043;Hello World&amp;#31243;&amp;#24207;&amp;#32534;&amp;#35793;"&gt;C语言之Hello World程序编译 &lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/fastfm.html" rel="bookmark" title="Python&amp;#22240;&amp;#23376;&amp;#20998;&amp;#35299;&amp;#24211;&amp;#65306;fastFM"&gt;Python因子分解库：fastFM &lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/linux-windows-mac-os-file_systems.html" rel="bookmark" title="Linux/Windows/Mac OS&amp;#25991;&amp;#20214;&amp;#31995;&amp;#32479;"&gt;Linux/Windows/Mac OS文件系统 &lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>器→工具 工具软件 Linux</category>
      <guid isPermaLink="true">https://itindex.net/detail/62362-linux-%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F-inode</guid>
      <pubDate>Sat, 13 Aug 2022 09:50:00 CST</pubDate>
    </item>
    <item>
      <title>线程池如何观测？这个方案让你对线程池的运行情况了如指掌！</title>
      <link>https://itindex.net/detail/62041-%E7%BA%BF%E7%A8%8B%E6%B1%A0-%E4%BD%95%E8%A7%82-%E7%BA%BF%E7%A8%8B%E6%B1%A0</link>
      <description>&lt;p&gt;今天我们来聊一个比较实用的话题，动态可监控可观测的线程池实践。&lt;/p&gt; &lt;p&gt;这是个全新的开源项目，作者提供了一种非常好的思路解决了线程池的可观测问题。&lt;/p&gt; &lt;p&gt;这个开源项目叫：  &lt;strong&gt;DynamicTp&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;地址在文章末尾。&lt;/p&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;写在前面&lt;/h3&gt; &lt;p&gt;稍微有些Java编程经验的小伙伴都知道，Java的精髓在juc包，这是大名鼎鼎的Doug Lea老爷子的杰作，评价一个程序员Java水平怎么样，一定程度上看他对juc包下的一些技术掌握的怎么样，这也是面试中的基本上必问的一些技术点之一。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;juc包主要包括：&lt;/strong&gt;&lt;/p&gt; &lt;blockquote&gt;  &lt;p&gt;1.原子类（AtomicXXX）&lt;/p&gt;  &lt;p&gt;2.锁类（XXXLock）&lt;/p&gt;  &lt;p&gt;3.线程同步类（AQS、CountDownLatch、CyclicBarrier、Semaphore、Exchanger）&lt;/p&gt;  &lt;p&gt;4.任务执行器类（Executor体系类，包括今天的主角ThreadPoolExecutor）&lt;/p&gt;  &lt;p&gt;5.并发集合类（ConcurrentXXX、CopyOnWriteXXX）相关集合类&lt;/p&gt;  &lt;p&gt;6.阻塞队列类（BlockingQueue继承体系类）&lt;/p&gt;  &lt;p&gt;7.Future相关类&lt;/p&gt;  &lt;p&gt;8.其他一些辅助工具类&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;多线程编程场景下，这些类都是必备技能，会这些可以帮助我们写出高质量、高性能、少bug的代码，同时这些也是Java中比较难啃的一些技术，需要持之以恒，学以致用，在使用中感受他们带来的奥妙。&lt;/p&gt; &lt;p&gt;上边简单罗列了下juc包下功能分类，这篇文章我们主要来介绍动态可监控线程池的，所以具体内容也就不展开讲了，以后有时间单独来聊吧。看这篇文章前，希望读者最好有一定的线程池ThreadPoolExecutor使用经验，不然看起来会有点懵。&lt;/p&gt; &lt;p&gt;如果你对ThreadPoolExecutor不是很熟悉，推荐阅读下面两篇文章&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;javadoop：&lt;/strong&gt;   &lt;a href="https://www.javadoop.com/post/java-thread-pool" rel="nofollow noreferrer" title="https://www.javadoop.com/post/java-thread-pool"&gt;https://www.javadoop.com/post/java-thread-pool&lt;/a&gt;&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;美团技术博客：&lt;/strong&gt;   &lt;a href="https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html" rel="nofollow noreferrer" title="https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html"&gt;https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html&lt;/a&gt;&lt;/p&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;背景&lt;/h3&gt; &lt;p&gt;  &lt;strong&gt;使用ThreadPoolExecutor过程中你是否有以下痛点呢？&lt;/strong&gt;&lt;/p&gt; &lt;blockquote&gt;  &lt;p&gt;1.代码中创建了一个ThreadPoolExecutor，但是不知道那几个核心参数设置多少比较合适&lt;/p&gt;  &lt;p&gt;2.凭经验设置参数值，上线后发现需要调整，改代码重启服务，非常麻烦&lt;/p&gt;  &lt;p&gt;3.线程池相对开发人员来说是个黑盒，运行情况不能感知到，直到出现问题&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;如果你有以上痛点，这篇文章要介绍的动态可监控线程池（DynamicTp）或许能帮助到你。&lt;/p&gt; &lt;p&gt;如果看过ThreadPoolExecutor的源码，大概可以知道其实它有提供一些set方法，可以在运行时动态去修改相应的值，这些方法有：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;public void setCorePoolSize(int corePoolSize);
public void setMaximumPoolSize(int maximumPoolSize);
public void setKeepAliveTime(long time, TimeUnit unit);
public void setThreadFactory(ThreadFactory threadFactory);
public void setRejectedExecutionHandler(RejectedExecutionHandler handler);&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;现在大多数的互联网项目其实都会微服务化部署，有一套自己的服务治理体系，微服务组件中的分布式配置中心扮演的就是动态修改配置，实时生效的角色。那么我们是否可以结合配置中心来做运行时线程池参数的动态调整呢？答案是肯定的，而且配置中心相对都是高可用的，使用它也不用过于担心配置推送出现问题这类事儿，而且也能减少研发动态线程池组件的难度和工作量。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;综上，我们总结出以下的背景&lt;/strong&gt;&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;广泛性：在Java开发中，想要提高系统性能，线程池已经是一个90%以上的人都会选择使用的基础工具&lt;/li&gt;  &lt;li&gt;不确定性：项目中可能会创建很多线程池，既有IO密集型的，也有CPU密集型的，但线程池的参数并不好确定；需要有套机制在运行过程中动态去调整参数&lt;/li&gt;  &lt;li&gt;无感知性，线程池运行过程中的各项指标一般感知不到；需要有套监控报警机制在事前、事中就能让开发人员感知到线程池的运行状况，及时处理&lt;/li&gt;  &lt;li&gt;高可用性，配置变更需要及时推送到客户端；需要有高可用的配置管理推送服务，配置中心是现在大多数互联网系统都会使用的组件，与之结合可以大幅度减少开发量及接入难度&lt;/li&gt;&lt;/ul&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;简介&lt;/h3&gt; &lt;p&gt;我们基于配置中心对线程池ThreadPoolExecutor做一些扩展，实现对运行中线程池参数的动态修改，实时生效；以及实时监控线程池的运行状态，触发设置的报警策略时报警，报警信息会推送办公平台（钉钉、企微等）。报警维度包括（队列容量、线程池活性、拒绝触发等）；同时也会定时采集线程池指标数据供监控平台可视化使用。使我们能时刻感知到线程池的负载，根据情况及时调整，避免出现问题影响线上业务。&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;    |  __ \                            (_) |__   __|
    | |  | |_   _ _ __   __ _ _ __ ___  _  ___| |_ __  
    | |  | | | | | &amp;apos;_ \ / _` | &amp;apos;_ ` _ | |/ __| | &amp;apos;_ \ 
    | |__| | |_| | | | | (_| | | | | | | | (__| | |_) |
    |_____/ __, |_| |_|__,_|_| |_| |_|_|___|_| .__/ 
             __/ |                              | |    
            |___/                               |_|    
     :: Dynamic Thread Pool :: &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;  &lt;strong&gt;特性&lt;/strong&gt;&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;参考美团线程池实践 ，对线程池参数动态化管理，增加监控、报警功能&lt;/li&gt;  &lt;li&gt;基于Spring框架，现只支持SpringBoot项目使用，轻量级，引入starter即可食用&lt;/li&gt;  &lt;li&gt;基于配置中心实现线程池参数动态调整，实时生效；集成主流配置中心，默认支持Nacos、Apollo，同时也提供SPI接口可自定义扩展实现&lt;/li&gt;  &lt;li&gt;内置通知报警功能，提供多种报警维度（配置变更通知、活性报警、容量阈值报警、拒绝策略触发报警），默认支持企业微信、钉钉报警，同时提供SPI接口可自定义扩展实现&lt;/li&gt;  &lt;li&gt;内置线程池指标采集功能，支持通过MicroMeter、JsonLog日志输出、Endpoint三种方式，可通过SPI接口自定义扩展实现&lt;/li&gt;&lt;/ul&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;架构设计&lt;/h3&gt; &lt;p&gt;  &lt;strong&gt;主要分四大模块&lt;/strong&gt;&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;p&gt;配置变更监听模块：&lt;/p&gt;   &lt;p&gt;1.监听特定配置中心的指定配置文件（默认实现Nacos、Apollo）,可通过内部提供的SPI接口扩展其他实现&lt;/p&gt;   &lt;p&gt;2.解析配置文件内容，内置实现yml、properties配置文件的解析，可通过内部提供的SPI接口扩展其他实现&lt;/p&gt;   &lt;p&gt;3.通知线程池管理模块实现刷新&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;线程池管理模块：&lt;/p&gt;   &lt;p&gt;1.服务启动时从配置中心拉取配置信息，生成线程池实例注册到内部线程池注册中心中&lt;/p&gt;   &lt;p&gt;2.监听模块监听到配置变更时，将变更信息传递给管理模块，实现线程池参数的刷新&lt;/p&gt;   &lt;p&gt;3.代码中通过getExecutor()方法根据线程池名称来获取线程池对象实例&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;监控模块：&lt;/p&gt;   &lt;p&gt;实现监控指标采集以及输出，默认提供以下三种方式，也可通过内部提供的SPI接口扩展其他实现&lt;/p&gt;   &lt;p&gt;1.默认实现Json log输出到磁盘&lt;/p&gt;   &lt;p&gt;2.MicroMeter采集，引入MicroMeter相关依赖&lt;/p&gt;   &lt;p&gt;3.暴雷Endpoint端点，可通过http方式访问&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;通知告警模块：&lt;/p&gt;   &lt;p&gt;对接办公平台，实现通告告警功能，默认实现钉钉、企微，可通过内部提供的SPI接口扩展其他实现，通知告警类型如下&lt;/p&gt;   &lt;p&gt;1.线程池参数变更通知&lt;/p&gt;   &lt;p&gt;2.阻塞队列容量达到设置阈值告警&lt;/p&gt;   &lt;p&gt;3.线程池活性达到设置阈值告警&lt;/p&gt;   &lt;p&gt;4.触发拒绝策略告警&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000041296799" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;使用&lt;/h3&gt; &lt;ul&gt;  &lt;li&gt;   &lt;p&gt;maven依赖&lt;/p&gt;   &lt;pre&gt;    &lt;code&gt;&amp;lt;dependency&amp;gt;
     &amp;lt;groupId&amp;gt;io.github.lyh200&amp;lt;/groupId&amp;gt;
     &amp;lt;artifactId&amp;gt;dynamic-tp-spring-cloud-starter&amp;lt;/artifactId&amp;gt;
     &amp;lt;version&amp;gt;1.0.2-RELEASE&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;线程池配置&lt;/p&gt;   &lt;pre&gt;    &lt;code&gt;spring:
  dynamic:
    tp:
      enabled: true
      enabledBanner: true        # 是否开启banner打印，默认true
      enabledCollect: false      # 是否开启监控指标采集，默认false
      collectorType: logging     # 监控数据采集器类型（JsonLog | MicroMeter），默认logging
      logPath: /home/logs        # 监控日志数据路径，默认${user.home}/logs
      monitorInterval: 5         # 监控时间间隔（报警判断、指标采集），默认5s
      nacos:                     # nacos配置，不配置有默认值（规则name-dev.yml这样）
        dataId: dynamic-tp-demo-dev.yml
        group: DEFAULT_GROUP
      apollo:                    # apollo配置，不配置默认拿apollo配置第一个namespace
        namespace: dynamic-tp-demo-dev.yml
      configType: yml            # 配置文件类型
      platforms:                 # 通知报警平台配置
        - platform: wechat
          urlKey: 3a7500-1287-4bd-a798-c5c3d8b69c  # 替换
          receivers: test1,test2                   # 接受人企微名称
        - platform: ding
          urlKey: f80dad441fcd655438f4a08dcd6a     # 替换
          secret: SECb5441fa6f375d5b9d21           # 替换，非sign模式可以没有此值
          receivers: 15810119805                   # 钉钉账号手机号          
      executors:                                   # 动态线程池配置
        - threadPoolName: dynamic-tp-test-1
          corePoolSize: 6
          maximumPoolSize: 8
          queueCapacity: 200
          queueType: VariableLinkedBlockingQueue   # 任务队列，查看源码QueueTypeEnum枚举类
          rejectedHandlerType: CallerRunsPolicy    # 拒绝策略，查看RejectedTypeEnum枚举类
          keepAliveTime: 50
          allowCoreThreadTimeOut: false
          threadNamePrefix: test           # 线程名前缀
          notifyItems:                     # 报警项，不配置自动会配置（变更通知、容量报警、活性报警、拒绝报警）
            - type: capacity               # 报警项类型，查看源码 NotifyTypeEnum枚举类
              enabled: true
              threshold: 80                # 报警阈值
              platforms: [ding,wechat]     # 可选配置，不配置默认拿上层platforms配置的所以平台
              interval: 120                # 报警间隔（单位：s）
            - type: change
              enabled: true
            - type: liveness
              enabled: true
              threshold: 80
            - type: reject
              enabled: true
              threshold: 1&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;代码方式生成，服务启动会自动注册&lt;/p&gt;   &lt;pre&gt;    &lt;code&gt;@Configuration
public class DtpConfig {

   @Bean
   public DtpExecutor demo1Executor() {
       return DtpCreator.createDynamicFast(&amp;quot;demo1-executor&amp;quot;);
  }

   @Bean
   public ThreadPoolExecutor demo2Executor() {
       return ThreadPoolBuilder.newBuilder()
              .threadPoolName(&amp;quot;demo2-executor&amp;quot;)
              .corePoolSize(8)
              .maximumPoolSize(16)
              .keepAliveTime(50)
              .allowCoreThreadTimeOut(true)
              .workQueue(QueueTypeEnum.SYNCHRONOUS_QUEUE.getName(), null, false)
              .rejectedExecutionHandler(RejectedTypeEnum.CALLER_RUNS_POLICY.getName())
              .buildDynamic();
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;代码调用，根据线程池名称获取&lt;/p&gt;   &lt;pre&gt;    &lt;code&gt;public static void main(String[] args) {
       DtpExecutor dtpExecutor = DtpRegistry.getExecutor(&amp;quot;dynamic-tp-test-1&amp;quot;);
       dtpExecutor.execute(() -&amp;gt; System.out.println(&amp;quot;test&amp;quot;));
}&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;注意事项&lt;/h3&gt; &lt;ol&gt;  &lt;li&gt;配置文件配置的参数会覆盖通过代码生成方式配置的参数&lt;/li&gt;  &lt;li&gt;阻塞队列只有VariableLinkedBlockingQueue类型可以修改capacity，该类型功能和LinkedBlockingQueue相似，只是capacity不是final类型，可以修改，   &lt;br /&gt;VariableLinkedBlockingQueue参考RabbitMq的实现&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;启动看到如下日志输出证明接入成功&lt;/p&gt;   &lt;pre&gt;    &lt;code&gt;
|  __ \                            (_) |__   __|   
| |  | |_   _ _ __   __ _ _ __ ___  _  ___| |_ __  
| |  | | | | | &amp;apos;_ \ / _` | &amp;apos;_ ` _ | |/ __| | &amp;apos;_ \ 
| |__| | |_| | | | | (_| | | | | | | | (__| | |_) |
|_____/ __, |_| |_|__,_|_| |_| |_|_|___|_| .__/ 
         __/ |                              | |    
        |___/                               |_|    
 :: Dynamic Thread Pool :: 

DynamicTp register, executor: DtpMainPropWrapper(dtpName=dynamic-tp-test-1, corePoolSize=6, maxPoolSize=8, keepAliveTime=50, queueType=VariableLinkedBlockingQueue, queueCapacity=200, rejectType=RejectedCountableCallerRunsPolicy, allowCoreThreadTimeOut=false)&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;配置变更会推送通知消息，且会高亮变更的字段&lt;/p&gt;   &lt;pre&gt;    &lt;code&gt;
DynamicTp [dynamic-tp-test-1] refresh end, changed keys: [corePoolSize, queueCapacity], corePoolSize: [6 =&amp;gt; 4], maxPoolSize: [8 =&amp;gt; 8], queueType: [VariableLinkedBlockingQueue =&amp;gt; VariableLinkedBlockingQueue], queueCapacity: [200 =&amp;gt; 2000], keepAliveTime: [50s =&amp;gt; 50s], rejectedType: [CallerRunsPolicy =&amp;gt; CallerRunsPolicy], allowsCoreThreadTimeOut: [false =&amp;gt; false]&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;通知报警&lt;/h3&gt; &lt;p&gt;触发报警阈值会推送相应报警消息（活性、容量、拒绝），且会高亮显示相应字段&lt;/p&gt; &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000041296800" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;配置变更会推送通知消息，且会高亮变更的字段&lt;/p&gt; &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000041296801" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;监控日志&lt;/h3&gt; &lt;p&gt;通过collectType属性配置监控指标采集类型，默认 logging&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;MicroMeter：通过引入相关MicroMeter依赖采集到相应的平台   &lt;br /&gt;（如Prometheus，InfluxDb...）&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Logging：定时采集指标数据以Json日志格式输出磁盘，地址${logPath}/dy    &lt;br /&gt;namictp/${appName}.monitor.log&lt;/p&gt;   &lt;pre&gt;    &lt;code&gt;2022-01-11 00:25:20.599 INFO [dtp-monitor-thread-1:d.m.log] {&amp;quot;activeCount&amp;quot;:0,&amp;quot;queueSize&amp;quot;:0,&amp;quot;largestPoolSize&amp;quot;:0,&amp;quot;poolSize&amp;quot;:0,&amp;quot;rejectHandlerName&amp;quot;:&amp;quot;RejectedCountableCallerRunsPolicy&amp;quot;,&amp;quot;queueCapacity&amp;quot;:1024,&amp;quot;fair&amp;quot;:false,&amp;quot;rejectCount&amp;quot;:0,&amp;quot;waitTaskCount&amp;quot;:0,&amp;quot;taskCount&amp;quot;:0,&amp;quot;queueRemainingCapacity&amp;quot;:1024,&amp;quot;corePoolSize&amp;quot;:6,&amp;quot;queueType&amp;quot;:&amp;quot;VariableLinkedBlockingQueue&amp;quot;,&amp;quot;completedTaskCount&amp;quot;:0,&amp;quot;dtpName&amp;quot;:&amp;quot;remoting-call&amp;quot;,&amp;quot;maximumPoolSize&amp;quot;:8}
2022-01-11 00:25:25.603 INFO [dtp-monitor-thread-1:d.m.log] {&amp;quot;activeCount&amp;quot;:0,&amp;quot;queueSize&amp;quot;:0,&amp;quot;largestPoolSize&amp;quot;:0,&amp;quot;poolSize&amp;quot;:0,&amp;quot;rejectHandlerName&amp;quot;:&amp;quot;RejectedCountableCallerRunsPolicy&amp;quot;,&amp;quot;queueCapacity&amp;quot;:1024,&amp;quot;fair&amp;quot;:false,&amp;quot;rejectCount&amp;quot;:0,&amp;quot;waitTaskCount&amp;quot;:0,&amp;quot;taskCount&amp;quot;:0,&amp;quot;queueRemainingCapacity&amp;quot;:1024,&amp;quot;corePoolSize&amp;quot;:6,&amp;quot;queueType&amp;quot;:&amp;quot;VariableLinkedBlockingQueue&amp;quot;,&amp;quot;completedTaskCount&amp;quot;:0,&amp;quot;dtpName&amp;quot;:&amp;quot;remoting-call&amp;quot;,&amp;quot;maximumPoolSize&amp;quot;:8}
2022-01-11 00:25:30.609 INFO [dtp-monitor-thread-1:d.m.log] {&amp;quot;activeCount&amp;quot;:0,&amp;quot;queueSize&amp;quot;:0,&amp;quot;largestPoolSize&amp;quot;:0,&amp;quot;poolSize&amp;quot;:0,&amp;quot;rejectHandlerName&amp;quot;:&amp;quot;RejectedCountableCallerRunsPolicy&amp;quot;,&amp;quot;queueCapacity&amp;quot;:1024,&amp;quot;fair&amp;quot;:false,&amp;quot;rejectCount&amp;quot;:0,&amp;quot;waitTaskCount&amp;quot;:0,&amp;quot;taskCount&amp;quot;:0,&amp;quot;queueRemainingCapacity&amp;quot;:1024,&amp;quot;corePoolSize&amp;quot;:6,&amp;quot;queueType&amp;quot;:&amp;quot;VariableLinkedBlockingQueue&amp;quot;,&amp;quot;completedTaskCount&amp;quot;:0,&amp;quot;dtpName&amp;quot;:&amp;quot;remoting-call&amp;quot;,&amp;quot;maximumPoolSize&amp;quot;:8}
2022-01-11 00:25:35.613 INFO [dtp-monitor-thread-1:d.m.log] {&amp;quot;activeCount&amp;quot;:0,&amp;quot;queueSize&amp;quot;:0,&amp;quot;largestPoolSize&amp;quot;:0,&amp;quot;poolSize&amp;quot;:0,&amp;quot;rejectHandlerName&amp;quot;:&amp;quot;RejectedCountableCallerRunsPolicy&amp;quot;,&amp;quot;queueCapacity&amp;quot;:1024,&amp;quot;fair&amp;quot;:false,&amp;quot;rejectCount&amp;quot;:0,&amp;quot;waitTaskCount&amp;quot;:0,&amp;quot;taskCount&amp;quot;:0,&amp;quot;queueRemainingCapacity&amp;quot;:1024,&amp;quot;corePoolSize&amp;quot;:6,&amp;quot;queueType&amp;quot;:&amp;quot;VariableLinkedBlockingQueue&amp;quot;,&amp;quot;completedTaskCount&amp;quot;:0,&amp;quot;dtpName&amp;quot;:&amp;quot;remoting-call&amp;quot;,&amp;quot;maximumPoolSize&amp;quot;:8}
2022-01-11 00:25:40.616 INFO [dtp-monitor-thread-1:d.m.log] {&amp;quot;activeCount&amp;quot;:0,&amp;quot;queueSize&amp;quot;:0,&amp;quot;largestPoolSize&amp;quot;:0,&amp;quot;poolSize&amp;quot;:0,&amp;quot;rejectHandlerName&amp;quot;:&amp;quot;RejectedCountableCallerRunsPolicy&amp;quot;,&amp;quot;queueCapacity&amp;quot;:1024,&amp;quot;fair&amp;quot;:false,&amp;quot;rejectCount&amp;quot;:0,&amp;quot;waitTaskCount&amp;quot;:0,&amp;quot;taskCount&amp;quot;:0,&amp;quot;queueRemainingCapacity&amp;quot;:1024,&amp;quot;corePoolSize&amp;quot;:6,&amp;quot;queueType&amp;quot;:&amp;quot;VariableLinkedBlockingQueue&amp;quot;,&amp;quot;completedTaskCount&amp;quot;:0,&amp;quot;dtpName&amp;quot;:&amp;quot;remoting-call&amp;quot;,&amp;quot;maximumPoolSize&amp;quot;:8}&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;暴露EndPoint端点(dynamic-tp)，可以通过http方式请求&lt;/p&gt;   &lt;pre&gt;    &lt;code&gt;[
    {
        &amp;quot;dtp_name&amp;quot;: &amp;quot;remoting-call&amp;quot;,
        &amp;quot;core_pool_size&amp;quot;: 6,
        &amp;quot;maximum_pool_size&amp;quot;: 12,
        &amp;quot;queue_type&amp;quot;: &amp;quot;SynchronousQueue&amp;quot;,
        &amp;quot;queue_capacity&amp;quot;: 0,
        &amp;quot;queue_size&amp;quot;: 0,
        &amp;quot;fair&amp;quot;: false,
        &amp;quot;queue_remaining_capacity&amp;quot;: 0,
        &amp;quot;active_count&amp;quot;: 0,
        &amp;quot;task_count&amp;quot;: 21760,
        &amp;quot;completed_task_count&amp;quot;: 21760,
        &amp;quot;largest_pool_size&amp;quot;: 12,
        &amp;quot;pool_size&amp;quot;: 6,
        &amp;quot;wait_task_count&amp;quot;: 0,
        &amp;quot;reject_count&amp;quot;: 124662,
        &amp;quot;reject_handler_name&amp;quot;: &amp;quot;CallerRunsPolicy&amp;quot;
    },
    {
        &amp;quot;max_memory&amp;quot;: &amp;quot;228 MB&amp;quot;,
        &amp;quot;total_memory&amp;quot;: &amp;quot;147 MB&amp;quot;,
        &amp;quot;free_memory&amp;quot;: &amp;quot;44.07 MB&amp;quot;,
        &amp;quot;usable_memory&amp;quot;: &amp;quot;125.07 MB&amp;quot;
    }
]&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;项目地址&lt;/h3&gt; &lt;p&gt;  &lt;strong&gt;gitee地址：&lt;/strong&gt;   &lt;a href="https://gitee.com/yanhom/dynamic-tp-spring-cloud-starter" rel="nofollow noreferrer" title="https://gitee.com/yanhom/dynamic-tp-spring-cloud-starter"&gt;https://gitee.com/yanhom/dynamic-tp-spring-cloud-starter&lt;/a&gt;&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;github地址&lt;/strong&gt;：  &lt;a href="https://github.com/lyh200/dynamic-tp-spring-cloud-starter" rel="nofollow noreferrer" title="https://github.com/lyh200/dynamic-tp-spring-cloud-starter"&gt;https://github.com/lyh200/dynamic-tp-spring-cloud-starter&lt;/a&gt;&lt;/p&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;联系作者&lt;/h3&gt; &lt;p&gt;对项目有什么想法或者建议，可以在上述地址中加到作者微信进行交流，或者创建issues，一起完善项目！&lt;/p&gt; &lt;p&gt;最后，支持的话还望大家去点个star哦。&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>开源软件 java 线程池 监控</category>
      <guid isPermaLink="true">https://itindex.net/detail/62041-%E7%BA%BF%E7%A8%8B%E6%B1%A0-%E4%BD%95%E8%A7%82-%E7%BA%BF%E7%A8%8B%E6%B1%A0</guid>
      <pubDate>Mon, 17 Jan 2022 16:04:02 CST</pubDate>
    </item>
    <item>
      <title>HTTP抓包工具之Charles</title>
      <link>https://itindex.net/detail/61869-http-%E5%B7%A5%E5%85%B7-charles</link>
      <description>&lt;h2&gt;Charles简介&lt;/h2&gt;
 &lt;p&gt;Charles是一个HTTP代理服务器，当浏览器连接Charles的代理访问互联网时，Charles可以监控浏览器发送和接收的所有数据。它允许一个开发者查看所有连接互联网的HTTP通信，这些包括request, response和HTTP headers （包含cookies与caching信息）。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="197" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/charles.jpg" width="560"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Charles主要功能：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;支持SSL代理。可以截取分析SSL的请求。&lt;/li&gt;
  &lt;li&gt;支持流量控制。可以模拟慢速网络以及等待时间（latency）较长的请求。&lt;/li&gt;
  &lt;li&gt;支持AJAX调试。可以自动将json或xml数据格式化，方便查看。&lt;/li&gt;
  &lt;li&gt;支持AMF调试。可以将Flash Remoting 或 Flex Remoting信息格式化，方便查看。&lt;/li&gt;
  &lt;li&gt;支持重发网络请求，方便后端调试。&lt;/li&gt;
  &lt;li&gt;支持修改网络请求参数。&lt;/li&gt;
  &lt;li&gt;支持网络请求的截获并动态修改。&lt;/li&gt;
  &lt;li&gt;检查HTML，CSS和RSS内容是否符合W3C标准。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;以上介绍了Charles的主要功能，个人在使用过程中主要用的是抓取HTTP和HTTPS请求。特别是HTTPS的请求，抓取起来还是有一些麻烦，特此记录。&lt;/p&gt;
 &lt;h2&gt;Charles 抓包原理&lt;/h2&gt;
 &lt;p&gt;市面上绝大多数的抓包软件，背后的原理都是中间人攻击（Man-in-the-middle attack，缩写：MITM）。&lt;/p&gt;
 &lt;p&gt;维基百科是这样定义 MITM 的：中间人攻击在密码学和计算机安全领域中是指攻击者与通讯的两端分别建立独立的联系，并交换其所收到的数据，使通讯的两端认为他们正在通过一个私密的连接与对方直接对话，但事实上整个会话都被攻击者完全控制。&lt;/p&gt;
 &lt;p&gt;上面的定义写的很清晰，下图中结合箭头方向就能看懂 HTTP Packets 的流向：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="323" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/MITM.png" width="674"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;Charles的使用&lt;/h2&gt;
 &lt;p&gt;Charles的安装过程是比较简单，只需到  &lt;a href="https://www.charlesproxy.com/"&gt;官网&lt;/a&gt;下载安装即可。比较困难的是HTTPS请求的配置。&lt;/p&gt;
 &lt;h3&gt;Windows下HTTPS请求抓包&lt;/h3&gt;
 &lt;p&gt;1、配置SSL支持。点击【Proxy】–&amp;gt;【SSL Proxying Settings…】，在弹出选项卡中，勾选【Enable SSL Proxying】点击【add】，在Host输入【*】表示接收任何主机，在Prot输入【*】表示任何端口，最后点击【ok】保存。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="425" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/ssl.png" width="525"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;2、安装证书。点击【Help】–&amp;gt;【SSL Proxying】–&amp;gt;【Install Charles Root Certificate】，按照引导流程安装证书。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="606" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/ca.png" width="431"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;完成后打开IE进行测试：出现证书错误！&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="258" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/ie.png" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;打开Chrome测试：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="391" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/chrome.png" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;打开Edge测试：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="317" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/edge.png" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;都被安全拦截了，装了证书都不起作用。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;解决方案：安装Firefox！&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;安装完毕后在开启Charles时，使用Firefox打开，http://chls.pro/ssl，弹出如下页面：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="313" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/firefox.png" width="434"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;选择保存文件后按确定。文件默认保存到下载文件夹。&lt;/p&gt;
 &lt;p&gt;打开Firefox【设置】–&amp;gt;【隐私与安全】–&amp;gt;【证书】–&amp;gt;【查看证书】&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="91" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/pem-1.png" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;使用【证书管理器】–&amp;gt;【证书办法机构】–&amp;gt;【导入】进行导入操作。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="365" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/pem-2.png" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;iOS下HTTPS请求抓包&lt;/h3&gt;
 &lt;p&gt;在PC上开启共享网络。将手机连接到PC共享的WIFI上。&lt;/p&gt;
 &lt;p&gt;在手机上设置代理地址，代理IP为PC的IP，端口为Charles的端口。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="156" src="https://www.biaodianfu.com/wp-content/uploads/2021/11/ios.png" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在手机自带浏览器Safari中输入chls.pro，完成后需要进入【设置】安装描述文件。安装完毕后，如果是iOS 10 以后需要进入【设置】–&amp;gt;【通用】–&amp;gt;【关于本机】–&amp;gt;【证书信任设置】，开启证书。&lt;/p&gt;
 &lt;h3&gt;Android下HTTPS请求抓包&lt;/h3&gt;
 &lt;p&gt;在PC上开启共享网络。将手机连接到PC共享的WIFI上。&lt;/p&gt;
 &lt;p&gt;在手机上设置代理地址，代理IP为PC的IP，端口为Charles的端口。&lt;/p&gt;
 &lt;p&gt;在手机默认浏览器中输入chls.pro，下载downloadfile.crt文件，然后在【我的下载】中进行打开，按引导进行安装。&lt;/p&gt;
 &lt;div&gt;
  &lt;h3&gt;相关文章:&lt;/h3&gt;  &lt;ol&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/python-build-web-server.html" rel="bookmark" title="Python &amp;#20174;0&amp;#21040;1&amp;#25645;&amp;#24314;Web &amp;#26381;&amp;#21153;&amp;#22120;"&gt;Python 从0到1搭建Web 服务器 &lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/skyline-centos-7.html" rel="bookmark" title="Skyline&amp;#23454;&amp;#25112;&amp;#65306;CentOS 7&amp;#37096;&amp;#32626;"&gt;Skyline实战：CentOS 7部署 &lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;a href="https://www.biaodianfu.com/install-wordpress-on-ubuntu-20-04-with-lemp-stack.html" rel="bookmark" title="Ubuntu Server 20.04 WordPress&amp;#29615;&amp;#22659;&amp;#23433;&amp;#35013;&amp;#19982;&amp;#37197;&amp;#32622;"&gt;Ubuntu Server 20.04 WordPress环境安装与配置 &lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>器→工具 工具软件 抓包 爬虫</category>
      <guid isPermaLink="true">https://itindex.net/detail/61869-http-%E5%B7%A5%E5%85%B7-charles</guid>
      <pubDate>Tue, 02 Nov 2021 09:20:20 CST</pubDate>
    </item>
    <item>
      <title>通过DLNA让Windows电脑成为媒体存储设备</title>
      <link>https://itindex.net/detail/61076-dlna-windows-%E7%94%B5%E8%84%91</link>
      <description>&lt;p&gt;　　由于电视盒子和智能电视的种种限制，导致很多视频无法在电视上播放，需要使用外部存储设备，例如U盘、移动硬盘、NAS等等，对于多个电视终端设备来说，移动硬盘等插拔起来不方便，使用起来易损坏，NAS搭建较为麻烦，需要额外成本，实际上，Windows电脑通过一些操作和设置，可以实现类似NAS的相同功能，而无需再购买额外设备，这里就介绍以下设置和使用的方法。&lt;/p&gt;

 &lt;p&gt;　　DLNA（Digital Living Network Alliance/数字生活网络联盟）是由索尼、英特尔、微软等发起成立的一套解决电脑、移动设备、消费电器之间互联互通的协议。它们的宗旨是“随时随地享受音乐、照片和视频”。它们的目标在于创建一套可以使得各厂商的产品互相连接，互相适应的工业标准，从而为消费者实现数字化生活。&lt;/p&gt;

 &lt;p&gt;　　DLNA与苹果的AirPlay功能比较类似，协议也大体相同，他们都可以让用户电脑或其他设备中的媒体内容连接到电视屏幕里，用户只要智能电视支持AirPlay或DLNA，即在智能电视上观看同一个局域网下的某个设备上的视频。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#36890;&amp;#36807;DLNA&amp;#35753;Windows&amp;#30005;&amp;#33041;&amp;#25104;&amp;#20026;&amp;#23186;&amp;#20307;&amp;#23384;&amp;#20648;&amp;#35774;&amp;#22791;" src="https://www.williamlong.info/upload/6283_1.jpg"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;　　先要保证电脑和智能电视或电视盒子同处于一个局域网下，智能电视要支持DLNA功能，例如小米电视和小米盒子就支持DLNA功能，在其内置应用“高清播放器”里，可以看到同一个网络下的DLNA设备。&lt;/p&gt;

 &lt;p&gt;　　接着，我们需要在电脑上安装DLNA服务器，实际上，目前微软的Windows操作系统已经集成了DLNA服务器，也就是Windows Media Player软件，只需要做一些简单的设置接口。&lt;/p&gt;

 &lt;p&gt;　　在“设置”-“网络和Internet”-“共享选项”-“网络和共享中心”里，如果媒体流未启用，则点击“启用媒体流”。&lt;/p&gt;

 &lt;p&gt;　　第一，首先保证系统为Windows 7以上系统的Windows Media Player，打开“网络和共享中心”，点击左边的“更改高级共享设置”，在“流媒体”那一栏中点击“选择流媒体选项”然后点击“启用”。在弹出来的窗口中保持列表中的设备都是处于“已允许”的状态，然后点击“确定”。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#36890;&amp;#36807;DLNA&amp;#35753;Windows&amp;#30005;&amp;#33041;&amp;#25104;&amp;#20026;&amp;#23186;&amp;#20307;&amp;#23384;&amp;#20648;&amp;#35774;&amp;#22791;" src="https://www.williamlong.info/upload/6283_2.jpg"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;　　第二，接下来打开Windows自带的Windows Media Player播放器，点击“媒体流”，勾选“自动允许设备播放我的媒体”，点“组织”-“管理媒体库”-“视频”，将电脑上的视频文件都集中在一个文件夹里，然后将这个文件夹添加到库中。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#36890;&amp;#36807;DLNA&amp;#35753;Windows&amp;#30005;&amp;#33041;&amp;#25104;&amp;#20026;&amp;#23186;&amp;#20307;&amp;#23384;&amp;#20648;&amp;#35774;&amp;#22791;" src="https://www.williamlong.info/upload/6283_3.jpg"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;　　完成以上两步后，就可以将Windows Media Player的“媒体库”中视频通过DLNA分享到处于同一个无线WIFI网络环境中智能电视或电视盒子了。&lt;/p&gt;

 &lt;p&gt;　　在智能电视或电视盒子端，打开“高清播放器”，电视会自动搜索DLNA设备，如果设置都正常，会看到提示“1个DLNA设备”，点进去，选择“视频”-“文件夹”，即可看到电脑端的共享文件，点击视频文件即可播放。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#36890;&amp;#36807;DLNA&amp;#35753;Windows&amp;#30005;&amp;#33041;&amp;#25104;&amp;#20026;&amp;#23186;&amp;#20307;&amp;#23384;&amp;#20648;&amp;#35774;&amp;#22791;" src="https://www.williamlong.info/upload/6283_4.jpg"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#36890;&amp;#36807;DLNA&amp;#35753;Windows&amp;#30005;&amp;#33041;&amp;#25104;&amp;#20026;&amp;#23186;&amp;#20307;&amp;#23384;&amp;#20648;&amp;#35774;&amp;#22791;" src="https://www.williamlong.info/upload/6283_5.jpg"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;　　经过上面的设置，我们的电脑就会变成一个类似NAS的设备，可以共享指定文件夹的视频，我们只要电脑硬盘足够大，里面放多少视频都可以在电视上播放。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件应用</category>
      <guid isPermaLink="true">https://itindex.net/detail/61076-dlna-windows-%E7%94%B5%E8%84%91</guid>
      <pubDate>Sun, 13 Dec 2020 20:30:28 CST</pubDate>
    </item>
    <item>
      <title>code-gen 1.2.1 发布，新增 vue-element-admin 增删改查模板</title>
      <link>https://itindex.net/detail/60813-code-gen-vue</link>
      <description>code-gen 1.2.1 发布，本次更新内容如下： 修复保存模板时的错误 模板编辑器新增行号 新增admin-vue-CRUD模板 doc 新增的vue模板可配合vue-element-admin使用，效果图： 关于code-gen 一款代码生成工具，可自定义模板生成不同的代码，支持MySQL、Oracle、SQL Server、PostgreSQL 只需要一个Java8环境，下载后即可运行使用...&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/60813-code-gen-vue</guid>
      <pubDate>Wed, 12 Aug 2020 16:06:14 CST</pubDate>
    </item>
    <item>
      <title>建议收藏！2020 年必备的几个 DevOps 工具</title>
      <link>https://itindex.net/detail/60672-%E6%94%B6%E8%97%8F-devops-%E5%B7%A5%E5%85%B7</link>
      <description>&lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVbIhGv" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;提到 DevOps 这个词，我相信很多人一定不会陌生。作为一个热门的概念，DevOps近 年来频频出现在各大技术社区和媒体的文章中。到了 2020 年，DevOps 的革命也终于成为了一个主流，DevOps 相关工具的受欢迎程度也在激增。根据 Google 趋势，「DevOps 工具」的搜索量一直在稳定增长，并且这种趋势还在持续。&lt;/p&gt;
 &lt;p&gt;DevOps 工具越来越多，了解它们以及知道在什么时候使用他们越来越重要。由于 DevOps 涵盖了整个软件开发生命周期，因此有很多工具可供选择。让我们将其大致分为以下几类：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;开发和构建工具&lt;/li&gt;
  &lt;li&gt;自动化测试工具&lt;/li&gt;
  &lt;li&gt;部署工具&lt;/li&gt;
  &lt;li&gt;运行时 DevOps 工具&lt;/li&gt;
  &lt;li&gt;协作 DevOps 工具&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;成功且成熟地采用 DevOps 做法将始终拥有完整的渠道，其中包括适用于这五个类别的工具。确保评估您当前的工具堆栈，以确保您没有丢失 CI/CD 管道的关键部分。&lt;/p&gt;
 &lt;h2&gt;开发和构建工具&lt;/h2&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhCL" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这是 CI/CD 管道堆栈的基础。一切都从这里开始。该类别中最好的工具可以协调多个事件流，并可以轻松地与外部工具集成。&lt;/p&gt;
 &lt;p&gt;软件开发生命周期的这一部分中的工具分为三个子类别：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;源代码控制管理（SCM）&lt;/li&gt;
  &lt;li&gt;持续集成（CI）&lt;/li&gt;
  &lt;li&gt;数据管理&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;2020年，推荐的SCM技术是GIT，因此我们的SCM工具必须具有出色的GIT支持。对于CI，绝对需要在临时容器化环境中运行和执行构建的能力。对于数据管理，我们需要能够对数据库架构进行更改并使它与应用程序版本保持一致。&lt;/p&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的SCM + CI工具：Gitlab和Gitlab-CI&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhCV" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Gitlab无疑是2020年最伟大的DevOps Lifecycle工具，它将在可预见的未来成为创新的领导者。&lt;/p&gt;
 &lt;p&gt;Gitlab的核心功能提供了一个完美的GIT存储库管理工具。它基于Web的用户界面是最冗长且易于使用的。Gitlab的免费套餐可提供您所需的一切，并且具有SaaS和On-Prem尺寸。&lt;/p&gt;
 &lt;p&gt;市场上有很多SCM工具，但是没有一种工具像Gitlab多年来所做的那样将“持续集成”直接集成到您的存储库中。称为Gitlab-CI，将.gitlab-ci.yml文件粘贴到代码库的根目录中，任何GIT事件都会根据您在此处定义的内容触发操作。他们确实是按代码进行持续集成的领导者。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;成熟度 - 该产品自2013年以来一直投放市场，并且非常稳定并且得到了很好的支持。&lt;/li&gt;
  &lt;li&gt;开源 - Gitlab的免费版没有削减开发团队所需的核心功能。每个付费层都提供了附加功能，这些附加功能可根据组织的规模和需求带来极高的价值。&lt;/li&gt;
  &lt;li&gt;易用的 CI — 市场上没有其他工具可以像Gitlab-CI一样直接将持续集成直接嵌入到您的SCM中。使用Docker构建进行临时构建的能力提供了无忧的构建作业，并且内置的报告使调试构建失败变得容易。无需复杂的集成和业务流程就可以对多种工具进行编排。&lt;/li&gt;
  &lt;li&gt;无限集成 - Gitlab提供了每个核心DevOps类别中所需工具的轻松集成。这使开发人员和操作人员在任何环境中都可以使用一个真实的来源来获取与其应用程序相关的信息。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手:&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;还有其他工具在此领域也很流行，但是它们不如Gitlab。原因如下：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;GitHub - GitHub一直是小型和早期开发商店的出色SaaS源代码管理系统。但是，对于需要在网络中保留其IP的大型企业，GitHub的唯一选择是.OVA不支持高可用性的虚拟机。这使其难以维护on-prem，并且只能在中型组织中运行，然后服务器本身才开始崩溃。它缺少GitHub Actions（直到最近，但仍不在本地版本中）或CI-as-Code，这意味着您始终需要带上自己的CI工具并管理该集成。最后，它比任何Gitlab定价都昂贵。&lt;/li&gt;
  &lt;li&gt;Jenkins — 尽管Jenkins已经成为持续集成工具的默认标准，但它始终缺少源代码控制元素。意味着，您将始终使用Jenkins 和 SCM工具。当像GitLab这样的工具同时提供这两种功能时，这简直是不必要的复杂。它可怕的UX使得现代Web应用程序有很多不足之处。&lt;/li&gt;
  &lt;li&gt;BitBucket/Bamboo — 我不得不说，这是一个自动失败者，考虑到您需要两种工具来完成Gitlab的一项工作。尽管BitBucket云支持Gitlab-CI / GitHub Action功能，但没有一家公司（规模超过一家初创公司）可以轻易采用它。用于本地的 BitBucket服务器甚至不支持BitBucket管道！&lt;/li&gt;
&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的数据管理工具：FlywayDB&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhDs" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Web应用程序开发中最容易被忽视的方面是数据库的自动化需求。在应用程序的新版本中部署数据库架构更改通常是事后的想法。模式更改通常会添加或重命名列或表。如果应用程序版本与架构版本不匹配，则该应用程序可能会完全损坏。由于存在两个不同的系统，因此通过应用程序升级来协调数据库更改也可能很困难。FlyWayDB解决了所有这些问题。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;数据库版本控制 - FlyWay允许您简单地创建数据库版本，跟踪数据库迁移以及轻松地前滚或后退架构更改，而无需某些定制解决方案。&lt;/li&gt;
  &lt;li&gt;二进制或内置 - 您可以选择在应用程序启动时或作为二进制可执行文件运行Flyway。在代码中使用此工具，以便它在启动时检查版本功能并运行适当的迁移，从而使数据库和应用程序版本保持同步。您也可以临时运行cmd行，从而在不重建整个应用程序的情况下为现有数据库提供了灵活性。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;这个空间中没有太多工具。但是，让我们来看几个：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;LiquiBase — Liquibase是相似的，实际上，如果有人在我的组织中工作过，那么我很乐意通过FlyWay对该工具进行标准化。&lt;/li&gt;
  &lt;li&gt;Flocker - 这可能仅适用于容器化的应用程序-在容器中运行数据库非常困难，必须精心计划才能成功执行。我建议将RDS之类的服务用于数据库，而不要尝试运行存储在容器中的关键数据。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;自动化测试工具&lt;/h2&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhDJ" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;我们必须首先将自动化工具安装到测试金字塔中，从而开始对自动测试工具进行评估。测试金字塔有4层：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;单元测试 - 这是所有自动化测试的基础。就数量而言，与其他类型相比，您应该拥有最多的单元测试。这些测试应由软件开发人员编写和运行，以确保应用程序的一部分（称为“单元”）符合其设计并按预期运行。&lt;/li&gt;
  &lt;li&gt;组件测试 — 组件测试的主要目的是验证测试对象的输入/输出行为。这样可以确保测试对象的功能按照所需规范正确运行。&lt;/li&gt;
  &lt;li&gt;集成测试 — 这是测试阶段，在此阶段中，各个软件模块被组合在一起并作为一个整体进行测试。&lt;/li&gt;
  &lt;li&gt;端到端测试 - 此层是不言自明的。我们正在研究从头到尾的应用程序流程，并使其表现出预期的效果。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;由于单元和组件层测试仅由应用程序开发人员驱动，并且通常是特定于编程语言的，因此我们不会在DevOps空间中评估这些工具。&lt;/p&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的集成测试工具：Cucumber&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhDP" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Cucumber将规范和测试文档合并为一个有凝聚力的有效文档。由于它们是由Cucumber自动测试的，因此您的规格始终是最新的。如果您想开始构建Web自动化测试框架并在Web应用程序上模拟用户行为，那么带有Java和Cucumber BDD的Selenium WebDriver是在项目中学习和实现Cucumber的好方法。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;行为驱动的开发 — Cucumber用于BDD测试，它已成为一种入门测试框架（与传统的测试驱动开发相比）。&lt;/li&gt;
  &lt;li&gt;动态文档 - 记录您所做的事情总是很痛苦。由于您的测试被定义​​为代码，因此Cucumber测试会自动生成文档以进行匹配以确保它们始终保持同步。&lt;/li&gt;
  &lt;li&gt;支持 - 这里有很多工具可供选择，但是当情况变得严重时，您需要工具维护者的认真支持。黄瓜拥有足够的资金和支持结构来维持该工具的未来几年。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在这个领域中有许多框架和特定于技术的工具，但是只有Cucumber接近于“一刀切”的解决方案。&lt;/p&gt;
 &lt;h2&gt;端到端测试工具&lt;/h2&gt;
 &lt;p&gt;进行端到端测试时，有两个重点领域需要关注：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;功能测试&lt;/li&gt;
  &lt;li&gt;负载测试&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;功能测试显然是在测试我们想要发生的事情是否实际发生。当我单击SPA上的某些页面，填写表格并单击Submit时，数据将显示在数据库中，并且屏幕显示成功！&lt;/p&gt;
 &lt;p&gt;我们还需要能够测试在相同场景下工作的x数量的用户是否可以正确处理。&lt;/p&gt;
 &lt;p&gt;如果您在这两个方面都没有进行测试，则CI / CD管道中的差距将很大。&lt;/p&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的端到端测试工具 — 功能：SoapUI Pro&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhDR" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;由于SOAP Web服务是默认的，因此SoapUI进入API测试领域已有很长时间了。尽管我们不再构建新的SOAP服务，并且该工具的名称没有更改，但这并不意味着它没有发展。SoapUI为构建后端Web服务的自动化功能测试提供了一种出色的结构。这些可以轻松地与持续集成工具集成，并且可以作为我们的CI / CD管道的一部分运行。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;广泛的文档 - 此工具已经存在了一段时间，因此有许多在线资源可帮助您确定如何配置负载测试。&lt;/li&gt;
  &lt;li&gt;易于使用 — 尽管有多种API测试工具可用，但拥有一个用于多种服务的接口可以使构建测试变得简单。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;Selenium - Selenium是该领域的另一个出色工具。如果您正在构建和运行基于Java的应用程序，则建议使用它。但是，如果您要使用多种技术来处理一个完整的Web应用程序，那么对于非Java语言的用户来说可能会有些笨拙。&lt;/li&gt;&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的端到端测试工具 — 负载测试：LoadRunner&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhDS" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;说明：在对应用程序的各个方面进行负载测试时，只有LoadRunner才能完成。是的，这很昂贵而且入门有点困难，但是它是唯一可以执行测试的工具，可以使我作为技术架构师相信新代码将在极端压力下执行。另外，我认为现在是时候让负载运行技巧从SQA资源转移到开发团队了。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;广泛的文档 - 该工具已经存在了一段时间，因此有许多在线资源可以帮助您确定如何配置负载测试。&lt;/li&gt;
  &lt;li&gt;协议支持 - 从ODBC到AJAX，再到HTTPS以及您的应用程序可能在某处使用的其他晦涩协议，LoadRunner支持该协议。我们要避免串接多个负载测试工具-这只会增加复杂性。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;击败竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;再说一次，在这个领域中没有太多的“一刀切”的工具，因此简单的解决方案是可以在任何环境中使用任何技术将其丢弃。&lt;/p&gt;
 &lt;h2&gt;部署工具&lt;/h2&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhDT" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;部署工具可能是应用程序开发中鲜为人知的方面。对于操作人员来说，如果不深入了解应用程序代码和功能，就很难使用部署工具。对于开发人员来说，管理代码部署是一项新的职责，因此他们对许多部署工具的经验很少。&lt;/p&gt;
 &lt;p&gt;首先，让我们将部署工具分为三个子类别：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;构件管理&lt;/li&gt;
  &lt;li&gt;配置管理&lt;/li&gt;
  &lt;li&gt;部署方式&lt;/li&gt;
&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的工件管理工具：Nexus&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhDV" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Nexus工件存储库支持几乎所有主要技术，从Java到NPM再到Docker。我们可以使用这一工具来存储我们所有可部署的工件。通过使软件包更接近构建过程，代理远程软件包管理器的能力还大大提高了我们CI配置的速度。这样做的另一个好处是，我们可以全局查看跨多个软件项目使用的所有软件包，从而锁定不安全的开源软件包，这些软件包可能是我们代码中的攻击媒介。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;技术支持 - 该产品自2013年以来一直投放市场，并且非常稳定且得到了很好的支持。&lt;/li&gt;
  &lt;li&gt;开源 - Gitlab的免费版本没有削减开发团队需要的核心功能。每个付费层均提供附加功能，这些附加功能可带来最大价值，具体取决于组织的规模和需求。&lt;/li&gt;
&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的配置管理工具：Ansible&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhD5" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Ansible是这个领域的领导者，原因很简单：无国籍。较早的现场配置管理工具着重于管理配置状态。如果它与所需的配置脱离同步，它将自行修复。在新的应用程序中，我们只有无状态组件。新版本的代码是新的构件，并已部署以替换现有的构件。我们拥有短暂的短暂环境。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;无状态 - Ansible剧本是从操作员机器上运行的，并命中服务器目标。我不在乎远程对象的状态，这使得使用Packer之类的工具来构建可部署对象变得更加容易。&lt;/li&gt;
  &lt;li&gt;开源 - 和CentOS一样，Ansible也由RedHat维护。该企业及其高级支持人员可以帮助维护社区，并确保高质量，易于使用的模块。&lt;/li&gt;
  &lt;li&gt;分子测试 — 因为配置管理和其他任何东西一样都是代码，所以如果不对其进行测试，我们将无所不能。用于测试Ansible角色的分子框架可以无缝地工作，以确保我们的按代码配置质量一样高，并遵循与应用程序代码相同的CI / CD管道。&lt;/li&gt;
  &lt;li&gt;YAML — 与其他工具相比，YAML更加容易使您头脑清醒。由于配置管理对于采用DevOps的任何人来说通常都是新事物，因此这使其成为关键卖点。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;OpsCode Chef - 我以厨师食谱开发人员的身份开始了DevOps生涯。露比和厨师很亲密，我的心。但是，它们根本无法解决当今无状态，云原生应用程序的问题。对于更传统的遗留应用程序来说，这是一个很好的工具，但是本文将重点放在未来。&lt;/li&gt;
  &lt;li&gt;Puppet — Puppet从未成长为一个庞大的社区，特别是与Chef and Ansible相比。它非常适合配置和裸机，但不支持Web应用程序类型的配置管理。&lt;/li&gt;
&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的部署工具：Terraform&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhD9" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Terraform解决了从网络组件到实际服务器映像定义基础架构即代码的问题。自最初发布以来，它已经走了很长一段路，并建立了庞大的插件社区和支持社区，以帮助您解决可能遇到的几乎所有部署场景。支持本地，云中或其他任何类型的环境的能力是首屈一指的。最后，最新版本在HCL中提供了许多与其他任何传统编程语言相同的逻辑功能和类，从而使开发人员可以轻松学习和学习。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;不受云/环境影响 - Terraform利用提供的资源作为Terraform代码与与基础架构提供商进行通信所需的所有API和后端逻辑之间的接口。这意味着我可以学习一种工具，并且能够在任何地方工作。&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;开源 — 同样，很难敲响免费工具。社区支持是一流的。&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;AWS CloudFormation — 即使您仅在AWS云环境中工作，您也可能会在职业生涯中继续前进，而不是去那里。将您的技能和知识整合到一个平台中可能会有风险。此外，许多新的AWS服务通常在CloudFormation中可用之前作为Terraform模块提供。&lt;/li&gt;&lt;/ul&gt;
 &lt;h2&gt;运行时DevOps工具&lt;/h2&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhFr" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;任何开发项目的最终目标都是在生产中运行我们的应用程序。在DevOps世界中，我们希望确保我们对环境中的任何潜在问题具有可见性，并且还希望将人工干预降至最低。选择正确的运行时工具集对于实现开发必不可少的条件至关重要。&lt;/p&gt;
 &lt;p&gt;运行时工具子类别为：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;X 即服务&lt;/li&gt;
  &lt;li&gt;编排&lt;/li&gt;
  &lt;li&gt;监控方式&lt;/li&gt;
  &lt;li&gt;日志记录&lt;/li&gt;
&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的X-as-a-Service工具：Amazon Web Services&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhFt" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;亚马逊一直是云计算领域的领导者。他们也不仅止步于此-他们为开发人员提供了许多新服务，以利用它可以使您旋转。将任何技术和任何模式带到AWS上，就可以构建和运行它。与在自己的数据中心中构建，管理和维护传统硬件相比，它们的成本极其合理。免费服务层使任何人都有机会在必须做出购买决定之前进行尝试，这对于尝试以正确的方式构建应用程序而不必因成本而造成损害非常有用。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要好处：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;行业标准 - 如果您有在AWS中构建应用程序的经验，那么您基本上可以在任何地方找到工作。企业喜欢AWS，而创业公司喜欢AWS的低成本。&lt;/li&gt;
  &lt;li&gt;Free-Tier — 与其他所有功能相比，AWS的业务确实如此。让我使用该服务并查看其工作原理，然后再决定将数千美元投入可能有巨大陷阱的事物中。我从未为POC构建的任何产品都超过免费套餐限制。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Azure – 自最初发布以来，Azure已经走了很长一段路，值得称赞。但是，区分自身的需求已导致其对服务的名称进行了怪异的命名，而这些服务要难一点了-到底什么是“ blob存储”？尽管.NET代码在Microsoft生态系统中效果更好，但不太可能仅将.NET用于应用程序的各个方面。&lt;/li&gt;
  &lt;li&gt;Heroku — 简而言之，除了在Heroku上的个人项目外，我什么都不会运行。透明度不高，企业没有理由将其用作平台。这对于在博客中演示某些内容非常有用，但对于实际应用程序来说，非常感谢！&lt;/li&gt;
&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的编排工具：OpenShift&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhFu" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;您可能在应用程序堆栈中的某处使用了Docker或容器。无服务器应用程序很棒，但它们不能适合所有的架构模式。在没有业务流程平台的情况下运行容器根本行不通。从安全性和工具角度来看，Core Kubernetes带来了很多需求。OpenShift是唯一拥有Kubernetes平台的平台，它具有Source2Image构建，pod中的部署自动化以及甚至可追溯性和监视功能。它可以在本地，云中或同时在两者中运行。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;内置的安全性 - 管理K8安全性几乎需要博士学位。必须仔细考虑并考虑所有细节。默认情况下，OpenShift所采用的安全机制减少了开发人员的工作量，并为他们的应用程序提供了更安全的平台。&lt;/li&gt;
  &lt;li&gt;多合一解决方案 – 与默认不包含负载平衡工具的香草K8不同，OpenShift拥有一切。我可以使用它来托管我的容器，构建容器，运行CI / CD工具，协调外部流程，管理机密等等。尽管GUI仍然需要做更多的工作，但API优先的方法意味着一切都可以编写脚本，并且与K8的其他GUI不同，它使学习Kubernetes的基础知识变得更加简单，而无需首先获得该学位！&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;Docker Swarm - Docker swarm尝试通过删除大量内容来简化K8。这对于较小的应用程序非常有用，但对于企业应用程序则根本不起作用。此外，AWS ECS之类的服务采用了类似的方法，但是使我可能正在与之交互的其他服务（Lambda，IAM等）的使用变得更容易。&lt;/li&gt;&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的监控工具：New Relic&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhFv" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;New Relic的早期发行版确实做得非常好-APM监视。现在，它是一套完整的监视工具，使我可以监视服务器性能，容器性能，数据库性能，最终用户体验监视，当然还有APM监视。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;易用性 - 我在担任系统工程师时曾使用过许多监视工具，但从未遇到过像New Relic这样易于使用的监视工具。这是一个SaaS，因此不必设置服务器组件也很不错。&lt;/li&gt;
  &lt;li&gt;端到端可见性 - 其他工具尝试监视应用程序的一个特定方面。无论是CPU利用率还是网络流量，所有这些层都可以协同工作，以使您的应用正常运行。New Relic使您能够组合所有数据以真实了解正在发生的事情。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Zabbix — Zabbix是我最喜欢的监视系统，但是由于缺乏向云原生环境和APM空间发展的能力，因此使其滞后。它仍然可以很好地监视传统的服务器基础结构，仅此而已。&lt;/li&gt;
  &lt;li&gt;DataDog - 此工具过于侧重于管理生产应用程序的过程视角，而对代码本身的关注不足。在真正的DevOps团队中，有开发人员参与生产，我们无需依靠繁琐的工具来提供世界一流的支持。&lt;/li&gt;
&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的测井工具：Splunk&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhFM" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;很难反对Splunk。他们很久以来一直是日志聚合的领导者，并且他们继续做得最好。借助本地和SaaS产品，您可以在任何地方使用它。主要的缺点是，它仍然很难运行！&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;行业标准 —企业喜欢Splunk，他们也有钱为此付出代价。虽然初创企业可能难以证明其成本合理，但许多概念和技能可以转移到开源替代方案中。&lt;/li&gt;
  &lt;li&gt;可支持性 -简单地说，它可以正常工作。它具有许多默认值和即用型功能，因此您不必花费大量时间阅读文档并尝试使一些没有明确说明的内容能够正常工作。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;ELK Stack - ElasticSearch，LogStash和Kibana，虽然似乎总是很酷，因为它们不向您收取使用费用，但随着日志集的增长和机上越来越多的应用程序的维护，它的确变得更加困难您的工具。与使用Splunk相比，我在构建任何类型的仪表板之前花了更多的时间来设置工具。&lt;/li&gt;&lt;/ul&gt;
 &lt;h2&gt;协作DevOps工具&lt;/h2&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhFQ" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;DevOps首先是组织内部的文化变革。虽然购买工具不会一夜之间改变文化，但无疑可以帮助培养与同事合作的新方法。&lt;/p&gt;
 &lt;p&gt;协作工具子类别为：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;问题跟踪&lt;/li&gt;
  &lt;li&gt;聊天操作&lt;/li&gt;
  &lt;li&gt;文献资料&lt;/li&gt;
&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的问题跟踪工具：Jira&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhFV" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;吉拉（Jira）继续保持头把交椅，尽管在这个领域竞争日益激烈。但是，Jira内置的强大灵活性使开发团队和运营团队可以管理其项目工作和冲刺任务。使用敏捷术语的内置标准有助于缓解从传统工作方法到更精益流程的文化转变。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势:&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;行业标准 — 同样，就像许多工具一样，Jira到处都有使用。小型团队可以使用便宜的许可证并获得所需的一切，而企业可以为任何人负担得起许可证。&lt;/li&gt;
  &lt;li&gt;集成 - 在这个领域处于领先地位并且快速增长意味着第三方工具会选择您首先构建本机集成，而它们只会增加您工具的价值，而Jira就是这种情况。我们可以与现成的列表中的所有其他工具集成，而无需进行任何定制。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手:&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Trello — Trello成为免费使用的看板工具，因此迅速流行。但是，一旦事情开始扩展，并且您从数十个问题扩展到数千个问题，Trello将变得难以导航，搜索和报告。&lt;/li&gt;
  &lt;li&gt;Pivotal Tracker - 在初创公司工作期间，我非常喜欢该工具。但是，他们更多地关注产品管理，而不是技术任务。尽管从Jira进行产品管理比较困难，但是仍然可以完成此过程，而不必获取完全独立的工具。&lt;/li&gt;
&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的ChatOps工具：MatterMost&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhF0" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;说明：这可能是2020年这份清单上最大的惊喜，这是一件好事！MatterMost通过使用以前最好的工具，但引入了本地部署而获得了普及。对于企业来说，这是巨大的，因为它可以控制数据，还可以帮助与本地工具集成-我们不再需要为了新的事物而走出防火墙。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势:&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;开源 - MatterMost的开源版本非常适合小型或大型团队。与Slack的免费层会丢失历史记录不同，您自己运行服务器意味着您拥有数据。&lt;/li&gt;
  &lt;li&gt;集成 - 因为API几乎100％基于Slack API，所以几乎所有Slacks集成都可以直接与MatterMost一起使用。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手:&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Slack - 松弛很棒，但是它们已经变得如此庞大，需要开始获利。他们业务的付费阶段即将到来，并且剥夺了Slack用来免费提供的许多价值，最关键的是聊天记录。&lt;/li&gt;
  &lt;li&gt;Microsoft Teams - 尝试将Microsoft产品与非Microsoft本地产品集成-祝您好运。这就是我要说的！&lt;/li&gt;
&lt;/ul&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2020年排名第一的文档工具：Confluence&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhF6" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;无论使用哪种工具，都很难创建和维护高质量的技术文档。尽管最近有许多SaaS文档工具进入市场，但我很难接受将有关关键应用程序的敏感技术文档存储给第三方。我需要将数据和文档保留在本地，这就是Confluence为我所做的。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;主要优势：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;易于管理 - 大多数自托管工具的启动和运行可能有些复杂，并且大规模维护它们需要一些特定知识。开箱即用的Confluence服务器非常适合10个用户或10,000个用户。&lt;/li&gt;
  &lt;li&gt;插件－ 尽管创建具有默认融合功能的漂亮且易于浏览的文档已经很不错了，但是拥有用于几乎所有内容的插件的能力释放了Wiki的潜力。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;strong&gt;竞争对手：&lt;/strong&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Read the docs — 非常适合开源公共代码，但永远不会考虑在这里存储关键的应用程序知识。&lt;/li&gt;
  &lt;li&gt;MarkDown — 尽管非常适合于记录有关我的代码的内容，但很难将体系结构，过程或其他类型的文档直接放入MarkDown格式中。&lt;/li&gt;
  &lt;li&gt;Jekyll — 在记录技术知识时，我并不想简单地构建一个新的静态站点，以便在每次更改时进行部署。简单的Confluence版本管理系统使内部文档的处理变得更加容易。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;总结 2020 年最佳&lt;/h2&gt;
 &lt;p&gt;市场上实际上有数百种DevOps工具。试图浏览应使用哪些以及何时实施它们可能会令人不知所措。遵循此简单指南，为完整的CI / CD管道选择DevOps工具堆栈。&lt;/p&gt;
 &lt;p&gt;将工具分为以下五个关键领域：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;开发和构建工具&lt;/li&gt;
  &lt;li&gt;自动化测试工具&lt;/li&gt;
  &lt;li&gt;部署工具&lt;/li&gt;
  &lt;li&gt;运行时工具&lt;/li&gt;
  &lt;li&gt;协作工具&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;最后希望大家切记：自动化所有能自动化的事情！&lt;/p&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;blockquote&gt;部分参考链接：  &lt;br /&gt;  &lt;a href="https://medium.com/better-programming/must-learn-devops-tools-for-2020-1a8a2675e88f" rel="nofollow noreferrer"&gt;1. 《Must Learn DevOps Tools for 2020》&lt;/a&gt;  &lt;br /&gt;  &lt;a href="https://tech.treebo.com/how-to-create-a-devops-roadmap-treebos-1-year-devops-journey-27c072001a28" rel="nofollow noreferrer"&gt;2. 《How to create a DevOps roadmap &amp;amp; Treebo’s 9 month DevOps Journey》&lt;/a&gt;  &lt;br /&gt;  &lt;a href="https://www.softwareone.com/en/solutions/publisher-advisory-services/aws/devops-with-aws" rel="nofollow noreferrer"&gt;3. 《DevOps with AWS》&lt;/a&gt;  &lt;br /&gt;  &lt;a href="https://devops.com/using-this-time-to-optimize-your-dev-teams-workflow/" rel="nofollow noreferrer"&gt;4. 《 Using this Time to Optimize Your Dev Team’s Workflow》&lt;/a&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbIhGo" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>devops 工具软件</category>
      <guid isPermaLink="true">https://itindex.net/detail/60672-%E6%94%B6%E8%97%8F-devops-%E5%B7%A5%E5%85%B7</guid>
      <pubDate>Thu, 11 Jun 2020 20:59:14 CST</pubDate>
    </item>
    <item>
      <title>一个用于搜索电子书的 Telegram-bot</title>
      <link>https://itindex.net/detail/60239-%E6%90%9C%E7%B4%A2-%E7%94%B5%E5%AD%90%E4%B9%A6-telegram</link>
      <description>&lt;p&gt;其实这篇文章应该很早之前就写的，但是我太懒了，一直拖到现在。TG-bot还是蛮好玩的，可以做到很多意想不到的功能。因为i-Book.in页面的后端是algolia的，他们对于免费用户最大的数据存储量只有1W条。而经过多次扩容，我目前的数据量已经有超过了很多了，但是我还是没有将它整改，因为Flask实在是太难了。而多出的数据没有索引的话我自己要找也很麻烦，所以我搭建了一个TG-bot，后端使用Elasticsearch储存数据，这样哪怕数百万条的数据，也能轻松应对，前端使用的是Telegram的API。&lt;/p&gt; &lt;p&gt;如果有兴趣可以  &lt;a href="https://telegram.me/i_bookdotin" rel="noopener" target="_blank"&gt;   &lt;em&gt;&lt;/em&gt;点击这里&lt;/a&gt;到TG群组里骚扰这个bot哦。&lt;/p&gt; &lt;p&gt;注：需要翻墙才可以使用Telegram&lt;/p&gt; &lt;a&gt;&lt;/a&gt; &lt;p&gt;以下部分是这个bot的一些介绍。&lt;/p&gt; &lt;h2&gt;使用方法&lt;/h2&gt; &lt;p&gt;这个bot就只有一个命令，就是  &lt;code&gt;/so&lt;/code&gt;，这个命令可以同时搜索书名和作者，根据你输入的内容，返回最接近的结果，建议输入完整的书名/作者以获取最精确的结果。当然，如果搜索的是数据库没有的书也会返回一些关键词接近的结果。&lt;/p&gt; &lt;p&gt;找不到想要的书这很正常，毕竟只是一个的样本量很小的数据库，要知道现在每年新增的出版物有几十万册之多，目前的总量连每年新增的十分之一都没有。我也没打算据此  &lt;code&gt;盈利&lt;/code&gt;，只是对数据的整理以及提炼感兴趣。最近在爬取一些图书的信息，打算做一些数据的升华比如数据库里谁的书最多，那个国家的书最多，什么类型的书最多这样。&lt;/p&gt; &lt;p&gt;整个运行步骤简单来说就是：bot先接收私聊发来的信息返回给后端脚本，后端根据信息的内容去检索ES，再根据ES的返回数据解析出来的信息发送回接收到消息的频道。具体的细节不是很想写了，因为没有数据库，也没法复刻这个bot，所以我只打算写一些核心内容。&lt;/p&gt; &lt;h2&gt;构建&lt;/h2&gt; &lt;h3&gt;安装 docker&lt;/h3&gt; &lt;p&gt;因为ES我用的还不是很熟练，所以我直接使用的是docker版本，不用捣鼓java和断其八糟的配置项，直接pull就可以用了。&lt;/p&gt; &lt;table&gt;  &lt;tr&gt;   &lt;td&gt;    &lt;pre&gt;1     &lt;br /&gt;2     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;   &lt;td&gt;    &lt;pre&gt;curl -fsSL https://get.docker.com -o get-docker.sh     &lt;br /&gt;sudo sh get-docker.sh     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;h3&gt;安装&amp;amp;配置 ES&lt;/h3&gt; &lt;p&gt;docker安装完了之后就是要获取ES了：&lt;/p&gt; &lt;table&gt;  &lt;tr&gt;   &lt;td&gt;    &lt;pre&gt;1     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;   &lt;td&gt;    &lt;pre&gt;docker pull elasticsearch:6.7.0     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;p&gt;创建ES的挂载目录以及配置文件：&lt;/p&gt; &lt;table&gt;  &lt;tr&gt;   &lt;td&gt;    &lt;pre&gt;1     &lt;br /&gt;2     &lt;br /&gt;3     &lt;br /&gt;4     &lt;br /&gt;5     &lt;br /&gt;6     &lt;br /&gt;7     &lt;br /&gt;8     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;   &lt;td&gt;    &lt;pre&gt;cd  /     &lt;br /&gt;mkdir-p mnt/elasticsearch     &lt;br /&gt;cd  mnt/elasticsearch     &lt;br /&gt;mkdir config     &lt;br /&gt;mkdir master     &lt;br /&gt;mkdir slave     &lt;br /&gt;chmod 777 master     &lt;br /&gt;chmod 777 slave     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;p&gt;config 里面分别放两个配置文件：&lt;/p&gt; &lt;table&gt;  &lt;tr&gt;   &lt;td&gt;    &lt;pre&gt;1     &lt;br /&gt;2     &lt;br /&gt;3     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;   &lt;td&gt;    &lt;pre&gt;cd config     &lt;br /&gt;touch master.yml     &lt;br /&gt;touch slave.yml     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;p&gt;  &lt;em&gt;   &lt;code&gt;matser.yml&lt;/code&gt;&lt;/em&gt;：&lt;/p&gt; &lt;table&gt;  &lt;tr&gt;   &lt;td&gt;    &lt;pre&gt;1     &lt;br /&gt;2     &lt;br /&gt;3     &lt;br /&gt;4     &lt;br /&gt;5     &lt;br /&gt;6     &lt;br /&gt;7     &lt;br /&gt;8     &lt;br /&gt;9     &lt;br /&gt;10     &lt;br /&gt;11     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;   &lt;td&gt;    &lt;pre&gt;cluster.name: elasticsearch-cluster     &lt;br /&gt;node.name: master     &lt;br /&gt;network.bind_host: 0.0.0.0     &lt;br /&gt;network.publish_host: `your ip`     &lt;br /&gt;http.port: 9200     &lt;br /&gt;transport.tcp.port: 9300     &lt;br /&gt;http.cors.enabled: true     &lt;br /&gt;http.cors.allow-origin: &amp;quot;*&amp;quot;     &lt;br /&gt;node.master: true      &lt;br /&gt;node.data: true       &lt;br /&gt;discovery.zen.ping.unicast.hosts: [&amp;quot; `your ip`:9300&amp;quot;,&amp;quot; `your ip`:9301&amp;quot;]     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;p&gt;  &lt;em&gt;   &lt;code&gt;slave.yml&lt;/code&gt;&lt;/em&gt;：&lt;/p&gt; &lt;table&gt;  &lt;tr&gt;   &lt;td&gt;    &lt;pre&gt;1     &lt;br /&gt;2     &lt;br /&gt;3     &lt;br /&gt;4     &lt;br /&gt;5     &lt;br /&gt;6     &lt;br /&gt;7     &lt;br /&gt;8     &lt;br /&gt;9     &lt;br /&gt;10     &lt;br /&gt;11     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;   &lt;td&gt;    &lt;pre&gt;cluster.name: elasticsearch-cluster     &lt;br /&gt;node.name: slave     &lt;br /&gt;network.bind_host: 0.0.0.0     &lt;br /&gt;network.publish_host: `your ip`     &lt;br /&gt;http.port: 9202     &lt;br /&gt;transport.tcp.port: 9302     &lt;br /&gt;http.cors.enabled: true     &lt;br /&gt;http.cors.allow-origin: &amp;quot;*&amp;quot;     &lt;br /&gt;node.master: false     &lt;br /&gt;node.data: true       &lt;br /&gt;discovery.zen.ping.unicast.hosts: [&amp;quot;`your ip`:9300&amp;quot;,&amp;quot;`your ip`:9301&amp;quot;]     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;div&gt;  &lt;p&gt;注意！因为这个docker打包了java所以会特别消耗内存。&lt;/p&gt;&lt;/div&gt; &lt;p&gt;调高JVM线程数限制数量  &lt;code&gt;(否则会报错)&lt;/code&gt;：&lt;/p&gt; &lt;table&gt;  &lt;tr&gt;   &lt;td&gt;    &lt;pre&gt;1     &lt;br /&gt;2     &lt;br /&gt;3     &lt;br /&gt;4     &lt;br /&gt;5     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;   &lt;td&gt;    &lt;pre&gt;nano /etc/sysctl.conf     &lt;br /&gt;#添加这个     &lt;br /&gt;vm.max_map_count=262144      &lt;br /&gt;#保存后执行这个命令     &lt;br /&gt;sysctl -p     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;p&gt;初始化容器&lt;/p&gt; &lt;p&gt;  &lt;em&gt;   &lt;code&gt;master&lt;/code&gt;&lt;/em&gt;：&lt;/p&gt; &lt;table&gt;  &lt;tr&gt;   &lt;td&gt;    &lt;pre&gt;1     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;   &lt;td&gt;    &lt;pre&gt;docker run -e ES_JAVA_OPTS=&amp;quot;-Xms256m -Xmx256m&amp;quot; -d -p 9200:9200 -p 9300:9300 -v /mnt/elasticsearch/config/master.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /mnt/elasticsearch/master:/usr/share/elasticsearch/data --name es-master elasticsearch:6.7.0     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;p&gt;  &lt;em&gt;   &lt;code&gt;slave&lt;/code&gt;&lt;/em&gt;：&lt;/p&gt; &lt;table&gt;  &lt;tr&gt;   &lt;td&gt;    &lt;pre&gt;1     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;   &lt;td&gt;    &lt;pre&gt;docker run -e ES_JAVA_OPTS=&amp;quot;-Xms256m -Xmx256m&amp;quot; -d -p 9201:9201 -p 9301:9301 -v /mnt/elasticsearch/config/slave.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /mnt/elasticsearch/slave:/usr/share/elasticsearch/data --name es-slave elasticsearch:6.7.0     &lt;br /&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;h2&gt;后记&lt;/h2&gt; &lt;p&gt;只有当数据量大了，数据才能玩出花，所以我最近收集的图书信息都不是根据我现有的数据抓取，而是看到一个就全站爬取，这样以后如果我有了电子书文件，直接匹配数据就可以输出了，不需要焦头烂额的找数据了。下一步打算将去除ipfs连接的图书信息在github开源  &lt;code&gt;(我记得好像已经有现成的了，但我就喜欢造轮子！)&lt;/code&gt;。&lt;/p&gt; &lt;p&gt;最近刚刚看完了猫腻的  &lt;code&gt;间客&lt;/code&gt;，里面有一句话出现了很多遍：“社会阶层不平等的根源就是信息的不平等” 我很是赞同。我们没有办法将信息平等到每个人都一样多，但如果有能力获取到更多的信息，为什么不去做呢？我认为每个人都有这个能力，只是因为懒惰，因为怕麻烦，因为觉得很难，因为觉得很费时间所以放弃。看书是一件很费时间和精力的事情  &lt;code&gt;(一定有人会反驳我的，说什么几天看完几百万字的书，不好意思，那些就是电子毒品，看完没有任何营养。)&lt;/code&gt;，认认真真看书是能够将心神代入到书中的人物的，能够体会到作者透过文字传递出来的情感与感悟，也能够学到很多新的知识。这知识不一定是语数英，也许是某道菜的做法，也许是某个很冷门的小技巧，但只要掌握了，就是属于你的独一无二的知识。&lt;/p&gt; &lt;p&gt;可能需要使用Telegram提高了有些人使用这个bot的难度，但是我认为门槛是有必要的，如果你使用这个bot没有找到心仪的书，请不要私聊我让我添加，我不会添加的，我不喜欢一个个手动添加，那样很傻，除非我又找到了一批数据。但…如果有数百G的数据躺在我面前，我还是很馋的。&lt;/p&gt; &lt;p&gt;最后要是有会前端的大佬愿意接盘重构   &lt;a href="http://i-book.in" rel="noopener" target="_blank"&gt;i-book.in&lt;/a&gt;，可以联系我。&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>计算机 软件 Free i-book.in 电子书</category>
      <guid isPermaLink="true">https://itindex.net/detail/60239-%E6%90%9C%E7%B4%A2-%E7%94%B5%E5%AD%90%E4%B9%A6-telegram</guid>
      <pubDate>Sun, 22 Dec 2019 22:33:45 CST</pubDate>
    </item>
    <item>
      <title>如何快速部署容器化应用</title>
      <link>https://itindex.net/detail/60120-%E5%AE%B9%E5%99%A8-%E5%BA%94%E7%94%A8</link>
      <description>&lt;p&gt;摘要：容器化推行的过程中，研发、运维学习及使用成本都非常高，那有没有一款简单易用的平台呢？本文介绍基于Kubernetes的应用管理平台-开普勒云平台。&lt;/p&gt;
 &lt;h2&gt;一、背景&lt;/h2&gt;
 &lt;p&gt;为了快速适应和满足市场需求，小而快的应用越来越多，“这些零碎的应用如何部署、管理？”成为让大家头疼的问题。若全部上虚拟机，资源消耗太大。这时，将应用容器化，显然是一个非常不错的选择，但很多公司又都面临着一个同样的问题，那就是容器化推行难。&lt;/p&gt;
 &lt;p&gt;容器化推行的过程中，研发、运维学习及使用成本都非常高，那有没有一款简单易用的平台呢？&lt;/p&gt;
 &lt;p&gt;开普勒云平台是 宜人金科-财富技术部 开源的一款基于Kubernetes的应用管理解决方案。致力于解决公司的上容器难、上Kubernetes难、运维成本高等问题。应用只需要加一个非常简单的Dockerfile文件通过开普勒云台就能将应用部署在Kubernetes上，大大降低了使用的难度。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846120" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;二、开普勒云平台&lt;/h2&gt;
 &lt;p&gt;之前的一篇文章  &lt;a href="https://segmentfault.com/a/1190000020718505"&gt;Kubernetes+Docker+Istio 容器云实践&lt;/a&gt;对开普勒平台做了一些基本介绍。&lt;/p&gt;
 &lt;p&gt;经过一段时间的调整，我们终于把这个平台开源了:   &lt;a href="https://github.com/kplcloud/kplcloud" rel="nofollow noreferrer"&gt;https://github.com/kplcloud/kplcloud&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;开普勒云平台是一款面向研发、运维等人群的平台，只需要具备简单知识就可以快速将应用部署到Kubernetes上，以下是平台的基础架构：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846121" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;开普勒平台既可以通过容器的方式跑在Kubernetes上，也可以独立部署。&lt;/p&gt;
 &lt;p&gt;在kubernetes master节点上执行即可完成部署，当然，在此之前需要增加app.cfg配置文件。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;$ git clone github.com/kplcloud/kplcloud &amp;amp;&amp;amp; cd kplcloud/
$ kubectl apply -f install/kubernetes/kpaas/&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;下图是开普勒云平台所对接的平台及流程。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846122" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;开普勒云平台通过调用Jenkins、Gitlab(Github)、Kubernetes等API的方式对应用进行操作。&lt;/p&gt;
 &lt;p&gt;将Consul的KV功能作为配置中心来使用，在开普勒云平台上可以直接调用Consul API进行操作，可以在配置文件决定是否启用Consul KV功能。&lt;/p&gt;
 &lt;p&gt;Jenkins目前只担任代码编译及将Docker镜像上传仓库的功能。开普勒通过调用JenkinsAPI来创建Job或Build Job，并监听Job状态。&lt;/p&gt;
 &lt;p&gt;开普勒平台还可调用Github或Gitlab API获取项目的分支及需要上线的tags。并将相关信息传给jenkins，Jenkins拉取代码并执行相关构建过程。&lt;/p&gt;
 &lt;h2&gt;三、使用&lt;/h2&gt;
 &lt;p&gt;平台调用Kubernetes API的资源及Jenkins API或告警都是以模版的方式进行处理，管理员可以根据自己公司所处的环境随意调整相关资源的模版。&lt;/p&gt;
 &lt;p&gt;除了对生产最基本的需求外，还增加了对测试环境测试人员的需求支持。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;应用克隆: 测试人员可能需要做到一个版本多套环境的场景。在平台可以假设一个空间就是一种场景，在一个空间下部署完所有应用之后，需要在其他空间下也生成一样的应用，为了方便操作，可以直接使用“工具集-克隆”功能完成一键克隆。&lt;/li&gt;
  &lt;li&gt;调整容器时间: 金融产品应该都会遇到调整时间的问题。通常测试一个功能需要对服务的时间进行修改，由于Docker使用的是宿主机的内核时间，容器无法对内核时间进行调整，那就需要借助其他工具来完成这项工作。推荐使用一款开源的工具   &lt;a href="https://github.com/wolfcw/libfaketime" rel="nofollow noreferrer"&gt;https://github.com/wolfcw/libfaketime&lt;/a&gt;，我们将该工具编译到宿主机上，通过挂载的方式挂入容器里，就能对单个容器进行调整而不影响其他容器了。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;开普勒云平台功能众多，下面挑几个大家比较关心、常用的功能进行简单介绍。（更多的功能介绍请查看文档  &lt;a href="https://docs.nsini.com" rel="nofollow noreferrer"&gt;https://docs.nsini.com&lt;/a&gt;）&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;创建应用&lt;/li&gt;
  &lt;li&gt;发布新版本&lt;/li&gt;
  &lt;li&gt;日志采集&lt;/li&gt;
  &lt;li&gt;监控告警&lt;/li&gt;
  &lt;li&gt;持久化存储&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;3.1 创建应用&lt;/h3&gt;
 &lt;p&gt;创建一个应用的流程非常简单，只需要填写一些简单的信息，管理员审核之后就会执行构建。应用升级只需要选择tags，然后执行构建就可以完成。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846123" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;以创建一个Go应用为例：&lt;/p&gt;
 &lt;p&gt;Dockerfile:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;FROM golang:latest as build-env

ENV GO111MODULE=on
ENV BUILDPATH=github.com/kplcloud/hello
RUN mkdir -p /go/src/${BUILDPATH}
COPY ./ /go/src/${BUILDPATH}
RUN cd /go/src/${BUILDPATH} &amp;amp;&amp;amp; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install -v

FROM alpine:latest

COPY --from=build-env /go/bin/hello /go/bin/hello

WORKDIR /go/bin/
CMD [&amp;quot;/go/bin/hello&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;将以上Dockerfile放入项目目录，填写相关信息：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846124" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;一个应用就创建完成了，管理员审核提交的信息是否合格，不合格便驳回；合格了就直接通过并进行部署。&lt;/p&gt;
 &lt;p&gt;部署应用会根据用户所提交的信息获取我们事先定义好的基础模版，再根据基础模版生成Kubernetes所能识别的资源，然后调用Kubernetes API创建这些资源。创建完成后再调用Jenkins API创建Job，最后执行构建。&lt;/p&gt;
 &lt;p&gt;Jenkins完成构建，并将Docker Image 上传完仓库之后，开普勒才会更新Kubernetes相关应用的版本。&lt;/p&gt;
 &lt;p&gt;在这个过程中若想加入更多操作，可以修改  &lt;code&gt;JenkinsCommand&lt;/code&gt;模版。&lt;/p&gt;
 &lt;h3&gt;3.2 发布新应用&lt;/h3&gt;
 &lt;p&gt;构建应用的流程是通过创建应用提交一些信息进行处理。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;从git 仓库获取tags列表。&lt;/li&gt;
  &lt;li&gt;调用jenkins API 将应用的相关参数及版本信息传给它并进行构建。&lt;/li&gt;
  &lt;li&gt;Jenkins Job执行Shell命令，执行docker build并上传至Docker Image仓库。&lt;/li&gt;
  &lt;li&gt;平台监听到job已经成功执行，调用kubernetes API更新应用的Image地址。&lt;/li&gt;
  &lt;li&gt;监听升级情况。&lt;/li&gt;
  &lt;li&gt;发送通知。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;以上是构建应用的后端流程，而前端就比较简单了，只需要在应用详情页点击&amp;quot;Build&amp;quot;按钮，在弹出的对话框中选择想应用的tags版本并提交就行了，如下图：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846125" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;点击详情页的build日志选项卡，会显示最近的构建记录，点击左侧相应的版本，可以查看该版本的构建情况，也可以对正在构建的应用进行中断，如下图：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846126" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;3.3 日志采集&lt;/h3&gt;
 &lt;p&gt;我们的日志收集采用的是低耦合、扩展性强、方便维护和升级的方案。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;每个节点Filebeat收集宿主机日志。&lt;/li&gt;
  &lt;li&gt;每个Pod注入Filebeat容器收集业务日志。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;Filebeat会跟应用容器部署在一起，应用也不需要知道它的存在，只需要指定日志输入的目录就可以了。Filebeat所使用的配置是从ConfigMap读取，只需要维护好收集日志的规则。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846127" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如果配置了上面的采集器，那么它会向服务所在的Pod注入一个Filebeat采集器对应用服务的业务日志进行采集。把采集到的日志注入到kafka集群，然后logstash进行消息处理及格式化。&lt;/p&gt;
 &lt;p&gt;处理完后入到ES集群，最终我们就可以通过kibana查询到业务日志了。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846128" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Filebeat容器及filebeat的ConfigMap也可以通过模版的方式进行参数调整。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846129" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;3.4 监控告警&lt;/h3&gt;
 &lt;p&gt;应用监控告警也是非常重要的一个环节，我们采用Prometheus+Grafana的方案进行监控，Prometheus+AlertManager进行告警的处理。&lt;/p&gt;
 &lt;p&gt;AlertManager所抛出的告警信息会发送至开普勒云平台进行处理，若你在平台订阅了告警类型的消息则会发送至所订阅类型的相关工具。&lt;/p&gt;
 &lt;p&gt;我们可以在“个人设置-消息订阅设置”里选择需要订阅的类型及接收的工具：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846131" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;以下是微信接收到的操作通知: &lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846132" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;更多的教程请查阅我们提供的文档。  &lt;a href="https://docs.nsini.com" rel="nofollow noreferrer"&gt;https://docs.nsini.com&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;3.5 持久化存储&lt;/h3&gt;
 &lt;blockquote&gt;Kubernetes集群管理员通过提供不同的存储类，可以满足用户不同的服务质量级别、备份策略和任意策略要求的存储需求。动态存储卷供应使用StorageClass来实现，允许存储卷按需被创建。  &lt;br /&gt;如果没有动态存储供应，Kubernetes集群的管理员将不得不通过手工的方式来创建新的存储卷。  &lt;br /&gt;通过动态存储卷，Kubernetes能够按照用户的需求，自动创建其需要的存储。&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846133" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在菜单找到“配置与存储”-&amp;gt;&amp;quot;持久化存储卷声明&amp;quot;，选择应用的空间，并点击“创建”按钮，先创建一个存储卷，然后我们找到需要挂载持久化存储盘应用并进入详情页，找到“持久化存储”选项卡，挂载刚刚所创建的持久化存储卷就好了。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020846134" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;四、尾巴&lt;/h2&gt;
 &lt;p&gt;开普勒平台目前已开源，并且已有演示平台可使用，提供完整文档供参考。文档详细地介绍了相关服务的搭建过程，同时，提供了多种部署方案。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Github:    &lt;a href="https://github.com/kplcloud/kplcloud" rel="nofollow noreferrer"&gt;https://github.com/kplcloud/kplcloud&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;Document:    &lt;a href="https://docs.nsini.com" rel="nofollow noreferrer"&gt;https://docs.nsini.com&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;Demo:    &lt;a href="https://kplcloud.nsini.com" rel="nofollow noreferrer"&gt;https://kplcloud.nsini.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;作者：王聪  &lt;p&gt;宜信技术学院&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>云计算 kubernetes paas平台 开源软件</category>
      <guid isPermaLink="true">https://itindex.net/detail/60120-%E5%AE%B9%E5%99%A8-%E5%BA%94%E7%94%A8</guid>
      <pubDate>Tue, 29 Oct 2019 14:09:06 CST</pubDate>
    </item>
    <item>
      <title>人工智能会改变电网的工作方式，它会努力让断电不再发生</title>
      <link>https://itindex.net/detail/60060-%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD-%E6%94%B9%E5%8F%98-%E7%94%B5%E7%BD%91</link>
      <description>&lt;p&gt;  &lt;img alt="" height="1300" src="https://s3.ifanr.com/wp-content/uploads/2019/09/photo-1473073899705-e7b1055a7419.jpeg" width="1950"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;为了预测一个复杂而不确定的世界，你不能仅依靠过去的数据和数据科学，你必须将其与社会的专业知识结合起来。&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;这句话是 Cosmo Tech 的 CEO Hugues de Bantel   &lt;a href="https://news-24.fr/a-i-et-les-connaissances-humaines-pourraient-transformer-le-fonctionnement-des-reseaux-electriques/"&gt;说的&lt;/a&gt;。这家法国公司希望利用这项技术在未来能够通过 AI 改变电力生产和分配环节。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1175" src="https://s3.ifanr.com/wp-content/uploads/2019/09/photo-1541358150975-668b4a0531c4.jpeg" width="1567"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲ 图片来自：unsplash&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;这似乎和特斯拉创始人马斯克的想法相似——和 AI 组队，一起去答未来的疑题。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://cosmotech.com/augmented-intelligence/"&gt;Cosmo Tech&lt;/a&gt; 这家公司选择的是创建软件来帮助决策者在最复杂的环境中做出决策，用软件预测决策对其业务的影响，这属于增强智能领域。增强智能的理念是将人类智能和人工智能结合起来。一旦做到了这一点，我们就有能力进行预测，做出假设场景，再进行决策。&lt;/p&gt;
 &lt;p&gt;而这些技术甚至可以应用在  &lt;a href="https://www.newtonx.com/insights/2018/08/21/ai-machine-learning-power-grid/"&gt;电力行业&lt;/a&gt;。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1400" src="https://s3.ifanr.com/wp-content/uploads/2019/09/photo-1516110833967-0b5716ca1387-1.jpeg" width="1867"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;我们都知道，太阳能和风能是可再生的清洁能源，是未来能源的一种，但它们并不能保证提供稳定和持续可预测的能源。他们在城市电网中的存在使能源平衡和优化变得更加复杂。这导致了可再生能源的损失，以及电力供应的故障。&lt;/p&gt;
 &lt;p&gt;2003 年，美国东北地区因清洁能源造成的大规模停电就造成了 5000 万人连续多日的断电。而在今天，欧美地区的私人住宅公寓也在安装太阳能板来为自己供电，但私人住宅用户无法消耗完太阳能板产生的能源，电力公司还需要购买（接收）这些多余的能源，让这些过剩的电量还需要返回电网。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="675" src="https://s3.ifanr.com/wp-content/uploads/2019/08/TESLA.jpg" width="1200"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;个人太阳能板的供大于求是一种情况，还有一种情况则是电力供不应求。当需求超过供应时，电力公司就会启用化石燃料发电厂，即启用「峰值发电厂」，以避免停电。这个过程是昂贵的，无论是在消费者使用成本方面，还是在环境影响方面，我们都该尽力避免此事的发生。&lt;/p&gt;
 &lt;p&gt;这是清洁能源应用在电网中让情况更复杂的一个缩影，这也意味着能够按需提供能源的「智能电网」在未来几年将变得越来越重要。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1088" src="https://s3.ifanr.com/wp-content/uploads/2019/09/China-Clean-Energy-Fund-invests-in-wind-farms-082619_big.jpg.large_2x.jpg" width="1632"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲ 图片来自：Apple&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;为此，英国的国家电网公司为此就在与 Google 旗下的 DeepMind 进行初步谈判，以开发一套系统准确预测需求，更有效地平衡国家能源系统与风能和太阳能的供应。&lt;/p&gt;
 &lt;p&gt;而美国能源部也在与斯坦福大学国家加速器实验室合作，开发人工智能和机器学习算法，以建立一个自主电网，处理来自卫星图像、公用事业运营和其他来源的数据。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="1300" src="https://s3.ifanr.com/wp-content/uploads/2019/09/photo-1529111316-da2e2a1e625d.jpeg" width="975"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;▲ 图片来自：unsplash&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;这依然是一个给 AI 投喂数据，再由 AI 反哺人类的案例。AI 在初始接收了大量电网系统中断的案例，随后他们就能逐渐学会从已定义的系统故障中区分（并精确分类）出正常的操作数据。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://phys.org/news/2019-04-artificial-intelligence-automatically-disturbances-power.html"&gt;训练&lt;/a&gt;后，研究人员就可以将 AI 应用到当前数据中，代替曾经的手动处理方式。这是 AI 首次进入电网的实时应用领域，它能在瞬间发现哪里存在异常或故障，并定义干扰的类型和位置。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="2000" src="https://s3.ifanr.com/wp-content/uploads/2019/09/img_1194.jpg" width="2000"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如果一个发电厂发生故障，那么其他发电厂的负荷可能会突然出现一个峰值。增加的负荷使发电机变慢，频率降低。这需要快速地做出决策，快速指的是 500 毫秒以下。&lt;/p&gt;
 &lt;p&gt;而 AI 就是那个能在 500 毫秒内做出决策的「人」，它能在 20-50 毫秒内做出决策，有足够的时间做出调整，保证电网的正常运营。&lt;/p&gt;
   &lt;div&gt;
      &lt;div&gt;   &lt;a href="https://www.ifanr.com/author/lengsizhen" target="_blank"&gt;&lt;/a&gt;

         &lt;div&gt;
            &lt;div&gt;
               &lt;div&gt;      &lt;strong&gt;       &lt;a href="https://www.ifanr.com/author/lengsizhen" target="_blank"&gt;冷思真&lt;/a&gt;&lt;/strong&gt;
          &lt;/div&gt;
               &lt;div&gt;不太有趣，不太乐观。&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
      &lt;div&gt;
         &lt;div&gt;
                                    &lt;a href="mailto:lengsizhen@ifanr.com" target="_blank"&gt;邮箱&lt;/a&gt;

          
                                      &lt;a href="https://www.ifanr.com/1" target="_blank"&gt;4&lt;/a&gt;

          
                &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
   &lt;p&gt;#欢迎关注爱范儿官方微信公众号：爱范儿（微信号：ifanr），更多精彩内容第一时间为您奉上。&lt;/p&gt; &lt;p&gt;
  &lt;a href="https://www.ifanr.com"&gt;爱范儿&lt;/a&gt; |
  &lt;a href="https://www.ifanr.com/1265808"&gt;原文链接&lt;/a&gt; ·
  &lt;a href="https://www.ifanr.com/1265808#comments"&gt;查看评论&lt;/a&gt; ·
  &lt;a href="https://weibo.com/ifanr"&gt;新浪微博&lt;/a&gt;
&lt;/p&gt;

 &lt;br /&gt;
 &lt;div&gt;
&lt;/div&gt; &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件 AI 人工智能 电网</category>
      <guid isPermaLink="true">https://itindex.net/detail/60060-%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD-%E6%94%B9%E5%8F%98-%E7%94%B5%E7%BD%91</guid>
      <pubDate>Sat, 28 Sep 2019 17:05:50 CST</pubDate>
    </item>
    <item>
      <title>降低软件复杂性的一般原则和方法</title>
      <link>https://itindex.net/detail/60048-%E8%BD%AF%E4%BB%B6-%E5%A4%8D%E6%9D%82%E6%80%A7-%E5%8E%9F%E5%88%99</link>
      <description>&lt;h1&gt;一、前言&lt;/h1&gt;
 &lt;p&gt;斯坦福教授、Tcl语言发明者John Ousterhout 的著作《A Philosophy of Software Design》[1]，自出版以来，好评如潮。按照IT图书出版的惯例，如果冠名为“实践”，书中内容关注的是某项技术的细节和技巧；冠名为“艺术”，内容可能是记录一件优秀作品的设计过程和经验；而冠名为“哲学&amp;quot;，则是一些通用的原则和方法论，这些原则方法论串起来，能够形成一个体系。正如”知行合一”、“世界是由原子构成的”、“我思故我在”，这些耳熟能详的句子能够一定程度上代表背后的人物和思想。用一句话概括《A Philosophy of Software Design》，软件设计的核心在于降低复杂性。&lt;/p&gt;
 &lt;p&gt;本篇文章是围绕着“降低复杂性”这个主题展开的，很多重要的结论来源于John Ousterhout，笔者觉得很有共鸣，就做了一些相关话题的延伸、补充了一些实例。虽说是&amp;quot;一般原则“，也不意味着是绝对的真理，整理出来，只是为了引发大家对软件设计的思考。&lt;/p&gt;
 &lt;h1&gt;二、如何定义复杂性&lt;/h1&gt;
 &lt;p&gt;关于复杂性，尚无统一的定义，从不同的角度可以给出不同的答案。可以用数量来度量，比如芯片集成的电子器件越多越复杂(不一定对)；按层次性[2]度量，复杂度在于层次的递归性和不可分解性。在信息论中，使用熵来度量信息的不确定性。&lt;/p&gt;
 &lt;p&gt;John Ousterhout选择从认知的负担和开发工作量的角度来定义软件的复杂性，并且给出了一个复杂度量公式：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020476519" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;子模块的复杂度cp乘以该模块对应的开发时间权重值tp，累加后得到系统的整体复杂度C。系统整体的复杂度并不简单等于所有子模块复杂度的累加，还要考虑该模块的开发维护所花费的时间在整体中的占比(对应权重值tp）。也就是说，即使某个模块非常复杂，如果很少使用或修改，也不会对系统的整体复杂度造成大的影响。&lt;/p&gt;
 &lt;p&gt;子模块的复杂度cp是一个经验值，它关注几个现象：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;修改扩散，修改时有连锁反应。&lt;/li&gt;
  &lt;li&gt;认知负担，开发人员需要多长时间来理解功能模块。&lt;/li&gt;
  &lt;li&gt;不可知（Unknown Unknowns），开发人员在接到任务时，不知道从哪里入手。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;造成复杂的原因一般是代码依赖和晦涩(Obscurity)。其中，依赖是指某部分代码不能被独立地修改和理解，必定会牵涉到其他代码。代码晦涩，是指从代码中难以找到重要信息。&lt;/p&gt;
 &lt;h1&gt;三、解决复杂性的一般原则&lt;/h1&gt;
 &lt;p&gt;首先，互联网行业的软件系统，很难一开始就做出完美的设计，通过一个个功能模块衍生迭代，系统才会逐步成型；对于现存的系统，也很难通过一个大动作，一劳永逸地解决所有问题。系统设计是需要持续投入的工作，通过细节的积累，最终得到一个完善的系统。因此，好的设计是日拱一卒的结果，在日常工作中要重视设计和细节的改进。&lt;/p&gt;
 &lt;p&gt;其次，专业化分工和代码复用促成了软件生产率的提升。比如硬件工程师、软件工程师（底层、应用、不同编程语言）可以在无需了解对方技术背景的情况下进行合作开发；同一领域服务可以支撑不同的上层应用逻辑等等。其背后的思想，无非是通过将系统分成若干个水平层、明确每一层的角色和分工，来降低单个层次的复杂性。同时，每个层次只要给相邻层提供一致的接口，可以用不同的方法实现，这就为软件重用提供了支持。分层是解决复杂性问题的重要原则。&lt;/p&gt;
 &lt;p&gt;第三，与分层类似，分模块是从垂直方向来分解系统。分模块最常见的应用场景，是如今广泛流行的微服务。分模块降低了单模块的复杂性，但是也会引入新的复杂性，例如模块与模块的交互，后面的章节会讨论这个问题。这里，我们将第三个原则确定为分模块。&lt;/p&gt;
 &lt;p&gt;最后，代码能够描述程序的工作流程和结果，却很难描述开发人员的思路，而注释和文档可以。此外，通过注释和文档，开发人员在不阅读实现代码的情况下，就可以理解程序的功能，注释间接促成了代码抽象。好的注释能够帮助解决软件复杂性问题，尤其是认知负担和不可知问题（Unknown Unknowns）。&lt;/p&gt;
 &lt;h1&gt;四、解决复杂性之日拱一卒&lt;/h1&gt;
 &lt;h2&gt;4.1 拒绝战术编程&lt;/h2&gt;
 &lt;p&gt;战术编程致力于完成任务，新增加特性或者修改Bug时，能解决问题就好。这种工作方式，会逐渐增加系统的复杂性。如果系统复杂到难以维护时，再去重构会花费大量的时间，很可能会影响新功能的迭代。&lt;/p&gt;
 &lt;p&gt;战略编程，是指重视设计并愿意投入时间，短时间内可能会降低工作效率，但是长期看，会增加系统的可维护性和迭代效率。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020476520" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;设计系统时，很难在开始阶段就面面俱到。好的设计应该体现在一个个小的模块上，修改bug时，也应该抱着设计新系统的心态，完工后让人感觉不到“修补”的痕迹。经过累积，最终形成一个完善的系统。从长期看，对于中大型的系统，将日常开发时间的10-15%用于设计是值得的。有一种观点认为，创业公司需要追求业务迭代速度和节省成本，可以容忍糟糕的设计，这是用错误的方法去追求正确的目标。降低开发成本最有效的方式是雇佣优秀的工程师，而不是在设计上做妥协。&lt;/p&gt;
 &lt;h2&gt;4.2 设计两次&lt;/h2&gt;
 &lt;p&gt;为一个类、模块或者系统的设计提供两套或更多方案，有利于我们找到最佳设计。以我们日常的技术方案设计为例，技术方案本质上需要回答两个问题，其一，为什么该方案可行？ 其二，在已有资源限制下，为什么该方案是最优的？为了回答第一个问题，我们需要在技术方案里补充架构图、接口设计和时间人力估算。而要回答第二个问题，需要我们在关键点或争议处提供二到三种方案，并给出建议方案，这样才有说服力。通常情况下，我们会花费很多的时间准备第一个问题，而忽略第二个问题。其实，回答好第二个问题很重要，大型软件的设计已经复杂到没人能够一次就想到最佳方案，一个仅仅“可行”的方案，可能会给系统增加额外的复杂性。对聪明人来说，接受这点更困难，因为他们习惯于“一次搞定问题”。但是聪明人迟早也会碰到自己的瓶颈，在低水平问题上徘徊，不如花费更多时间思考，去解决真正有挑战性的问题。&lt;/p&gt;
 &lt;h1&gt;五、解决复杂性之分层&lt;/h1&gt;
 &lt;h2&gt;5.1 层次和抽象&lt;/h2&gt;
 &lt;p&gt;软件系统由不同的层次组成，层次之间通过接口来交互。在严格分层的系统里，内部的层只对相邻的层次可见，这样就可以将一个复杂问题分解成增量步骤序列。由于每一层最多影响两层，也给维护带来了很大的便利。分层系统最有名的实例是TCP/IP网络模型。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020476521" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在分层系统里，每一层应该具有不同的抽象。TCP/IP模型中，应用层的抽象是用户接口和交互；传输层的抽象是端口和应用之间的数据传输；网络层的抽象是基于IP的寻址和数据传输；链路层的抽象是适配和虚拟硬件设备。如果不同的层具有相同的抽象，可能存在层次边界不清晰的问题。&lt;/p&gt;
 &lt;h2&gt;5.2 复杂性下沉&lt;/h2&gt;
 &lt;p&gt;不应该让用户直面系统的复杂性，即便有额外的工作量，开发人员也应当尽量让用户使用更简单。如果一定要在某个层次处理复杂性，这个层次越低越好。举个例子，Thrift接口调用时，数据传输失败需要引入自动重试机制，重试的策略显然在Thrift内部封装更合适，开放给用户(下游开发人员）会增加额外的使用负担。与之类似的是系统里随处可见的配置参数(通常写在XML文件里），在编程中应当尽量避免这种情况，用户(下游开发人员)一般很难决定哪个参数是最优的，如果一定要开放参数配置，最好给定一个默认值。&lt;/p&gt;
 &lt;p&gt;复杂性下沉，并不是说把所有功能下移到一个层次，过犹不及。如果复杂性跟下层的功能相关，或者下移后，能大大下降其他层次或整体的复杂性，则下移。&lt;/p&gt;
 &lt;h2&gt;5.3 异常处理&lt;/h2&gt;
 &lt;p&gt;异常和错误处理是造成软件复杂的罪魁祸首之一。有些开发人员错误的认为处理和上报的错误越多越好，这会导致过度防御性的编程。如果开发人员捕获了异常并不知道如何处理，直接往上层扔，这就违背了封装原则。&lt;/p&gt;
 &lt;p&gt;降低复杂度的一个原则就是尽可能减少需要处理异常的可能性。而最佳实践就是确保错误终结，例如删除一个并不存在的文件，与其上报文件不存在的异常，不如什么都不做。确保文件不存在就好了，上层逻辑不但不会被影响，还会因为不需要处理额外的异常而变得简单。&lt;/p&gt;
 &lt;h1&gt;六、解决复杂性之分模块&lt;/h1&gt;
 &lt;p&gt;分模块是解决复杂性的重要方法。理想情况下，模块之间应该是相互隔离的，开发人员面对具体的任务，只需要接触和了解整个系统的一小部分，而无需了解或改动其他模块。&lt;/p&gt;
 &lt;h2&gt;6.1 深模块和浅模块&lt;/h2&gt;
 &lt;p&gt;深模块(Deep Module)指的是拥有强大功能和简单接口的模块。深模块是抽象的最佳实践，通过排除模块内部不重要的信息，让用户更容易理解和使用。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000020476522" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Unix操作系统文件I/O是典型的深模块，以Open函数为例，接口接受文件名为参数，返回文件描述符。但是这个接口的背后，是几百行的实现代码，用来处理文件存储、权限控制、并发控制、存储介质等等，这些对用户是不可见的。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;int open(const char* path, int flags, mode_t permissions);
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;与深模块相对的是浅模块(Shallow Module)，功能简单，接口复杂。通常情况下，浅模块无助于解决复杂性。因为他们提供的收益（功能）被学习和使用成本抵消了。以Java I/O为例，从I/O中读取对象时，需要同时创建三个对象FileInputStream、BufferedInputStream、ObjectInputStream，其中前两个创建后不会被直接使用，这就给开发人员造成了额外的负担。默认情况下，开发人员无需感知到BufferedInputStream，缓冲功能有助于改善文件I/O性能，是个很有用的特性，可以合并到文件I/O对象里。假如我们想放弃缓冲功能，文件I/O也可以设计成提供对应的定制选项。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;
FileInputStream fileStream = new FileInputStream(fileName);
BufferedInputStream bufferedStream = new BufferedInputStream(fileStream);
ObjectInputStream objectStream = new ObjectInputStream(bufferedStream);
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;关于浅模块有一些争议，大多数情况是因为浅模块是不得不接受的既定事实，而不见得是因为合理性。当然也有例外，比如领域驱动设计里的防腐层，系统在与外部系统对接时，会单独建立一个服务或模块去适配，用来保证原有系统技术栈的统一和稳定性。&lt;/p&gt;
 &lt;h2&gt;6.2 通用和专用&lt;/h2&gt;
 &lt;p&gt;设计新模块时，应该设计成通用模块还是专用模块？一种观点认为通用模块满足多种场景，在未来遇到预期外的需求时，可以节省时间。另外一种观点则认为，未来的需求很难预测，没必要引入用不到的特性，专用模块可以快速满足当前的需求，等有后续需求时再重构成通用的模块也不迟。&lt;/p&gt;
 &lt;p&gt;以上两种思路都有道理，实际操作的时候可以采用两种方式各自的优点，即在功能实现上满足当前的需求，便于快速实现；接口设计通用化，为未来留下余量。举个例子。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;
void backspace(Cursor cursor);
void delete(Cursor cursor);
void deleteSelection(Selection selection);

//以上三个函数可以合并为一个更通用的函数
void delete(Position start, Position end);
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;设计通用性接口需要权衡，既要满足当前的需求，同时在通用性方面不要过度设计。一些可供参考的标准：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;满足当前需求最简单的接口是什么？在不减少功能的前提下，减少方法的数量，意味着接口的通用性提升了。&lt;/li&gt;
  &lt;li&gt;接口使用的场景有多少？如果接口只有一个特定的场景，可以将多个这样的接口合并成通用接口。&lt;/li&gt;
  &lt;li&gt;满足当前需求情况下，接口的易用性？如果接口很难使用，意味着我们可能过度设计了，需要拆分。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;6.3 信息隐藏&lt;/h2&gt;
 &lt;p&gt;信息隐藏是指，程序的设计思路以及内部逻辑应当包含在模块内部，对其他模块不可见。如果一个模块隐藏了很多信息，说明这个模块在提供很多功能的同时又简化了接口，符合前面提到的深模块理念。软件设计领域有个技巧，定义一个&amp;quot;大&amp;quot;类有助于实现信息隐藏。这里的“大”类指的是，如果要实现某功能，将该功能相关的信息都封装进一个类里面。&lt;/p&gt;
 &lt;p&gt;信息隐藏在降低复杂性方面主要有两个作用：一是简化模块接口，将模块功能以更简单、更抽象的方式表现出来，降低开发人员的认知负担；二是减少模块间的依赖，使得系统迭代更轻量。举个例子，如何从B+树中存取信息是一些数据库索引的核心功能，但是数据库开发人员将这些信息隐藏了起来，同时提供简单的对外交互接口，也就是SQL脚本，使得产品和运营同学也能很快地上手。并且，因为有足够的抽象，数据库可以在保持外部兼容的情况下，将索引切换到散列或其他数据结构。&lt;/p&gt;
 &lt;p&gt;与信息隐藏相对的是信息暴露，表现为：设计决策体现在多个模块，造成不同模块间的依赖。举个例子，两个类能处理同类型的文件。这种情况下，可以合并这两个类，或者提炼出一个新类（参考《重构》[3]一书）。工程师应当尽量减少外部模块需要的信息量。&lt;/p&gt;
 &lt;h2&gt;6.4 拆分和合并&lt;/h2&gt;
 &lt;p&gt;两个功能，应该放在一起还是分开？“不管黑猫白猫”，能降低复杂性就好。这里有一些可以借鉴的设计思路：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;共享信息的模块应当合并，比如两个模块都依赖某个配置项。&lt;/li&gt;
  &lt;li&gt;可以简化接口时合并，这样可以避免客户同时调用多个模块来完成某个功能。&lt;/li&gt;
  &lt;li&gt;可以消除重复时合并，比如抽离重复的代码到一个单独的方法中。&lt;/li&gt;
  &lt;li&gt;通用代码和专用代码分离，如果模块的部分功能可以通用，建议和专用部分分离。举个例子，在实际的系统设计中，我们会将专用模块放在上层，通用模块放在下层以供复用。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h1&gt;七、解决复杂性之注释&lt;/h1&gt;
 &lt;p&gt;注释可以记录开发人员的设计思路和程序功能，降低开发人员的认知负担和解决不可知(Unkown Unkowns)问题，让代码更容易维护。通常情况下，在程序的整个生命周期里，编码只占了少部分，大量时间花在了后续的维护上。有经验的工程师懂得这个道理，通常也会产出更高质量的注释和文档。&lt;/p&gt;
 &lt;p&gt;注释也可以作为系统设计的工具，如果只需要简单的注释就可以描述模块的设计思路和功能，说明这个模块的设计是良好的。另一方面，如果模块很难注释，说明模块没有好的抽象。&lt;/p&gt;
 &lt;h2&gt;7.1 注释的误区&lt;/h2&gt;
 &lt;p&gt;关于注释，很多开发者存在一些认识上的误区，也是造成大家不愿意写注释的原因。比如“好代码是自注释的&amp;quot;、&amp;quot;没有时间“、“现有的注释都没有用，为什么还要浪费时间”等等。这些观点是站不住脚的。“好代码是自注释的”只在某些场景下是合理的，比如为变量和方法选择合适的名称，可以不用单独注释。但是更多的情况，代码很难体现开发人员的设计思路。此外，如果用户只能通过读代码来理解模块的使用，说明代码里没有抽象。好的注释可以极大地提升系统的可维护性，获取长期的效率，不存在“没有时间”一说。注释也是一种可以习得的技能，一旦习得，就可以在后续的工作中应用，这就解决了“注释没有用”的问题。&lt;/p&gt;
 &lt;h2&gt;7.2 使用注释提升系统可维护性&lt;/h2&gt;
 &lt;p&gt;注释应当能提供代码之外额外的信息，重视What和Why，而不是代码是如何实现的(How)，最好不要简单地使用代码中出现过的单词。&lt;/p&gt;
 &lt;p&gt;根据抽象程度，注释可以分为低层注释和高层注释，低层次的注释用来增加精确度，补充完善程序的信息，比如变量的单位、控制条件的边界、值是否允许为空、是否需要释放资源等。高层次注释抛弃细节，只从整体上帮助读者理解代码的功能和结构。这种类型的注释更好维护，如果代码修改不影响整体的功能，注释就无需更新。在实际工作中，需要兼顾细节和抽象。低层注释拆散与对应的实现代码放在一起，高层注释一般用于描述接口。&lt;/p&gt;
 &lt;p&gt;注释先行，注释应该作为设计过程的一部分，写注释最好的时机是在开发的开始环节，这不仅会产生更好的文档，也会帮助产生好的设计，同时减少写文档带来的痛苦。开发人员推迟写注释的理由通常是：代码还在修改中，提前写注释到时候还得再改一遍。这样的话就会衍生两个问题：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;首先，推迟注释通常意味着根本就没有注释。一旦决定推迟，很容易引发连锁反应，等到代码稳定后，也不会有注释这回事。这时候再想添加注释，就得专门抽出时间，客观条件可能不会允许这么做。&lt;/li&gt;
  &lt;li&gt;其次，就算我们足够自律抽出专门时间去写注释，注释的质量也不会很好。我们潜意识中觉得代码已经写完了，急于开展下一个项目，只是象征性地添加一些注释，无法准确复现当时的设计思路。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;避免重复的注释。如果有重复注释，开发人员很难找到所有的注释去更新。解决方法是，可以找到醒目的地方存放注释文档，然后在代码处注明去查阅对应文档的地址。如果程序已经在外部文档中注释过了，不要在程序内部再注释了，添加注释的引用就可以了。&lt;/p&gt;
 &lt;p&gt;注释属于代码，而不是提交记录。一种错误的做法是将功能注释放在提交记录里，而不是放在对应代码文件里。因为开发人员通常不会去代码提交记录里去查看程序的功能描述，很不方便。&lt;/p&gt;
 &lt;h2&gt;7.3 使用注释改善系统设计&lt;/h2&gt;
 &lt;p&gt;良好的设计基础是提供好的抽象，在开始编码前编写注释，可以帮助我们提炼模块的核心要素：模块或对象中最重要的功能和属性。这个过程促进我们去思考，而不是简单地堆砌代码。另一方面，注释也能够帮助我们检查自己的模块设计是否合理，正如前文中提到，深模块提供简单的接口和强大的功能，如果接口注释冗长复杂，通常意味着接口也很复杂；注释简单，意味着接口也很简单。在设计的早期注意和解决这些问题，会为我们带来长期的收益。&lt;/p&gt;
 &lt;h1&gt;八、后记&lt;/h1&gt;
 &lt;p&gt;John Ousterhout累计写过25万行代码，是3个操作系统的重要贡献者，这些原则可以视为作者编程经验的总结。有经验的工程师看到这些观点会有共鸣，一些著作如《代码大全》、《领域驱动设计》也会有类似的观点。本文中提到的原则和方法具有一定实操和指导价值，对于很难有定论的问题，也可以在实践中去探索。&lt;/p&gt;
 &lt;p&gt;关于原则和方法论，既不必刻意拔高，也不要嗤之以鼻。指导实践的不是更多的实践，而是实践后的总结和思考。应用原则和方法论实质是借鉴已有的经验，可以减少我们自行摸索的时间。探索新的方法可以帮助我们适应新的场景，但是新方法本身需要经过时间检验。&lt;/p&gt;
 &lt;h2&gt;九、参考文档&lt;/h2&gt;
 &lt;ul&gt;
  &lt;li&gt;John Ousterhout. A Philosophy of Software Design. Yaknyam Press, 2018.&lt;/li&gt;
  &lt;li&gt;梅拉尼·米歇尔. 复杂. 湖南科学技术出版社, 2016.&lt;/li&gt;
  &lt;li&gt;Martin Fowler. Refactoring: Improving the Design of Existing Code (2nd Edition) . Addison-Wesley Signature Series, 2018.&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;作者介绍&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;政华，顺谱，陶鑫&lt;/strong&gt;，美团打车调度系统工程团队工程师。&lt;/p&gt;
 &lt;h2&gt;招聘信息&lt;/h2&gt;
 &lt;p&gt;美团打车调度系统工程团队诚招高级工程师/技术专家，我们的目标，是与算法、数据团队密切协作，建设高性能、高可用、可配置的打车调度引擎, 为用户提供更好的出行体验。欢迎有兴趣的同学发送简历到tech@meituan.com（邮件标题注明：打车调度系统工程团队）。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件设计 系统</category>
      <guid isPermaLink="true">https://itindex.net/detail/60048-%E8%BD%AF%E4%BB%B6-%E5%A4%8D%E6%9D%82%E6%80%A7-%E5%8E%9F%E5%88%99</guid>
      <pubDate>Tue, 24 Sep 2019 10:36:39 CST</pubDate>
    </item>
    <item>
      <title>Apache CarbonData 1.5.0 发布，华为大数据存储方案</title>
      <link>https://itindex.net/detail/58912-apache-carbondata-%E5%8D%8E%E4%B8%BA</link>
      <description>&lt;p&gt;CarbonData 1.5.0 发布了，该版本更贴近于统一分析。我们希望能够从更多的引擎/库中读取CarbonData文件，以支持各种用例。在这方面，我们增加了支持从C++库读取 CarbonData 文件的支持。此外，可以使用Java SDK、Spark 文件格式接口、Spark、Presto 等读取 CarbonData 文件。&lt;/p&gt; &lt;p&gt;此外 CarbonData 添加了多个优化以减少存储大小，以便可以利用较小的IO进行查询。对来自 CarbonData 的流支持进行了一些改进。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;在该版本中，包含了超过 150 项 JIRA 的条目，包括新特性、改进和 bug 修复。详细的列表请看  &lt;a href="https://cwiki.apache.org/confluence/display/CARBONDATA/Apache+CarbonData+1.5.0+Release" target="_blank"&gt;发行说明&lt;/a&gt;。&lt;/p&gt; &lt;p&gt;Apache® CarbonData™是由华为开源贡献的大数据高效存储格式解决方案。针对当前大数据领域分析场景需求各异而导致的存储冗余问题，CarbonData提供了一种新的融合数据存储方案，以一份数据同时支持“交互式分析、详单查询、任意维度组合的过滤查询等”多种大数据应用场景，并通过丰富的索引技术、字典编码、列存等特性提升了IO扫描和计算性能，实现百亿数据级秒级响应，与大数据生态Apache Hadoop、Apache Spark等无缝集成。&lt;/p&gt; &lt;p&gt;  &lt;img src="https://static.oschina.net/uploads/space/2017/0421/141103_9y97_2903254.png"&gt;&lt;/img&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/58912-apache-carbondata-%E5%8D%8E%E4%B8%BA</guid>
      <pubDate>Thu, 25 Oct 2018 22:42:11 CST</pubDate>
    </item>
    <item>
      <title>开源 IP 地址定位库 ip2region 1.5 发布，升级数据</title>
      <link>https://itindex.net/detail/57933-%E5%BC%80%E6%BA%90-ip-%E5%9C%B0%E5%9D%80</link>
      <description>&lt;p&gt;
	ip2region 是准确率 99.9% 的 IP 地址定位库，0.0x毫秒级查询，数据库文件大小只有 2.7M，提供了 Java、PHP、C、Python、Node.js、Golang 的查询绑定和 Binary、B树、内存三种查询算法，妈妈再也不同担心我的 IP 地址定位！&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;ip2region 1.5 更新如下：&lt;/strong&gt;&lt;/p&gt; &lt;ol&gt;  &lt;li&gt;   &lt;p&gt;数据升级至 2018/01/12 的版本，包括 ip.merge.txt 和 ip2region.db。&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;升级的数据增加了 ipip 的缺失验证，主数据源缺失的数据使用 ipip 补充。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;  &lt;strong&gt;升级提醒：&lt;/strong&gt;因为每次更新都有可能会更改 ip2region.db 的生成配置，请保持使用最新版本的 binding。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;下载地址：&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;码云：  &lt;a href="https://gitee.com/lionsoul/ip2region/tree/v1.5-release" target="_blank"&gt;https://gitee.com/lionsoul/ip2region/tree/v1.5-release&lt;/a&gt;  &lt;br /&gt;github：  &lt;a href="https://github.com/lionsoul2014/ip2region/releases/tag/v1.5-release" target="_blank"&gt;https://github.com/lionsoul2014/ip2region/releases/tag/v1.5-release&lt;/a&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/57933-%E5%BC%80%E6%BA%90-ip-%E5%9C%B0%E5%9D%80</guid>
      <pubDate>Tue, 16 Jan 2018 15:17:35 CST</pubDate>
    </item>
    <item>
      <title>机器学习算法 Java 库 Smile 1.5.0 发布，引入新特性</title>
      <link>https://itindex.net/detail/57706-%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E7%AE%97%E6%B3%95-java</link>
      <description>&lt;p&gt;机器学习算法 Java 库 Smile 1.5.0 已发布。该版本引入了新特性和修复 bug，改进了对 Windows 的支持，具体如下：&lt;/p&gt; &lt;ol&gt;  &lt;li&gt;   &lt;p&gt;DataFrame&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;New Shell for Mac and Linux&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Shell improvement for Windows&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Out of box support of native LAPACK for Windows&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Scala functions to export AttributeDataset, double[][], double[] to ARFF or CSV&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Scala functions for validation measures&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Refactor feature transformation and generation classes&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;NeuralNetwork for regression&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Recursive least squares&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Refactor Scala NLP API&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Bug fixes&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;SmileMiner是一个包含各种现有的机器学习算法的Java库。主要组件包括：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;p&gt;    &lt;strong&gt;mile&lt;/strong&gt; 机器学习的核心库&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;    &lt;strong&gt;SmileMath&lt;/strong&gt; 数学函数、排序、随机数生成器、最优化、线性代数、统计分布、假设检验&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;    &lt;strong&gt;SmileData&lt;/strong&gt; Parsers for arff, libsvm, delimited text, sparse matrix, microarray gene expression data.&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;    &lt;strong&gt;SmileGraph&lt;/strong&gt; 邻接表和矩阵图算法&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;    &lt;strong&gt;SmileInterpolation&lt;/strong&gt; 一维和二维插值&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;    &lt;strong&gt;SmileNLP&lt;/strong&gt; Natural Language Processing.&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;    &lt;strong&gt;SmilePlot&lt;/strong&gt; 基于Swing的可视化库&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;下载地址&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;p&gt;    &lt;a href="https://github.com/haifengl/smile/releases/download/v1.5.0/smile-1.5.0.dmg"&gt;smile-1.5.0.dmg&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;    &lt;a href="https://github.com/haifengl/smile/releases/download/v1.5.0/smile-1.5.0.zip"&gt;smile-1.5.0.zip&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;    &lt;a href="https://github.com/haifengl/smile/archive/v1.5.0.zip"&gt;Source code (zip)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;    &lt;a href="https://github.com/haifengl/smile/archive/v1.5.0.tar.gz"&gt;Source code (tar.gz)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/57706-%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E7%AE%97%E6%B3%95-java</guid>
      <pubDate>Thu, 23 Nov 2017 06:46:31 CST</pubDate>
    </item>
    <item>
      <title>Hyperledger Fabric 1.0，基于区块链的分布式账本</title>
      <link>https://itindex.net/detail/57195-hyperledger-fabric-%E5%8C%BA%E5%9D%97%E9%93%BE</link>
      <description>&lt;p&gt;由 Linux 基金会发起创建的开源区块链分布式账本 —— Hyperledger Fabric，已经迎来了 1.0 版本。该项目着重于性能和可靠性，以及推动区块链和分布式账本技术的跨行业协作。Hyperledger Fabric 可用于全球供应链管理、金融交易、资产账和去中心化的社交网络等场景，但无意以此来构建一种加密货币。Hyperledger Fabric 项目执行总监 Brian Behlendorf 表示，1.0 版本是成员们在一年多的努力后催生的。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;  &lt;a href="https://www.hyperledger.org/" target="_self"&gt;   &lt;img alt="20170712 Hyperledger Fabric Project.jpg" src="http://static.cnbetacdn.com/article/2017/0712/4c2636aea4b6a5d.jpg"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Hyperledger Fabric 成员包括思科、IBM、英特尔、红帽等大型科技企业，以及摩根大通、富国银行、德意志交易所集团等金融机构。&lt;/p&gt; &lt;p&gt;Behlendorf 认为该项目已经足够成熟，做好了在生产环境中部署的准备（解决一些最后的次要问题和改进交易速度）。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;[编译自：  &lt;a href="https://www.neowin.net/news/open-source-distributed-ledger-hyperledger-fabric-reaches-version-10" target="_self"&gt;Neowin&lt;/a&gt;]&lt;/p&gt; &lt;p&gt;译者：  &lt;a href="http://www.cnbeta.com/articles/soft/630869.htm" target="_self"&gt;cnBeta.com&lt;/a&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/57195-hyperledger-fabric-%E5%8C%BA%E5%9D%97%E9%93%BE</guid>
      <pubDate>Wed, 12 Jul 2017 15:13:27 CST</pubDate>
    </item>
    <item>
      <title>Sharding-JDBC 1.5.0.M1 正式发布，全新的 SQL 解析引擎</title>
      <link>https://itindex.net/detail/57024-sharding-jdbc-m1</link>
      <description>&lt;p&gt;经过了长达几个月的紧张开发，Sharding-JDBC 1.5.0.M1终于正式发布。Sharding-JDBC 1.5.0.M1版本是一次里程碑式升级，工作量巨大，Sharding-JDBC截止到1.4.2之前所有的提交次数为385次，而1.5.0.M1一个版本的提交次数为517次。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;Sharding-JDBC从这个版本开始明确定位为“水平扩展以及inline事务数据库中间件”，将全力专注于OLTP以及内联事务的处理。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;本次里程碑版本的主要更新是：  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;1. 全新的SQL解析引擎，去掉了对Druid的依赖。新引擎仅解析分片上下文，对于SQL采用&amp;quot;半理解&amp;quot;理念，进一步提升性能和兼容性，同时降低了代码复杂度。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;2. 提供对MySQL的全方位支持的同时，增加了对Oracle，SQLServer和PostgreSQL的基本支持。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;3. 简化分布式自增序列。将每个表支持多自增序列简化为单表仅支持单一的分布式自增序列。  &lt;br /&gt;  &lt;br /&gt;由于1.5.0版本内容繁多，开发工作量巨大，因此先放出1.5.0.M1版本供大家试用，欢迎多提反馈意见。未来的一段时间，我们会尽快完成1.5.0的其他功能并发布GA版本。后续计划如下：  &lt;br /&gt;  &lt;br /&gt;1.5.0.M2版本：  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;1. ShardingRule简化，每个ShardingRule仅支持单TableRule  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;2. BindingTableRule增强，每个TableRule可以支持多个不同分片策略的BindingTableRule  &lt;br /&gt;  &lt;br /&gt;1.5.0.M3版本：  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;1. 子查询支持  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;2. OR支持  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;3. 包括分页的Oracle和SQLServer全语法支持  &lt;br /&gt;  &lt;br /&gt;1.5.0.M4版本：  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;1. 内置分片策略支持  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;2. 读写分离独立支持&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/57024-sharding-jdbc-m1</guid>
      <pubDate>Thu, 15 Jun 2017 18:53:11 CST</pubDate>
    </item>
    <item>
      <title>百度网盘助手-获取网盘文件的下载地址，破解限速</title>
      <link>https://itindex.net/detail/57003-%E7%99%BE%E5%BA%A6%E7%BD%91%E7%9B%98-%E7%BD%91%E7%9B%98-%E6%96%87%E4%BB%B6</link>
      <description>&lt;blockquote&gt;  &lt;p&gt;本文由   &lt;a href="https://www.91yun.org/archives/author/91yun" target="_blank"&gt;    &lt;strong&gt;@91yun&lt;/strong&gt;&lt;/a&gt;发布&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;众所周知，百度网盘的文件已经对非会员进行了各种限速。不过由于国内其他网盘基本都残废了，百度网盘作为仅存的少数几个，需求还是很大的，经常会碰到别人分享的百度网盘文件夹。 &lt;/p&gt;
 &lt;p&gt; 今天介绍的这种方法就是通过 chrome 的插件   &lt;code&gt; 网盘助手 &lt;/code&gt; 来获得文件的下载地址，然后大家可以自由选择 aria2 ， idm 或者迅雷进行下载。 &lt;/p&gt;
 &lt;p&gt; 这种方法通用性强，无论是在 windows 还是 mac 下都可以这样获得下载地址后用下载工具下载 &lt;/p&gt;
 &lt;h1&gt; 安装 chrome 的百度网盘助手插件 &lt;/h1&gt;
 &lt;h2&gt; 第一步：下载插件 &lt;/h2&gt;
 &lt;p&gt; 由于很早以前百度的干涉，现在这款插件已经在扩展程序商城找不到了，我们要把他源码下下来，然后通过开发者模式加上去。 &lt;/p&gt;
 &lt;p&gt; 插件的 GitHub 地址：   &lt;a href="https://github.com/acgotaku/BaiduExporter"&gt;https://github.com/acgotaku/BaiduExporter&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt; 按照图片所指示的，下载代码的 zip 包 &lt;/p&gt;
 &lt;p&gt;  &lt;img alt="HJzu.png" src="https://i0.wp.com/www.91yun.org/wp-content/uploads/2017/06/1497014800.png?resize=1142%2C633&amp;ssl=1"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt; 第二步：解压 &lt;/h2&gt;
 &lt;p&gt;  &lt;img alt="HiJk.png" src="https://i1.wp.com/www.91yun.org/wp-content/uploads/2017/06/1497014802.png?resize=532%2C199&amp;ssl=1"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt; 第三步：加载扩展程序 &lt;/h2&gt;
 &lt;p&gt;  &lt;img alt="HpB2.png" src="https://i1.wp.com/www.91yun.org/wp-content/uploads/2017/06/1497014803.png?resize=563%2C447&amp;ssl=1"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt; 勾选    &lt;code&gt; 开发者模式 &lt;/code&gt;&lt;/li&gt;
  &lt;li&gt; 选择    &lt;code&gt; 加载已解压的扩展程序 &lt;/code&gt;&lt;/li&gt;
  &lt;li&gt; 选择你刚才解压出来的扩展程序目录 &lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;  &lt;img alt="Hgox.png" src="https://i0.wp.com/www.91yun.org/wp-content/uploads/2017/06/1497014803-1.png?resize=958%2C564&amp;ssl=1"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt; 这样你就可以在 chrome 上看到这个扩展程序的图标了。 &lt;/p&gt;
 &lt;p&gt;  &lt;img alt="HjRC.png" src="https://i0.wp.com/www.91yun.org/wp-content/uploads/2017/06/1497014804.png?resize=283%2C159&amp;ssl=1"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h1&gt; 导出百度网盘的文件下载地址 &lt;/h1&gt;
 &lt;p&gt; 如果安装成功，那么在百度网盘的下载界面，你就会看到“导出下载”的按钮： &lt;/p&gt;
 &lt;p&gt;  &lt;img alt="HnuU.png" src="https://i1.wp.com/www.91yun.org/wp-content/uploads/2017/06/1497014805.png?resize=781%2C502&amp;ssl=1"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt; 选择   &lt;code&gt; 导出下载 &lt;/code&gt; 后就可以看到下载地址了： &lt;/p&gt;
 &lt;p&gt;  &lt;img alt="HDT9.png" src="https://i1.wp.com/www.91yun.org/wp-content/uploads/2017/06/1497014806.png?resize=839%2C528&amp;ssl=1"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt; 这时候我一般会选择   &lt;code&gt; 拷贝下载地址 &lt;/code&gt; ，然后用迅雷下载，当然你看也可以直接用 aria2  或者 idm 或者其他工具下载： &lt;/p&gt;
 &lt;p&gt;  &lt;img alt="HWny.png" src="https://i1.wp.com/www.91yun.org/wp-content/uploads/2017/06/1497014807.png?resize=415%2C341&amp;ssl=1"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://www.91yun.org/archives/12091" rel="nofollow"&gt;百度网盘助手-获取网盘文件的下载地址，破解限速&lt;/a&gt;，首发于  &lt;a href="https://www.91yun.org" rel="nofollow"&gt;91云(91yun.org)&lt;/a&gt;。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>小众软件 开源项目</category>
      <guid isPermaLink="true">https://itindex.net/detail/57003-%E7%99%BE%E5%BA%A6%E7%BD%91%E7%9B%98-%E7%BD%91%E7%9B%98-%E6%96%87%E4%BB%B6</guid>
      <pubDate>Fri, 09 Jun 2017 13:26:36 CST</pubDate>
    </item>
    <item>
      <title>LibRec 2.0.0 正式版发布： 基于机器学习的大数据推荐系统</title>
      <link>https://itindex.net/detail/56681-librec-%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E5%A4%A7%E6%95%B0%E6%8D%AE</link>
      <description>&lt;p&gt;LibRec： 基于机器学习的大数据推荐系统  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;简介：&lt;/p&gt; &lt;p&gt;  &lt;a href="http://www.librec.net/"&gt;LibRec&lt;/a&gt; 是领先的推荐系统Java开源算法工具库，覆盖了70余个各类型推荐算法，有效解决评分预测和物品推荐两大关键的推荐问题。推荐系统是机器学习和大数据技术的经典实际应用，旨在提供高效准确的个性化物品推荐，是现代Web应用的重要组件。&lt;/p&gt; &lt;p&gt;项目结构清晰，代码风格良好，测试充分，注释与手册完善。目前项目使用GPL3.0协议开源在github中，欢迎大家试用。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;Librec:   &lt;a href="http://www.librec.net/"&gt;http://www.librec.net/&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Github Repo:    &lt;a href="https://github.com/guoguibing/librec"&gt;https://github.com/guoguibing/librec&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Doc Link:   &lt;a href="http://wiki.librec.net/doku.php"&gt;http://wiki.librec.net/doku.php&lt;/a&gt;  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;特色功能：&lt;/p&gt; &lt;p&gt;l  丰富的算法集&lt;/p&gt; &lt;p&gt;截止到目前，LibRec已经集成了70余个各类型推荐算法。具体来说，分为基准算法、协同过滤算法、基于内容的算法、情景感知算法、混合算法和其它扩展算法等。在2.0版本中，增加了40余个新算法，包括概率图模型、张量分解模型、因子分解机、基于评论的模型、深度学习模块（RBM）等新颖的算法。团队的每个核心开发人员往往负责某一类型算法的开发和测试工作。&lt;/p&gt; &lt;p&gt;l  良好的模块化&lt;/p&gt; &lt;p&gt;相对于LibRec 1.x，新版本在底层结构上做了非常深入的优化，尤其是模块化方面。新版本的推荐库可分为以下三部分：数据预处理、推荐算法和训练后处理。在数据预处理模块，主要是数据的转换与分割。支持两种格式数据的输入和转换，一个是常见的 User-Item-Rating 格式，另一个是更通用的ARFF格式，用户还可以扩展新类型的数据以增强现有的ARFF格式。在数据分割方面，支持按Ratio，Given-N，k-fold Cross validation, Leave-one-out等方式。在推荐模型模块，包括情景感知和算法集成。情景感知指的是算法依赖的情景信息，如用户相似度；算法集成则是算法的逻辑实现。在模型训练之后，LibRec支持两种操作：一是对测试集进行评估，得到如MAE、RMSE、AUC、MAP、NDCG等测试结果；二是对给定的用户（或情景）进行评分预测或物品推荐等查询操作，用户可以通过实现filter接口自定义更多的过滤操作。&lt;/p&gt; &lt;p&gt;l  灵活的框架配置&lt;/p&gt; &lt;p&gt;LibRec新版本承袭了基于配置的特点，但是有所更新和发展。新的配置实现参考了其它知名数据挖掘工具库的实现特点，在灵活性上得到了有效的提高。具体来说，我们抽取出很多公共的配置项，也为独立的算法保留了特定的配置参数。为了提高算法的易配置性，我们为大多数算法保留了可用的供参考配置设置。&lt;/p&gt; &lt;p&gt;l  高效的执行性能&lt;/p&gt; &lt;p&gt;LibRec一直非常注重算法执行的高效性，并尽可能地优化框架结构和算法实现。与其它的推荐算法库相比，LibRec能够在得到相当的推荐性能的前提下，在更短的时间内执行完成。&lt;/p&gt; &lt;p&gt;l  简单的框架用法&lt;/p&gt; &lt;p&gt;LibRec早期版本只能独立运行，难以集成在其它工程中使用。由于良好的模块结构，新版本既可以单独运行，也能够作为依赖库应用于其它工程中&lt;/p&gt; &lt;p&gt;l  良好的可扩展性&lt;/p&gt; &lt;p&gt;良好的易扩展性。LibRec提供了很好的公共接口以便用户进行个性化扩展。包括数据类型、推荐算法、输出类型、评估因子、过滤器等的扩展接口。使用LibRec开发新算法，用户通常只需要关注新算法的逻辑实现，而不需要担心其它部分的实现。  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;结构示意：  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;   &lt;img alt="" src="https://static.oschina.net/uploads/space/2017/0213/192156_AHKh_2881411.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;流程示意：&lt;/p&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;   &lt;img alt="" src="https://static.oschina.net/uploads/space/2017/0213/192214_TQn0_2881411.jpg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;相关链接：&lt;/p&gt; &lt;p&gt;Librec 2.0 通识篇:    &lt;a href="https://mp.weixin.qq.com/s/AB39ihVWXYHRbeODbGO-2g"&gt;https://mp.weixin.qq.com/s/AB39ihVWXYHRbeODbGO-2g&lt;/a&gt;&lt;/p&gt; &lt;p&gt;导入LibRec至Eclipse平台:   &lt;a href="https://mp.weixin.qq.com/s/OyYn5_4GYAbF0L0SFgsHVQ"&gt;https://mp.weixin.qq.com/s/OyYn5_4GYAbF0L0SFgsHVQ&lt;/a&gt;&lt;/p&gt; &lt;p&gt;LibRec命令行操作:   &lt;a href="https://mp.weixin.qq.com/s/xnkg6BGyUUKmbs009p8XCw"&gt;https://mp.weixin.qq.com/s/xnkg6BGyUUKmbs009p8XCw&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Librec 一周年纪:   &lt;a href="https://mp.weixin.qq.com/s/vDnca1FMW9vVrFDgti_1IA" target="_blank"&gt;https://mp.weixin.qq.com/s/vDnca1FMW9vVrFDgti_1IA&lt;/a&gt;&lt;/p&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;欢迎关注Librec微信公众号：&lt;/p&gt; &lt;p&gt;   &lt;img alt="" src="https://static.oschina.net/uploads/space/2017/0213/192258_17Pr_2881411.jpg"&gt;&lt;/img&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/56681-librec-%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E5%A4%A7%E6%95%B0%E6%8D%AE</guid>
      <pubDate>Mon, 13 Feb 2017 19:23:00 CST</pubDate>
    </item>
    <item>
      <title>Ekho TTS 7.5 发布，支持广东台山话</title>
      <link>https://itindex.net/detail/56633-ekho-tts-%E5%B9%BF%E4%B8%9C%E5%8F%B0</link>
      <description>&lt;p&gt;Ekho（余音）是一个免费、开源的中文语音合成软件。它目前支持粤语、普通话（国语）、广东台山话、诏安客语、藏语、雅言（中国古代通用语）和韩语（试验中），英语则通过 eSpeak 或 Festival 间接实现。Ekho 支持 Linux、Windows 和 Android 平台。&lt;/p&gt; &lt;p&gt;台山被称为中国第一侨乡，海外的台山籍人比台山市常住人口还要多。辛亥革命和民国年间，台山华侨为中国的革命做过很多贡献。&lt;/p&gt; &lt;p&gt;非常感谢 Stephen Li 提供的  &lt;a href="http://www.stephen-li.com/TaishaneseVocabulary/Taishanese.html"&gt;台山话词典&lt;/a&gt;和录音，让 Ekho 可以支持台山话了。&lt;/p&gt; &lt;p&gt;也很感谢 Stan Leong/Leung 在保育乡土文化上做的贡献，促成了这件事情的完成。&lt;/p&gt; &lt;p&gt;  &lt;a href="http://sourceforge.net/projects/e-guidedog/files/Ekho/7.5/ekho-7.5.tar.xz" target="_blank"&gt;Ekho TTS 7.5 （Linux版）下载地址&lt;/a&gt;&lt;/p&gt; &lt;p&gt;  &lt;a href="http://www.eguidedog.net/ekho.php" target="_blank"&gt;Ekho TTS主页&lt;/a&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/56633-ekho-tts-%E5%B9%BF%E4%B8%9C%E5%8F%B0</guid>
      <pubDate>Sun, 05 Feb 2017 12:22:10 CST</pubDate>
    </item>
    <item>
      <title>微服务与架构师</title>
      <link>https://itindex.net/detail/56176-%E5%BE%AE%E6%9C%8D%E5%8A%A1-%E6%9E%B6%E6%9E%84%E5%B8%88</link>
      <description>&lt;p&gt;因为工作的关系，最近面试了很多软件架构师，遗憾的是真正能录用的很少。很多候选人有多年的工作经验，常见的框架也玩得很溜。然而最擅长的是“用既定的技术方案去解决特定的问题”，如果遇到的问题没有严格对应的现成框架，就比较吃力。这样的技能水平或许适合某些行业，但很遗憾不符合我们的要求。&lt;/p&gt;
 &lt;p&gt;软件架构师到底应该做什么，又为什么这么难做好，这都是近来的热门问题，我也一直在和朋友们讨论。正巧，最近我看完了新鲜出炉的《微服务设计》，所以大概可以谈谈自己的看法了。因为这类问题比较抽象，也没有统一答案，我努力尝试把思路整理清楚，把表达变得流畅。最终有没有讲清楚，说的对不对，欢迎大家给我留言。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;今天看来，传统的软件开发（尤其是应用型软件开发）其实是相对简单的。软件运行在基本可靠的单机环境下：CPU提供计算能力，内存提供动态存储，总线提供数据传输，硬盘提供永久存储。这些概念稳定而直观，程序员要完成的，就是调用和组装编程语言提供的各种功能，来满足现实的需求。相比应用程序员良莠不齐的开发水平，无论是操作系统还是硬件环境，都是来自大公司的工业级别的产品，是值得信赖的。&lt;/p&gt;
 &lt;p&gt;如果把程序要完成的功能比作个人，软件运行的环境比作房屋，那么房屋虽小，却是值得信赖的。对个人来说，只要进去了房屋里，就有相对稳定的环境，相比野外生存就是巨大的进步。当然，如果遇到意外情况，在野外可能生存机会大一点，在房屋里只能与房子“一损俱损”了。不过，通常来看这不要紧。&lt;/p&gt;
 &lt;p&gt;随着计算机要解决问题日趋复杂，出现了可复用的类库。它们把重复的功能包装起来，只要直接拿来就可以使用。回到房子的比喻，这些东西就好像标准化制作的家用电器，你搬回去、看懂说明书、用起来，就可以大大提升自己的效率。&lt;/p&gt;
 &lt;p&gt;上面说的是软件内部的进化，软件外部运行模型仍然相对简单——无论要解决什么任务，各种逻辑和资源都是处在同一个运行时（runtime），或者能够方便可靠访问的运行时当中。如果需要提升性能，除去软件本身的优化，就是升级硬件。如果我们需要更快的计算速度，就必须升级CPU；如果我们需要更多的动态存储，就必须升级内存…… 虽然升级需要停机，但是升级之后，性能提高了，运行环境的稳定可靠却不受影响。回到房屋的比喻，在这种思路下，房子还是原来的房子，只是建造得越来越高级，越来越稳定。&lt;/p&gt;
 &lt;p&gt;即便业界提出了N层模型，整体的复杂度提升也有限。这种划分往往并不是严格按照业务责任，还考虑了实现特性，而且层与层之间的接口仍然能依赖外部环境保持稳定可靠。比如常见的三层模型，表现层-业务逻辑层-数据库层，表现层与业务逻辑层之间往往是函数调用，业务层与数据库层之间的通常是通过安全稳定的内网连接，数据库则是配置很好的机器保证高可用性。回到房屋的比喻，这种思路很像花重金建造几栋紧密相连的专用房屋，各自对应不同的用途。如果外界环境变化不大，这种设计确实很稳定，但也很不灵活。&lt;/p&gt;
 &lt;p&gt;随着互联网的飞速发展，程序要解决的问题的复杂度也在飞速，原有的思维和范式，既要考虑业务，又要考虑实现，应对起来已经非常吃力了。所以，SOA（面向服务的架构）的概念应运而生。SOA基本脱离了技术实现的细节，引导开发人员从业务和抽象的“服务”角度来看待系统。与传统复用只考虑静态的代码和类库不同，SOA复用的则是动态的运行着的服务。&lt;/p&gt;
 &lt;p&gt;以上两点，都是SOA相对传统软件开发思想的巨大进步。可惜的是，大多数SOA的学说更倾向于理论和概念的层面，服务的“粒度”究竟定在哪个层级，服务如何落地保证可用性…… 这些问题始终没有取得广泛的共识和规范，对于软件所依赖的环境，SOA也很少涉及，但软件的运行是离不开外部环境的。所以SOA的学说虽然热门，但真正做到了、做好了的例子非常有限。&lt;/p&gt;
 &lt;p&gt;回到房屋的比喻，SOA不太关心每栋房子到底干什么，只是从逻辑上做个大致的区分：这片房子分给商人，那片房子分给农民，另一个片区的房子分给工人…… 但是SOA并不会具体地规定每个区域里应当安排多少房子，这些房子应当如何建造，如何组合，所以区域里很可能有混乱。&lt;/p&gt;
 &lt;p&gt;技术继续发展，尤其是移动互联网的兴起，极大地增加了软件所要解决问题的复杂度。从内部来说，性能的增长已经改变了方向，无论CPU还是内存，性能的增长都不再来源于单纯部件的提高，而更多来自多个普通部件的协同工作。如果说传统的性能提高是从纵向上考虑，现在则是从横向上考虑，承载计算能力的不再是“一颗高运算速度的CPU”，保存动态数据的也不再是“一片大容量内存”。玩法变了，程序的思维和编写范式也需要随之进行调整。&lt;/p&gt;
 &lt;p&gt;从外部来说，性能提升而运行环境仍然稳定的好事不复存在，运行环境日益复杂，可靠性也随之下降，已经没有哪家软件和硬件厂商能为系统提供足够可靠的运行环境。这种外部的挑战很难和以前一样依靠外部供应商来解决：廉价服务节点莫名崩溃很可能是家常便饭，如果网络完全要求节点自身质量过硬以提供高可用性，不但代价高昂，而且违背了网络设计“容忍故障”的初衷；大量程序调用现在通过网络而不是本地进行时进行，几乎无处不在的超时限制会逼迫大家采用异步调用，传输速度和稳定性也会受到极大限制——分布式系统设计中的重大谬误之一就是认为“网络是可靠的”。&lt;/p&gt;
 &lt;p&gt;更糟糕的是，SOA未能解决的粒度问题变得要紧起来。传统的软件系统大致都有规格说明书，在设计时就要考虑每个子系统的承载能力，而且这些能力大致是彼此协调彼此关联的，系统运行时应当保证压力不超过设计规格。但是现在，业务的飞速发展很可能把段时间内就压力集中到单个服务甚至其中的少数功能上，跨服务的功能很可能又需要迅速组合成新的服务，而这种变化是事先根本无法预料的，很容易暴露出服务定义的粒度问题。再者，从整体上考虑，每个服务既要保证自己的稳定，又要相对隔离以限制故障的影响，同时还要适度容忍其它服务的不稳定，最终才能从总体上保证系统的稳定。这，也是对传统开发思维的一大挑战。&lt;/p&gt;
 &lt;p&gt;在这种局面下，“微服务”应运而生了。承接SOA的概念，它把系统按照业务责任划分为彼此独立的多个服务，既保证了概念的清晰和自洽，又保证了系统的灵活性、伸缩性。面对杂乱不可靠的现实，它又从实现上注重每个服务的自治性，也就是能独立部署，具备自动化、可观察、故障隔离、自动恢复等特性，由此提供高可用保障。同时，微服务又抛弃了SOA中的很多概念，比如难以落地的ESB、UDDI等等。&lt;/p&gt;
 &lt;p&gt;在SOA尚且没有完整落地的时候，对它有继承有更新有颠覆的“微服务”，极大增加了开发人员的挑战。首先，服务要拆的足够小，又不至于太小，这样才能保证伸缩性并隔离故障；其次，不能因为服务“小”就降低保障级别，维护一堆“小服务”的保障级别，这是极其麻烦的事情；再次，要做到上面这一切，无论是从理论学说上还是从可依赖的软硬件系统上，都没有现成的低成本的解决方案；最后，因为维护的是动态的“服务”，传统静态的“代码所有权”和“机器所有权”的划分不再有效，它们已经融合为统一的“服务所有权”，它属于开发人员、运维人员以及所有相关人员的共同体，这又会带来团队配合与分工的挑战。&lt;/p&gt;
 &lt;p&gt;回到房屋的比喻，其实这个比喻此时已经完全不合适了。现在的系统更像高度复杂的城市，而不是单独的房屋，所以架构师也不像建筑设计师，而更像城市规划师，他的职责是对城市进行规划，确定每个区域应该做的事情，这些区域应当达到统一的规范要求，又具有随时扩张或缩减的灵活性；同时，他还应当保证这种划分适合对应的专业人员在对应区域工作。&lt;/p&gt;
 &lt;p&gt;明白了这一点，就可以明白版本管理、持续集成、自动化测试、自动化发布、服务治理、详尽监控等等“磨刀工夫”的价值——没有这些工作，就谈不上微服务的质量和保障级别，也就无法驾驭微服务的体系。&lt;/p&gt;
 &lt;p&gt;由此，也很容易明白架构师在这个时代要面对的挑战。一方面，他没有现成的足够强大的集成工具，只能靠一堆“稀松平常”的工具组装出整体可靠的系统；另一方面，他又要深入理解业务，把业务拆散成边界清晰的概念，以高内聚低耦合的服务分而治之，还必须考虑到实现的限制——“高内聚低耦合”的原则人人都知道，如果没有可靠的分布式事务管理机制，就不得不把并非“高内聚”的模块聚合起来，但你又要担心业务边界模糊的风险；RESTful固然优雅，但有时候又不得不使用RPC通讯，所以你又要提防RPC带来的强绑定、客户端服务器端同步更新等很多问题……&lt;/p&gt;
 &lt;p&gt;这一切设计、权衡、决策，并没有成型的理论和学说可以依靠，通常只能完全依赖架构师的经验、理解、思考。所以困难很大，风险也很大，如果做得好，收益也是非凡的。而这，恰恰是架构师的价值所在。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>Yurii谈工作 Yurii谈开发 微服务 架构师 软件架构</category>
      <guid isPermaLink="true">https://itindex.net/detail/56176-%E5%BE%AE%E6%9C%8D%E5%8A%A1-%E6%9E%B6%E6%9E%84%E5%B8%88</guid>
      <pubDate>Fri, 11 Nov 2016 17:47:37 CST</pubDate>
    </item>
    <item>
      <title>Android 7.1.1 正式版降临：续航猛增、支持压感</title>
      <link>https://itindex.net/detail/56289-android-%E9%99%8D%E4%B8%B4</link>
      <description>&lt;p&gt;
      &lt;img src="https://static.oschina.net/uploads/space/2016/1206/084657_ttVz_2720166.jpg"&gt;&lt;/img&gt;
&lt;/p&gt;
 &lt;p&gt;
    今天早些时候，谷歌正式带来Android 7.1.1的更新，目前有些用户已经可以OTA升级了。
&lt;/p&gt;
 &lt;p&gt;
    目前能够抢先升级的机型包含了  &lt;strong&gt;，Pixel、Pixel XL、Nexus 5X、Nexus 9、Nexus 9 LTE以及Nexus Player，而此次更新是全球同步的。&lt;/strong&gt;
&lt;/p&gt;
 &lt;p&gt;
    对于Pixel和Pixel XL两款机型来说，它们开卖的时候直接预装的就是Android 7.1，现在的Android 7.1.1对于两者来说，是一个重要的安全补丁。
&lt;/p&gt;
 &lt;p&gt;
    Android 7.1/7.1.1除了修复不少Bug外，谷歌还重新对系统进行了优化，以便最大的程度的增加手机续航，同时Android 7.1.1新系统包含最初在Pixel上推出的出色的应用程序快捷方式功能，比如长按某个应用程序的图标，会激活功能快捷方式的子菜单。  &lt;strong&gt;用户可以使用这些快捷方式快速向特定联系人发送消息或导航到已保存的位置。该功能与iPhone的3D触摸 “用力按压”快捷方式非常相似。&lt;/strong&gt;
&lt;/p&gt;
 &lt;p&gt;
    Android 7.1.1新系统包括谷歌最新的一组更多样化的emoji表情符号，更彰显女性职业多样性。此外，新系统还加入图像键盘的支持，使用户无需退出正在运行的即时通讯应用程，就可以轻松地查找和发送图片以及GIF，包括Google环聊（Hangout），Allo和默认的短信应用。
&lt;/p&gt;
 &lt;p&gt;
    像往常一样，Android新系统不会一夜之间普及所有手机。 谷歌表示，“用户在接下来的几周内会渐渐获得系统更新”。迫不及待的用户可以通过Android Beta预览体验计划注册手机设备，从而更快地更新系统。
&lt;/p&gt;
 &lt;p&gt;
    每个设备类别的版本号都不一样：  &lt;br /&gt;
&lt;/p&gt;
 &lt;ul&gt;
      &lt;li&gt;
           &lt;p&gt;
            大多数 Nexus 设备是 NMF26F
        &lt;/p&gt;
    &lt;/li&gt;
      &lt;li&gt;
           &lt;p&gt;
            Nexus Player 的版本号是 NMF26J
        &lt;/p&gt;
    &lt;/li&gt;
      &lt;li&gt;
           &lt;p&gt;
            Pixel C 的版本号是 NMF26H
        &lt;/p&gt;
    &lt;/li&gt;
      &lt;li&gt;
           &lt;p&gt;
            Pixel 系列手机的版本号是 NMF26O
        &lt;/p&gt;
    &lt;/li&gt;
&lt;/ul&gt;
 &lt;ul&gt;&lt;/ul&gt;
 &lt;ul&gt;&lt;/ul&gt;
 &lt;p&gt;
    部分内容来自：  &lt;a href="http://news.mydrivers.com/1/510/510629.htm" target="_blank"&gt;快科技&lt;/a&gt;
&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/56289-android-%E9%99%8D%E4%B8%B4</guid>
      <pubDate>Tue, 06 Dec 2016 08:49:00 CST</pubDate>
    </item>
    <item>
      <title>谷歌工程师：杀毒软件根本没什么用</title>
      <link>https://itindex.net/detail/56231-%E8%B0%B7%E6%AD%8C-%E5%B7%A5%E7%A8%8B%E5%B8%88-%E6%9D%80%E6%AF%92%E8%BD%AF%E4%BB%B6</link>
      <description>&lt;p&gt;  &lt;strong&gt;如果说你还认为杀毒软件对每个电脑用户都是必不可少的，谷歌的高级安全工程师Darren Bilby可能会给你一个不一样的答案。&lt;/strong&gt;&lt;/p&gt;
 &lt;h2&gt;“不要在没用的东西上投资”&lt;/h2&gt;
 &lt;p&gt;Bilby作为企业基础设施保护团队中保障平台完整（Platform Integrity）组的负责人，在近期新西兰的Kiwicon黑客大会上明确表达了自己的观点：  &lt;strong&gt;杀毒软件其实没什么用，安全行业应该把工作的重心放在其他真正有用的方面，像是白名单这一类的应用。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;   &lt;img alt="darren_bilby_765.jpg" height="348" src="http://image.3001.net/images/20161118/14794516516648.jpg!small" width="648"&gt;&lt;/img&gt;   &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;Bilby不仅是谷歌悉尼办公室应急事件响应人，还负责包括2009年极光行动（Operation Aurora）在内等最高级入侵事件的研究。他在这次大会上谴责了多个目前市面上使用的工具，认为工程师被迫安装这些规定的杀毒软件反而会牺牲真正的安全。极光行动是2009年12月可能源自中国的一场网络攻击，其名“Aurora”来自攻击者电脑上恶意文件所在路径的一部分。遭受攻击的除Google外，还有Adobe System、雅虎、赛门铁克等20多家公司。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;“拜托再别变什么把戏了，”Bilby称，“我们应该停止再在这些已经证明没用的东西上投资了。”他认为这些杀毒软件只是看起来神奇的魔术，实际上并没有什么真正作用。而且绝大多数人安装杀毒软件都是因为他们觉得应该要装，而不是真觉得装了之后多有用。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;“杀毒软件也不是一点用都没有，但那点作用更像是将一只金丝雀养在煤窑里，指望它的存在能净化煤窑产生的有毒气体，而我们就站在死去的金丝雀尸体旁说：‘感谢上帝你把毒气都吸走了’。”&lt;/p&gt;
 &lt;p&gt;Bilby希望安全专家和黑客们能花更多时间在更有意义的事情上，像是白名单、硬件安全密钥、动态访问权限等。就像谷歌的BeyondCorp模型。BeyondCorp模型是谷歌内部使用的安全策略，就是不要相信任何网络，无论何时何地。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="google-engineer-says-antivirus-apps-are-ineffective-magic-don-t-genuinely-help-510287-2.jpg" height="431" src="http://image.3001.net/images/20161118/14794516878761.jpg!small" width="690"&gt;&lt;/img&gt;    &lt;/p&gt;
 &lt;h2&gt;“停止向用户推卸责任”&lt;/h2&gt;
 &lt;p&gt;Bilby认为网络很难做到安全防御，因为用户很容易就可以绕过传统的防御方式，通过移动网络将数据上传到云上。&lt;/p&gt;
 &lt;p&gt;所以安全使用互联网这种建议听起来就很“恐怖”，  &lt;strong&gt;像是告诉用户不要点击钓鱼链接、下载奇怪的可执行文件，其实这都是逃避责任&lt;/strong&gt;，最根本的原因还是那些硬件和软件制造商从一开始就没做出来能让用户安全上网的工具。如何改善这种现状才是安全专家在未来最应该关注的事情，比如将IDS做得更好，即使用户访问了恶意网站或打开被感染的文件，系统可以始终保障用户安全。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;这种推卸责任听起来就是：“我们给用户提供了不能安全上网的设备，但出了安全问题都是用户的错。”&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;Bilby还说道Adobe Flash光是去年一年就爆出了314个远程代码执行漏洞，嘲讽他们的后院基本上每隔一周就要失火一次。&lt;/p&gt;
 &lt;p&gt;虽说杀毒软件是否真像Bilby说得那样如此不堪还有待商榷，但Bilby提到的现状也是不争的事实。真正实现用户的网络安全，各安全公司都还有很长的路要走。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;* 参考来源：   &lt;a href="http://www.theregister.co.uk/2016/11/17/google_hacker_pleads_try_whitelists_not_just_bunk_antivirus_ids" target="_blank"&gt;theregister&lt;/a&gt;，   &lt;a href="http://news.softpedia.com/news/kaspersky-accuses-microsoft-of-playing-dirty-with-antivirus-apps-in-windows-10-510160.shtml"&gt;softpedia&lt;/a&gt;，FB小编孙毛毛编译，转载请注明来自   &lt;a href="http://www.freebuf.com/"&gt;FreeBuf.COM&lt;/a&gt;     &lt;/strong&gt;    &lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>资讯 google 杀毒软件</category>
      <guid isPermaLink="true">https://itindex.net/detail/56231-%E8%B0%B7%E6%AD%8C-%E5%B7%A5%E7%A8%8B%E5%B8%88-%E6%9D%80%E6%AF%92%E8%BD%AF%E4%BB%B6</guid>
      <pubDate>Sun, 20 Nov 2016 15:54:41 CST</pubDate>
    </item>
    <item>
      <title>FreeFileSync 8.7 发布，文件夹比较和同步工具</title>
      <link>https://itindex.net/detail/56462-freefilesync-%E6%96%87%E4%BB%B6%E5%A4%B9-%E5%90%8C%E6%AD%A5</link>
      <description>&lt;p&gt;FreeFileSync 8.7 发布，FreeFileSync是开放源代码的一个文件夹比较和同步工具，界面简洁，只需简单的设置就可以实现文件夹的比较和同步操作！&lt;/p&gt; &lt;p&gt;  &lt;img src="https://static.oschina.net/uploads/img/201612/29004552_FJqa.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;该版本改进内容包括：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;p&gt;New auto-updater feature for FreeFileSync Donation Edition&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Download zip archive of portable FreeFileSync Donation Edition&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;New command line options to define parameters for silent installation&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Support offline activation for portable Donation Edition&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Use automatic keyboard-interactive SFTP authentication as fallback&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Check for available SFTP authentication methods before login&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Support cloud sync of portable edition installation files&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Access donation transaction details from about dialog&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Use width from flexible grid column when showing/hiding extra columns&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Show item short names in middle column tooltip&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Enhanced file category descriptions with modification times&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Don&amp;apos;t warn about missing recycle bin when only moving or updating attributes&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Fixed crash when switching to main dialog during batch sync&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;下载地址：&lt;/p&gt; &lt;p&gt;  &lt;a href="http://www.freefilesync.org/download/FreeFileSync_8.7_Windows_Setup.exe" rel="nofollow"&gt;Download FreeFileSync 8.7 Windows Setup&lt;/a&gt;  &lt;br /&gt;  &lt;a href="http://www.freefilesync.org/download/FreeFileSync_8.7_macOS.zip" rel="nofollow"&gt;Download FreeFileSync 8.7 macOS&lt;/a&gt;  &lt;br /&gt;  &lt;a href="http://www.freefilesync.org/download/FreeFileSync_8.7_Ubuntu_16.10_64-bit.tar.gz" rel="nofollow"&gt;Download FreeFileSync 8.7 Ubuntu 16.10 64-bit&lt;/a&gt;  &lt;br /&gt;  &lt;a href="http://www.freefilesync.org/download/FreeFileSync_8.7_Ubuntu_16.04_64-bit.tar.gz" rel="nofollow"&gt;Download FreeFileSync 8.7 Ubuntu 16.04 64-bit&lt;/a&gt;  &lt;br /&gt;  &lt;a href="http://www.freefilesync.org/download/FreeFileSync_8.7_Debian_8.6_64-bit.tar.gz" rel="nofollow"&gt;Download FreeFileSync 8.7 Debian 8.6 64-bit&lt;/a&gt;  &lt;br /&gt;  &lt;a href="http://www.freefilesync.org/download/FreeFileSync_8.7_openSUSE_64-bit.tar.gz" rel="nofollow"&gt;Download FreeFileSync 8.7 openSUSE 64-bit&lt;/a&gt;  &lt;br /&gt;  &lt;a href="http://www.freefilesync.org/download/FreeFileSync_8.7_Source.zip" rel="nofollow"&gt;Download FreeFileSync 8.7 Source&lt;/a&gt;  &lt;br /&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/56462-freefilesync-%E6%96%87%E4%BB%B6%E5%A4%B9-%E5%90%8C%E6%AD%A5</guid>
      <pubDate>Thu, 29 Dec 2016 00:45:51 CST</pubDate>
    </item>
    <item>
      <title>sharding-jdbc 1.4.1 发布，当当 JDBC 增强驱动</title>
      <link>https://itindex.net/detail/56446-sharding-jdbc-%E5%BD%93%E5%BD%93</link>
      <description>&lt;p&gt;sharding-jdbc 1.4.1 发布了。&lt;/p&gt; &lt;p&gt;Sharding-JDBC是一个轻量级的关系型数据库中间件，提供分库分表、读写分离和柔性事务等功能。它直接封装JDBC协议，可以理解为增强版的JDBC驱动，旧代码迁移成本几乎为零。它使用客户端直连数据库，以jar包形式提供服务，无proxy代理层，无需额外部署，无其他依赖，DBA也无需改变原有的运维方式。&lt;/p&gt; &lt;p&gt;该版本暂未提供更新内容。&lt;/p&gt; &lt;p&gt;下载地址：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;p&gt;    &lt;a href="https://github.com/dangdangdotcom/sharding-jdbc/archive/1.4.1.zip" rel="nofollow"&gt;Source code (zip)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;    &lt;a href="https://github.com/dangdangdotcom/sharding-jdbc/archive/1.4.1.zip" rel="nofollow"&gt;&lt;/a&gt;&lt;/p&gt;   &lt;p&gt;    &lt;a href="https://github.com/dangdangdotcom/sharding-jdbc/archive/1.4.1.tar.gz" rel="nofollow"&gt;Source code (tar.gz)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/56446-sharding-jdbc-%E5%BD%93%E5%BD%93</guid>
      <pubDate>Mon, 26 Dec 2016 17:20:02 CST</pubDate>
    </item>
    <item>
      <title>NutzWk 4.0.5 发布，Java 企业级开源开发框架</title>
      <link>https://itindex.net/detail/56798-nutzwk-java-%E4%BC%81%E4%B8%9A</link>
      <description>&lt;p&gt;NutzWk 基于Nutz的开源企业级开发框架 &lt;/p&gt; &lt;h3&gt;前言&lt;/h3&gt; &lt;p&gt;本项目源于2010年，那时老东家还在使用Jsp和Struts1，需要手动创建并释放连接池、需要配置XML请求路径和类映射关系、要支持刚刚兴起的JSON非常痛苦等等的原因，开始选择适用“快速开发、功能丰富、扩展性强、性能优越”等技术要求的框架产品，讨厌Spring的繁杂配置、Hibernate及Mybatis的繁琐，讨厌一切让开发变得低效和繁杂的技术，这和Nutz的设计理念不谋而合。  &lt;br /&gt;  &lt;br /&gt;使用本框架开发商用项目始于2012年，先是基于NutzWk v1.0开发了CMS网站群管理系统、网络问政系统，而后分别用于交通厅网站群项目、12345市长热线项目、财政厅数据上报、羽毛球场地管理、新媒体指数、Police大数据分析、Police视频监控、各类微信公众号等项目中，经过几年的积累，使用NutzWk v1.0及 v3.x开发并商用的项目少则几十多则上百。因为她是开源的，不光老东家和现所在公司在用，广大网友也在用哦。&lt;/p&gt; &lt;h3&gt;在线演示地址  &lt;br /&gt;&lt;/h3&gt; &lt;p&gt;  &lt;a href="https://nutzwk.wizzer.cn/" target="_blank"&gt;https://nutzwk.wizzer.cn/&lt;/a&gt;&lt;/p&gt; &lt;h3&gt;v4.0.5 更新内容&lt;/h3&gt; &lt;p&gt;1、update: 开发指南增加功能扩展章节；  &lt;br /&gt;2、update: 几个工具类增加@IocBean便于容器管理；  &lt;br /&gt;3、update: Quartz改为集群模式,首次启动项目执行初始化sql；  &lt;br /&gt;4、update: 去掉上传微信多媒体文件的编译警告 &amp;amp; 多语言切换判断url；  &lt;br /&gt;5、add: python build.py脚本,可生成独立运行的jar文件；&lt;/p&gt; &lt;h3&gt;项目地址&lt;/h3&gt; &lt;p&gt;码云：  &lt;a href="https://git.oschina.net/wizzer/NutzWk" target="_blank"&gt;https://git.oschina.net/wizzer/NutzWk&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Github：  &lt;a href="https://github.com/Wizzercn/NutzWk" target="_blank"&gt;https://github.com/Wizzercn/NutzWk&lt;/a&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/56798-nutzwk-java-%E4%BC%81%E4%B8%9A</guid>
      <pubDate>Wed, 22 Mar 2017 14:14:54 CST</pubDate>
    </item>
  </channel>
</rss>

