Blog Post 写作指南

Blog Post 写作指南

本指南总结了技术博客文章的写作规范和最佳实践,确保文章质量一致且易于维护。


一、文件结构与命名

1.1 文件命名规范

_posts/YYYY-MM-DD-主题关键词.md

示例:

规则:

1.2 Front Matter 格式

---
title: "文章标题"
---

<style>
/* Mermaid diagram container */
.mermaid-container {
  position: relative;
  display: block;
  cursor: pointer;
  transition: opacity 0.2s;
  max-width: 100%;
  margin: 20px 0;
  overflow-x: auto;
}

.mermaid-container:hover {
  opacity: 0.8;
}

.mermaid-container svg {
  max-width: 100%;
  height: auto;
  display: block;
}

/* Modal overlay */
.mermaid-modal {
  display: none;
  position: fixed;
  z-index: 9999;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.9);
  animation: fadeIn 0.3s;
}

.mermaid-modal.active {
  display: flex;
  align-items: center;
  justify-content: center;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Modal content */
.mermaid-modal-content {
  position: relative;
  width: 90vw;
  height: 90vh;
  overflow: hidden;
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
}

.mermaid-modal-diagram {
  transform-origin: center center;
  transition: transform 0.2s ease;
  display: inline-block;
  min-width: 100%;
  cursor: grab;
  user-select: none;
}

.mermaid-modal-diagram.dragging {
  cursor: grabbing;
  transition: none;
}

.mermaid-modal-diagram svg {
  width: 100%;
  height: auto;
  display: block;
  pointer-events: none;
}

/* Control buttons */
.mermaid-controls {
  position: absolute;
  top: 10px;
  right: 10px;
  display: flex;
  gap: 8px;
  z-index: 10000;
}

.mermaid-btn {
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid #ddd;
  border-radius: 4px;
  padding: 8px 12px;
  cursor: pointer;
  font-size: 14px;
  transition: background 0.2s;
  color: #333;
  font-weight: 500;
}

.mermaid-btn:hover {
  background: white;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* Close button */
.mermaid-close {
  background: #f44336;
  color: white;
  border: none;
}

.mermaid-close:hover {
  background: #d32f2f;
}

/* Zoom indicator */
.mermaid-zoom-level {
  position: absolute;
  bottom: 20px;
  left: 20px;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 6px 12px;
  border-radius: 4px;
  font-size: 14px;
  z-index: 10000;
}
</style>

<script type="module">
  import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';

  mermaid.initialize({
    startOnLoad: false,
    theme: 'default',
    securityLevel: 'loose',
    htmlLabels: true,
    themeVariables: {
      fontSize: '14px'
    }
  });

  let currentZoom = 1;
  let currentModal = null;
  let isDragging = false;
  let startX = 0;
  let startY = 0;
  let translateX = 0;
  let translateY = 0;

  // Create modal HTML
  function createModal() {
    const modal = document.createElement('div');
    modal.className = 'mermaid-modal';
    modal.innerHTML = `
      <div class="mermaid-controls">
        <button class="mermaid-btn zoom-in">放大 +</button>
        <button class="mermaid-btn zoom-out">缩小 -</button>
        <button class="mermaid-btn zoom-reset">重置</button>
        <button class="mermaid-btn mermaid-close">关闭 ✕</button>
      </div>
      <div class="mermaid-modal-content">
        <div class="mermaid-modal-diagram"></div>
      </div>
      <div class="mermaid-zoom-level">100%</div>
    `;
    document.body.appendChild(modal);
    return modal;
  }

  // Show modal with diagram
  function showModal(diagramContent) {
    if (!currentModal) {
      currentModal = createModal();
      setupModalEvents();
    }

    const modalDiagram = currentModal.querySelector('.mermaid-modal-diagram');
    modalDiagram.innerHTML = diagramContent;

    // Remove any width/height attributes from SVG to make it responsive
    const svg = modalDiagram.querySelector('svg');
    if (svg) {
      svg.removeAttribute('width');
      svg.removeAttribute('height');
      svg.style.width = '100%';
      svg.style.height = 'auto';
    }

    // Setup drag functionality
    setupDrag(modalDiagram);

    currentModal.classList.add('active');
    currentZoom = 1;
    resetPosition();
    updateZoom();
    document.body.style.overflow = 'hidden';
  }

  // Hide modal
  function hideModal() {
    if (currentModal) {
      currentModal.classList.remove('active');
      document.body.style.overflow = '';
    }
  }

  // Update zoom level
  function updateZoom() {
    if (!currentModal) return;
    const diagram = currentModal.querySelector('.mermaid-modal-diagram');
    const zoomLevel = currentModal.querySelector('.mermaid-zoom-level');
    diagram.style.transform = `translate(${translateX}px, ${translateY}px) scale(${currentZoom})`;
    zoomLevel.textContent = `${Math.round(currentZoom * 100)}%`;
  }

  // Reset position when zoom changes
  function resetPosition() {
    translateX = 0;
    translateY = 0;
  }

  // Setup drag functionality
  function setupDrag(element) {
    element.addEventListener('mousedown', startDrag);
    element.addEventListener('touchstart', startDrag);
  }

  function startDrag(e) {
    if (e.type === 'mousedown' && e.button !== 0) return; // Only left click

    isDragging = true;
    const modalDiagram = currentModal.querySelector('.mermaid-modal-diagram');
    modalDiagram.classList.add('dragging');

    if (e.type === 'touchstart') {
      startX = e.touches[0].clientX - translateX;
      startY = e.touches[0].clientY - translateY;
    } else {
      startX = e.clientX - translateX;
      startY = e.clientY - translateY;
    }

    document.addEventListener('mousemove', drag);
    document.addEventListener('touchmove', drag);
    document.addEventListener('mouseup', stopDrag);
    document.addEventListener('touchend', stopDrag);
  }

  function drag(e) {
    if (!isDragging) return;
    e.preventDefault();

    if (e.type === 'touchmove') {
      translateX = e.touches[0].clientX - startX;
      translateY = e.touches[0].clientY - startY;
    } else {
      translateX = e.clientX - startX;
      translateY = e.clientY - startY;
    }

    updateZoom();
  }

  function stopDrag() {
    isDragging = false;
    const modalDiagram = currentModal?.querySelector('.mermaid-modal-diagram');
    if (modalDiagram) {
      modalDiagram.classList.remove('dragging');
    }
    document.removeEventListener('mousemove', drag);
    document.removeEventListener('touchmove', drag);
    document.removeEventListener('mouseup', stopDrag);
    document.removeEventListener('touchend', stopDrag);
  }

  // Setup modal event listeners
  function setupModalEvents() {
    if (!currentModal) return;

    // Close button
    currentModal.querySelector('.mermaid-close').addEventListener('click', hideModal);

    // Zoom buttons
    currentModal.querySelector('.zoom-in').addEventListener('click', () => {
      currentZoom = Math.min(currentZoom + 0.25, 3);
      updateZoom();
    });

    currentModal.querySelector('.zoom-out').addEventListener('click', () => {
      currentZoom = Math.max(currentZoom - 0.25, 0.5);
      updateZoom();
    });

    currentModal.querySelector('.zoom-reset').addEventListener('click', () => {
      currentZoom = 1;
      resetPosition();
      updateZoom();
    });

    // Close on background click
    currentModal.addEventListener('click', (e) => {
      if (e.target === currentModal) {
        hideModal();
      }
    });

    // Close on ESC key
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape' && currentModal.classList.contains('active')) {
        hideModal();
      }
    });
  }

  // Convert Jekyll-rendered code blocks to mermaid divs
  document.addEventListener('DOMContentLoaded', async function() {
    const codeBlocks = document.querySelectorAll('code.language-mermaid');

    for (const codeBlock of codeBlocks) {
      const pre = codeBlock.parentElement;
      const container = document.createElement('div');
      container.className = 'mermaid-container';

      const mermaidDiv = document.createElement('div');
      mermaidDiv.className = 'mermaid';
      mermaidDiv.textContent = codeBlock.textContent;

      container.appendChild(mermaidDiv);
      pre.replaceWith(container);
    }

    // Render all mermaid diagrams
    try {
      await mermaid.run({
        querySelector: '.mermaid'
      });
      console.log('Mermaid diagrams rendered successfully');
    } catch (error) {
      console.error('Mermaid rendering error:', error);
    }

    // Add click handlers to rendered diagrams
    document.querySelectorAll('.mermaid-container').forEach((container, index) => {
      // Find the rendered SVG inside the container
      const svg = container.querySelector('svg');
      if (!svg) {
        console.warn(`No SVG found in container ${index}`);
        return;
      }

      // Make the container clickable
      container.style.cursor = 'pointer';
      container.title = '点击查看大图';

      container.addEventListener('click', function(e) {
        e.preventDefault();
        e.stopPropagation();

        // Clone the SVG for the modal
        const svgClone = svg.cloneNode(true);
        const tempDiv = document.createElement('div');
        tempDiv.appendChild(svgClone);

        console.log('Opening modal for diagram', index);
        showModal(tempDiv.innerHTML);
      });

      console.log(`Click handler added to diagram ${index}`);
    });
  });
</script>

注意事项:

.mermaid-container:hover { opacity: 0.8; }

.mermaid-container svg { max-width: 100%; height: auto; display: block; }

/* Modal overlay */ .mermaid-modal { display: none; position: fixed; z-index: 9999; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.9); animation: fadeIn 0.3s; }

.mermaid-modal.active { display: flex; align-items: center; justify-content: center; }

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

/* Modal content */ .mermaid-modal-content { position: relative; width: 90vw; height: 90vh; overflow: hidden; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); display: flex; align-items: center; justify-content: center; }

.mermaid-modal-diagram { transform-origin: center center; transition: transform 0.2s ease; display: inline-block; min-width: 100%; cursor: grab; user-select: none; }

.mermaid-modal-diagram.dragging { cursor: grabbing; transition: none; }

.mermaid-modal-diagram svg { width: 100%; height: auto; display: block; pointer-events: none; }

/* Control buttons */ .mermaid-controls { position: absolute; top: 10px; right: 10px; display: flex; gap: 8px; z-index: 10000; }

.mermaid-btn { background: rgba(255, 255, 255, 0.9); border: 1px solid #ddd; border-radius: 4px; padding: 8px 12px; cursor: pointer; font-size: 14px; transition: background 0.2s; color: #333; font-weight: 500; }

.mermaid-btn:hover { background: white; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); }

/* Close button */ .mermaid-close { background: #f44336; color: white; border: none; }

.mermaid-close:hover { background: #d32f2f; }

/* Zoom indicator */ .mermaid-zoom-level { position: absolute; bottom: 20px; left: 20px; background: rgba(0, 0, 0, 0.7); color: white; padding: 6px 12px; border-radius: 4px; font-size: 14px; z-index: 10000; } </style>

`

示例:

# ✅ 正确
title: "当Linux内核不再「迁就」PostgreSQL:一次抢占模型变更引发的性能风暴"

# ❌ 错误 - 嵌套引号会导致YAML解析错误
title: "当Linux内核不再"迁就"PostgreSQL:一次抢占模型变更引发的性能风暴"

二、内容组织

2.1 文章结构

---
title: "标题"
---

<style>
/* Mermaid diagram container */
.mermaid-container {
  position: relative;
  display: block;
  cursor: pointer;
  transition: opacity 0.2s;
  max-width: 100%;
  margin: 20px 0;
  overflow-x: auto;
}

.mermaid-container:hover {
  opacity: 0.8;
}

.mermaid-container svg {
  max-width: 100%;
  height: auto;
  display: block;
}

/* Modal overlay */
.mermaid-modal {
  display: none;
  position: fixed;
  z-index: 9999;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.9);
  animation: fadeIn 0.3s;
}

.mermaid-modal.active {
  display: flex;
  align-items: center;
  justify-content: center;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Modal content */
.mermaid-modal-content {
  position: relative;
  width: 90vw;
  height: 90vh;
  overflow: hidden;
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
}

.mermaid-modal-diagram {
  transform-origin: center center;
  transition: transform 0.2s ease;
  display: inline-block;
  min-width: 100%;
  cursor: grab;
  user-select: none;
}

.mermaid-modal-diagram.dragging {
  cursor: grabbing;
  transition: none;
}

.mermaid-modal-diagram svg {
  width: 100%;
  height: auto;
  display: block;
  pointer-events: none;
}

/* Control buttons */
.mermaid-controls {
  position: absolute;
  top: 10px;
  right: 10px;
  display: flex;
  gap: 8px;
  z-index: 10000;
}

.mermaid-btn {
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid #ddd;
  border-radius: 4px;
  padding: 8px 12px;
  cursor: pointer;
  font-size: 14px;
  transition: background 0.2s;
  color: #333;
  font-weight: 500;
}

.mermaid-btn:hover {
  background: white;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* Close button */
.mermaid-close {
  background: #f44336;
  color: white;
  border: none;
}

.mermaid-close:hover {
  background: #d32f2f;
}

/* Zoom indicator */
.mermaid-zoom-level {
  position: absolute;
  bottom: 20px;
  left: 20px;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 6px 12px;
  border-radius: 4px;
  font-size: 14px;
  z-index: 10000;
}
</style>

<script type="module">
  import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';

  mermaid.initialize({
    startOnLoad: false,
    theme: 'default',
    securityLevel: 'loose',
    htmlLabels: true,
    themeVariables: {
      fontSize: '14px'
    }
  });

  let currentZoom = 1;
  let currentModal = null;
  let isDragging = false;
  let startX = 0;
  let startY = 0;
  let translateX = 0;
  let translateY = 0;

  // Create modal HTML
  function createModal() {
    const modal = document.createElement('div');
    modal.className = 'mermaid-modal';
    modal.innerHTML = `
      <div class="mermaid-controls">
        <button class="mermaid-btn zoom-in">放大 +</button>
        <button class="mermaid-btn zoom-out">缩小 -</button>
        <button class="mermaid-btn zoom-reset">重置</button>
        <button class="mermaid-btn mermaid-close">关闭 ✕</button>
      </div>
      <div class="mermaid-modal-content">
        <div class="mermaid-modal-diagram"></div>
      </div>
      <div class="mermaid-zoom-level">100%</div>
    `;
    document.body.appendChild(modal);
    return modal;
  }

  // Show modal with diagram
  function showModal(diagramContent) {
    if (!currentModal) {
      currentModal = createModal();
      setupModalEvents();
    }

    const modalDiagram = currentModal.querySelector('.mermaid-modal-diagram');
    modalDiagram.innerHTML = diagramContent;

    // Remove any width/height attributes from SVG to make it responsive
    const svg = modalDiagram.querySelector('svg');
    if (svg) {
      svg.removeAttribute('width');
      svg.removeAttribute('height');
      svg.style.width = '100%';
      svg.style.height = 'auto';
    }

    // Setup drag functionality
    setupDrag(modalDiagram);

    currentModal.classList.add('active');
    currentZoom = 1;
    resetPosition();
    updateZoom();
    document.body.style.overflow = 'hidden';
  }

  // Hide modal
  function hideModal() {
    if (currentModal) {
      currentModal.classList.remove('active');
      document.body.style.overflow = '';
    }
  }

  // Update zoom level
  function updateZoom() {
    if (!currentModal) return;
    const diagram = currentModal.querySelector('.mermaid-modal-diagram');
    const zoomLevel = currentModal.querySelector('.mermaid-zoom-level');
    diagram.style.transform = `translate(${translateX}px, ${translateY}px) scale(${currentZoom})`;
    zoomLevel.textContent = `${Math.round(currentZoom * 100)}%`;
  }

  // Reset position when zoom changes
  function resetPosition() {
    translateX = 0;
    translateY = 0;
  }

  // Setup drag functionality
  function setupDrag(element) {
    element.addEventListener('mousedown', startDrag);
    element.addEventListener('touchstart', startDrag);
  }

  function startDrag(e) {
    if (e.type === 'mousedown' && e.button !== 0) return; // Only left click

    isDragging = true;
    const modalDiagram = currentModal.querySelector('.mermaid-modal-diagram');
    modalDiagram.classList.add('dragging');

    if (e.type === 'touchstart') {
      startX = e.touches[0].clientX - translateX;
      startY = e.touches[0].clientY - translateY;
    } else {
      startX = e.clientX - translateX;
      startY = e.clientY - translateY;
    }

    document.addEventListener('mousemove', drag);
    document.addEventListener('touchmove', drag);
    document.addEventListener('mouseup', stopDrag);
    document.addEventListener('touchend', stopDrag);
  }

  function drag(e) {
    if (!isDragging) return;
    e.preventDefault();

    if (e.type === 'touchmove') {
      translateX = e.touches[0].clientX - startX;
      translateY = e.touches[0].clientY - startY;
    } else {
      translateX = e.clientX - startX;
      translateY = e.clientY - startY;
    }

    updateZoom();
  }

  function stopDrag() {
    isDragging = false;
    const modalDiagram = currentModal?.querySelector('.mermaid-modal-diagram');
    if (modalDiagram) {
      modalDiagram.classList.remove('dragging');
    }
    document.removeEventListener('mousemove', drag);
    document.removeEventListener('touchmove', drag);
    document.removeEventListener('mouseup', stopDrag);
    document.removeEventListener('touchend', stopDrag);
  }

  // Setup modal event listeners
  function setupModalEvents() {
    if (!currentModal) return;

    // Close button
    currentModal.querySelector('.mermaid-close').addEventListener('click', hideModal);

    // Zoom buttons
    currentModal.querySelector('.zoom-in').addEventListener('click', () => {
      currentZoom = Math.min(currentZoom + 0.25, 3);
      updateZoom();
    });

    currentModal.querySelector('.zoom-out').addEventListener('click', () => {
      currentZoom = Math.max(currentZoom - 0.25, 0.5);
      updateZoom();
    });

    currentModal.querySelector('.zoom-reset').addEventListener('click', () => {
      currentZoom = 1;
      resetPosition();
      updateZoom();
    });

    // Close on background click
    currentModal.addEventListener('click', (e) => {
      if (e.target === currentModal) {
        hideModal();
      }
    });

    // Close on ESC key
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape' && currentModal.classList.contains('active')) {
        hideModal();
      }
    });
  }

  // Convert Jekyll-rendered code blocks to mermaid divs
  document.addEventListener('DOMContentLoaded', async function() {
    const codeBlocks = document.querySelectorAll('code.language-mermaid');

    for (const codeBlock of codeBlocks) {
      const pre = codeBlock.parentElement;
      const container = document.createElement('div');
      container.className = 'mermaid-container';

      const mermaidDiv = document.createElement('div');
      mermaidDiv.className = 'mermaid';
      mermaidDiv.textContent = codeBlock.textContent;

      container.appendChild(mermaidDiv);
      pre.replaceWith(container);
    }

    // Render all mermaid diagrams
    try {
      await mermaid.run({
        querySelector: '.mermaid'
      });
      console.log('Mermaid diagrams rendered successfully');
    } catch (error) {
      console.error('Mermaid rendering error:', error);
    }

    // Add click handlers to rendered diagrams
    document.querySelectorAll('.mermaid-container').forEach((container, index) => {
      // Find the rendered SVG inside the container
      const svg = container.querySelector('svg');
      if (!svg) {
        console.warn(`No SVG found in container ${index}`);
        return;
      }

      // Make the container clickable
      container.style.cursor = 'pointer';
      container.title = '点击查看大图';

      container.addEventListener('click', function(e) {
        e.preventDefault();
        e.stopPropagation();

        // Clone the SVG for the modal
        const svgClone = svg.cloneNode(true);
        const tempDiv = document.createElement('div');
        tempDiv.appendChild(svgClone);

        console.log('Opening modal for diagram', index);
        showModal(tempDiv.innerHTML);
      });

      console.log(`Click handler added to diagram ${index}`);
    });
  });
</script>


> 副标题或引言性问题

## 引言:吸引读者

简短的场景描述或问题陈述...

## 一、第一个主要部分

### 子标题

内容...

## 二、第二个主要部分

...

## References

[^1]: 引用1
[^2]: 引用2

要点:

2.2 引言写作技巧

好的引言特点:

  1. 场景化开头: 描述一个具体的问题场景
  2. 提出核心问题: 让读者知道文章要解决什么
  3. 数据或事实: 用具体数字增强说服力
  4. 路线图: 简要说明文章将如何解答问题

示例:

## 引言:从"完美运行"到"性能腰斩"

想象一下这样的场景:你的数据库服务器刚刚升级了最新的Linux Kernel 7.0,
期待着更好的性能和安全性。然而,上线后监控图表却显示了一个触目惊心的画面
——PostgreSQL的吞吐量在毫无征兆的情况下**骤降了将近一半**。

这不是虚构的故障演练,而是在Kernel 7.0发布前测试中被多次报告的真实问题[^1]。

三、代码与引用规范

3.1 代码块格式

```c
// C语言代码
int main() {
    return 0;
}
```

```
# 配置文件或无特定语言的代码块
config PREEMPT_VOLUNTARY
    bool "Voluntary Kernel Preemption"
```

支持的语言标识符 (Rouge highlighter):

不支持的标识符:

3.2 源代码引用

必须使用GitHub链接,不要使用本地路径:

# ✅ 正确 - 使用GitHub链接[`kernel/sched/core.c`](https://github.com/torvalds/linux/blob/master/kernel/sched/core.c)中

PostgreSQL的源代码[`src/backend/storage/lmgr/s_lock.c`](https://github.com/postgres/postgres/blob/master/src/backend/storage/lmgr/s_lock.c)

# ❌ 错误 - 本地路径`/Users/weli/works/linux/kernel/sched/core.c`

引用commit时包含:

  1. Commit hash (简短形式,前7-8位)
  2. Commit 标题
  3. GitHub链接
  4. LKML或邮件列表链接(如果有)

示例:

在commit [`7dadeaa6e851`](https://github.com/torvalds/linux/commit/7dadeaa6e851)中,
Peter Zijlstra详细解释了引入这一机制的三个核心原因[^2]:

> The introduction of PREEMPT_LAZY was for multiple reasons:
> 
> - PREEMPT_RT suffered from over-scheduling...
> - the endless and uncontrolled sprinkling of cond_resched()...

3.3 代码块中引用源码行号

从实际文件引用时可以包含行号信息(仅在注释中说明):

内核在[`kernel/sched/core.c`](https://github.com/torvalds/linux/blob/master/kernel/sched/core.c)中实现了这一机制:

```c
// kernel/sched/core.c: 1172-1183
static __always_inline int get_lazy_tif_bit(void)
{
    if (dynamic_preempt_lazy())
        return TIF_NEED_RESCHED_LAZY;
    return TIF_NEED_RESCHED;
}
\```

四、Mermaid 图表规范

4.1 何时使用Mermaid图表

建议使用场景:

每篇文章建议:

4.2 Mermaid语法注意事项

4.2.1 Sequence Diagram(时序图)

✅ 正确的participant定义:

sequenceDiagram
    participant App as 用户态应用(PostgreSQL)
    participant Kernel as 内核调度器
    participant CPU0 as CPU 0 (进程A)

❌ 错误 - 不要使用HTML标签:

sequenceDiagram
    participant App as 用户态应用<br/>(PostgreSQL)  ❌
    participant CPU0 as CPU 0<br/>进程A  ❌

常用语法:

sequenceDiagram
    A->>B: 同步调用
    A-->>B: 异步响应
    A-xB: 失败/错误
    activate A   # 激活生命线
    deactivate A # 结束生命线
    Note over A,B: 注释
    alt 条件1
        A->>B: 操作1
    else 条件2
        A->>B: 操作2
    end

4.2.2 Graph(流程图/关系图)

节点中可以使用HTML:

graph LR
    A[PREEMPT_NONE<br/>服务器优化] -->|转换| B[PREEMPT_LAZY<br/>简化内核]
    
    style A fill:#90EE90
    style B fill:#87CEEB

常用语法:

graph LR
    A[矩形节点] --> B{菱形决策}
    B -->|是| C[结果1]
    B -.->|否| D[结果2]
    
    subgraph 子图标题
        C --> E
        D --> E
    end

4.2.3 图表样式最佳实践

颜色使用:

示例:

graph LR
    style A fill:#90EE90,stroke:#333,stroke-width:2px
    style B fill:#87CEEB,stroke:#333,stroke-width:3px

4.3 图表说明文字

在图表前后添加说明:

下图展示了两种模式的关键差异:

```mermaid
sequenceDiagram
    ...
\```

简单来说,**内核将抢占决策权从"代码中的分散检查点"收拢到了"调度器的时钟中断"中**。

五、引用与脚注规范

5.1 脚注编号

使用递增数字:

这是第一个引用[^1],这是第二个引用[^2]。

## References

[^1]: 第一个引用的详细信息
[^2]: 第二个引用的详细信息

5.2 引用格式

Linux内核commit:

[^2]: Peter Zijlstra,Linux内核提交 [`7dadeaa6e851`](https://github.com/torvalds/linux/commit/7dadeaa6e851)*sched: Further restrict the preemption modes*。详细说明了引入PREEMPT_LAZY的三个核心原因,以及为何限制PREEMPT_NONE和PREEMPT_VOLUNTARY。完整提交信息:<https://patch.msgid.link/20251219101502.GB1132199@noisy.programming.kicks-ass.net>

PostgreSQL commit:

[^11]: Tomas Vondra,PostgreSQL提交 [`7fe2f67c7c9`](https://github.com/postgres/postgres/commit/7fe2f67c7c9)*Limit the size of numa_move_pages requests*。PostgreSQL侧对内核bug的规避措施。讨论:<https://postgr.es/m/aEtDozLmtZddARdB@msg.df7cb.de>

LKML讨论:

[^13]: LKML patch series:《[PATCH 00/14] Restartable Sequences: selftests, time-slice extension》,Thomas Gleixner提出RSEQ时间片扩展机制,共14个补丁。链接:<https://lkml.kernel.org/r/20251215155615.870031952@linutronix.de>

内核文档:

[^3]: Linux内核文档,《preempt-locking.rst》,详细说明了内核抢占模型的演化和`cond_resched()`的使用。参见:[Documentation/locking/preempt-locking.rst](https://github.com/torvalds/linux/blob/master/Documentation/locking/preempt-locking.rst)

5.3 引用要包含的要素

每个技术引用应包含:

  1. ✅ 作者/维护者名字
  2. ✅ 仓库名(Linux kernel / PostgreSQL等)
  3. ✅ Commit hash(带GitHub链接)
  4. ✅ Commit标题(斜体)
  5. ✅ 简短说明(为何重要/解决什么问题)
  6. ✅ 上游讨论链接(LKML/邮件列表)

六、写作风格

6.1 技术准确性

必须做到:

示例:

# ✅ 好 - 有明确来源
在commit [`7c70cb94d29c`](https://github.com/torvalds/linux/commit/7c70cb94d29c)中,
Peter Zijlstra说明了工作机制[^6]:

> This LAZY bit will be promoted to the full NEED_RESCHED bit on tick.

# ❌ 差 - 无来源的断言
LAZY标志会在时钟中断时被升级。(读者会问:你怎么知道的?)

# ❌ 差 - 没有具体来源的转述
有人提出了一个方案:恢复PREEMPT_VOLUNTARY模式。
(谁提出的?在哪里提出的?什么时候?)

# ✅ 好 - 有具体人名、commit和链接
Peter Zijlstra在commit [`476e8583ca16`](https://github.com/torvalds/linux/commit/476e8583ca16)中
果断地在x86架构上启用了PREEMPT_LAZY[^12]。

6.2 叙事技巧

使用场景化描述:

# ✅ 生动
让我们一步步推演这个灾难场景:

1. **CPU 0**上的进程A获得自旋锁L,开始执行临界区代码。
2. **此时**,调度器为CPU 0设置了`TIF_NEED_RESCHED_LAZY`标志。
3. 进程A继续执行,它并不知道自己被标记了。

# ❌ 枯燥
当一个进程持有自旋锁时,如果被抢占,会导致性能下降。

使用对比和类比:

这就像在高速公路上设置的临时检查站——内核线程运行到这里时,
会主动"看一眼"是否有更高优先级的任务需要CPU。

6.3 层次递进

从宏观到微观:

## 一、问题背景(宏观)
Linux抢占模型的演化...

## 二、技术细节(中观)
两个标志位的实现...

## 三、代码实现(微观)
```c
static __always_inline int get_lazy_tif_bit(void) {
    ...
}
\```

6.4 术语使用

中英文混用规则:


七、Git提交规范

7.1 Commit Message 格式

<type>(<scope>): <subject>

<body>

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

Type类型:

Scope范围:

示例:

docs(post): add Linux Kernel 7.0 PREEMPT_LAZY and PostgreSQL performance analysis

Add comprehensive technical analysis of the performance regression issue between
Linux Kernel 7.0's PREEMPT_LAZY scheduler and PostgreSQL's spinlock implementation.

Key topics covered:
- Linux preemption model evolution and PREEMPT_LAZY introduction
- PostgreSQL's userspace spinlock design and implicit kernel assumptions
- Two-flag mechanism (TIF_NEED_RESCHED vs TIF_NEED_RESCHED_LAZY)
- RSEQ time slice extension as the official solution

Includes 16 authoritative references to kernel commits, LKML discussions,
and PostgreSQL source code with GitHub links.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

7.2 提交策略

初稿提交:

  1. 完成基本内容 → 一次commit
  2. 格式修复 → 单独commit
  3. 添加图表 → 单独commit
  4. 修复错误 → 单独commit

避免:


八、质量检查清单

8.1 发布前检查

格式检查:

.mermaid-container:hover { opacity: 0.8; }

.mermaid-container svg { max-width: 100%; height: auto; display: block; }

/* Modal overlay */ .mermaid-modal { display: none; position: fixed; z-index: 9999; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.9); animation: fadeIn 0.3s; }

.mermaid-modal.active { display: flex; align-items: center; justify-content: center; }

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

/* Modal content */ .mermaid-modal-content { position: relative; width: 90vw; height: 90vh; overflow: hidden; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); display: flex; align-items: center; justify-content: center; }

.mermaid-modal-diagram { transform-origin: center center; transition: transform 0.2s ease; display: inline-block; min-width: 100%; cursor: grab; user-select: none; }

.mermaid-modal-diagram.dragging { cursor: grabbing; transition: none; }

.mermaid-modal-diagram svg { width: 100%; height: auto; display: block; pointer-events: none; }

/* Control buttons */ .mermaid-controls { position: absolute; top: 10px; right: 10px; display: flex; gap: 8px; z-index: 10000; }

.mermaid-btn { background: rgba(255, 255, 255, 0.9); border: 1px solid #ddd; border-radius: 4px; padding: 8px 12px; cursor: pointer; font-size: 14px; transition: background 0.2s; color: #333; font-weight: 500; }

.mermaid-btn:hover { background: white; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); }

/* Close button */ .mermaid-close { background: #f44336; color: white; border: none; }

.mermaid-close:hover { background: #d32f2f; }

/* Zoom indicator */ .mermaid-zoom-level { position: absolute; bottom: 20px; left: 20px; background: rgba(0, 0, 0, 0.7); color: white; padding: 6px 12px; border-radius: 4px; font-size: 14px; z-index: 10000; } </style>

`(如有图表)

内容检查:

可读性检查:

8.2 本地测试

# 1. 检查文件名格式
ls -la _posts/YYYY-MM-DD-*.md

# 2. 检查YAML frontmatter
head -10 _posts/YYYY-MM-DD-*.md

# 3. 检查Mermaid语法(无HTML标签)
grep -n "<br/>" _posts/YYYY-MM-DD-*.md | grep "participant"

# 4. 检查本地路径(应该没有)
grep -n "/Users/\|/home/" _posts/YYYY-MM-DD-*.md

# 5. 检查代码块语言标识符
grep -n '```[a-z]*' _posts/YYYY-MM-DD-*.md

# 6. 验证Mermaid图表渲染(推荐)
# 见下方 8.2.1 Mermaid图表本地验证

8.2.1 Mermaid图表本地验证

强烈建议:在提交blog前本地验证所有Mermaid图表,避免推送后才发现渲染错误。

安装Mermaid CLI

# 使用npx(无需全局安装,每次自动下载最新版)
npx -y @mermaid-js/mermaid-cli@latest --version

# 或者全局安装(如果需要频繁使用)
npm install -g @mermaid-js/mermaid-cli

系统要求:需要Node.js环境(通过node --version检查)

提取并验证所有图表

方法1:使用Python脚本(推荐)

# 创建提取脚本
cat > /tmp/test_mermaid.py << 'EOF'
import re
import sys

post_file = sys.argv[1] if len(sys.argv) > 1 else '_posts/YYYY-MM-DD-*.md'

with open(post_file, 'r') as f:
    content = f.read()

diagrams = re.findall(r'```mermaid\n(.*?)```', content, re.DOTALL)
print(f"Found {len(diagrams)} diagrams\n")

for i, diagram in enumerate(diagrams, 1):
    filename = f'/tmp/diagram_{i}.mmd'
    with open(filename, 'w') as f:
        f.write(diagram.strip())
    print(f"Saved {filename}")
EOF

# 运行提取
python3 /tmp/test_mermaid.py _posts/2026-04-08-your-post.md

# 验证所有图表
for i in 1 2 3 4; do
  echo "Testing diagram_$i..."
  npx -y @mermaid-js/mermaid-cli@latest \
    -i /tmp/diagram_$i.mmd \
    -o /tmp/output_$i.svg 2>&1 | grep -E "(Generating|Error)"
  
  if [ -f /tmp/output_$i.svg ]; then
    echo "✅ diagram_$i: SUCCESS"
  else
    echo "❌ diagram_$i: FAILED"
  fi
done

方法2:验证单个图表

# 手动创建测试文件
cat > /tmp/test.mmd << 'EOF'
sequenceDiagram
    participant A as 用户
    participant B as 服务器
    A->>B: 请求
    B-->>A: 响应
EOF

# 渲染为SVG
npx -y @mermaid-js/mermaid-cli@latest -i /tmp/test.mmd -o /tmp/test.svg

# 检查结果
ls -lh /tmp/test.svg && echo "✅ 渲染成功"

常见Mermaid错误及修复

错误1:箭头缺少空格或多余空格

# ❌ 错误(某些版本不支持带空格的箭头)
A ->> B: 消息
A -->> B: 消息

# ✅ 正确(无空格版本更兼容)
A->>B: 消息
A-->>B: 消息

错误2:自引用的销毁箭头

# ❌ 错误
CPU0 --x CPU0: 被销毁

# ✅ 正确:用Note代替
Note right of CPU0: 被销毁

错误3:对participant使用deactivate

# ❌ 错误
participant CPU0
deactivate CPU0

# ✅ 正确:只对activate过的生命线使用deactivate
activate Lock
deactivate Lock

错误4:participant名称中使用HTML标签

# ❌ 错误(sequenceDiagram不支持)
participant A as 用户<br/>应用

# ✅ 正确
participant A as 用户(应用)

自动化脚本

可将验证步骤加入pre-commit hook或Makefile:

# .git/hooks/pre-commit
#!/bin/bash
changed_posts=$(git diff --cached --name-only | grep '^_posts/.*\.md$')
if [ -n "$changed_posts" ]; then
  echo "Validating Mermaid diagrams..."
  python3 /tmp/test_mermaid.py $changed_posts
  # 添加验证逻辑...
fi

九、常见问题与解决方案

9.1 YAML解析错误

问题: title: "文章标题中有"引号""

解决:

# 方案1: 使用书名号
title: "文章标题中有「引号」"

# 方案2: 转义
title: "文章标题中有\"引号\""

# 方案3: 单引号包裹
title: '文章标题中有"引号"'

9.2 Mermaid渲染错误

问题: “Syntax error in text”

检查:

  1. Participant中是否有<br/>标签?
  2. 箭头语法是否正确(是否有空格)?
  3. 缩进是否一致?
  4. 引号配对是否正确?

解决:

# ❌ 错误 - participant中使用HTML标签
participant A as 用户<br/>应用

# ✅ 正确
participant A as 用户(应用)

# ❌ 错误 - 箭头和participant之间缺少空格
CPU0--xCPU0: 消息

# ✅ 正确 - 箭头前后都要有空格
CPU0 --x CPU0: 消息
A ->> B: 消息
A -->> B: 消息

常用箭头类型:

9.3 代码高亮不工作

问题: 代码块没有语法高亮

检查:

  1. 语言标识符是否正确?
  2. 是否使用了不支持的语言?

解决:

# ✅ C代码
```c
int main() {}
```

# ✅ Kconfig(使用空标识符)
```
config PREEMPT_LAZY
```

# ❌ 不存在的语言
```kconfig  # Rouge不支持
```

十、工作流程总结

完整写作流程

graph TD
    A[选题与调研] --> B[收集上游讨论和源码]
    B --> C[撰写大纲]
    C --> D[编写正文]
    D --> E[添加代码引用]
    E --> F[创建Mermaid图表]
    F --> G[添加References]
    G --> H[本地测试]
    H --> I{检查通过?}
    I -->|否| J[修复问题]
    J --> H
    I -->|是| K[Git提交]
    K --> L[推送发布]

时间分配建议


附录:参考资源

工具链

上游资源

示例文章

参考这些高质量文章:


最后更新: 2026-04-08
版本: 1.0
适用范围: liweinan.github.io 技术博客

My Github Page: https://github.com/liweinan

Powered by Jekyll and Theme by solid

If you have any question want to ask or find bugs regarding with my blog posts, please report it here:
https://github.com/liweinan/liweinan.github.io/issues