<?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/categories/发现</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/categories/发现</link>
    </image>
    <item>
      <title>斯坦福大学的现代软件开发者课程The Modern Software Developer</title>
      <link>https://itindex.net/detail/63103-%E6%96%AF%E5%9D%A6%E7%A6%8F-%E5%A4%A7%E5%AD%A6-%E7%8E%B0%E4%BB%A3</link>
      <description>&lt;div&gt;课程链接： &lt;/div&gt; &lt;a href="https://t.co/erZjUgOI08" rel="noopener noreferrer nofollow" target="_blank"&gt;https://themodernsoftware.dev&lt;/a&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;斯坦福计算机科学系又一次站出来告诉所有人：谁才是真正的风向标  &lt;br /&gt;  &lt;br /&gt;2025秋季新开的CS146S：现代软件开发者，直接把我们最近一年新兴的AI原生软件工程整套活儿塞进了课堂  &lt;br /&gt;  &lt;br /&gt;课程完整复刻AI时代的全生命周期流水线：    &lt;br /&gt;  &lt;br /&gt;从零手搓编码Agent、玩转MCP协议、魔改AI IDE，到用Claude Code和Devin真刀真枪开干；  &lt;br /&gt;  &lt;br /&gt;再到Warp终端代理、Semgrep实时堵安全漏洞、Graphite自动stack PR、Vercel v0一个提示词吐出生产级全栈，最后用Resolve给上线后的系统装上自主修复的“大脑”  &lt;br /&gt;  &lt;br /&gt;整条线下来，几乎看不到人  &lt;br /&gt;  &lt;br /&gt;这些工具其实早就被我们X上的开发者玩烂了：    &lt;br /&gt;  &lt;br /&gt;Cursor、Windsurf、Aider、Continue dev、Cody、Copilot、Warp已经是标配  &lt;br /&gt;Cursor、Windsurf、Aider、Continue dev、Cody、Copilot、Warp 已经是标配  &lt;br /&gt;  &lt;br /&gt;Semgrep+Claude把安全审查干到飞起，Graphite把PR叠成艺术品，Vercel v0+Next.js 15让全栈开发变成一句话的事  &lt;br /&gt;  &lt;br /&gt;Resolve和LangSmith则直接让系统学会自己修bug  &lt;br /&gt;  &lt;br /&gt;同时不愧宇宙第一大系，每周都有Cognition、Anthropic、Warp、Semgrep、Graphite、Vercel、a16z的创始人或核心开发者亲自来拆SOTA工具；作业全用最新闭源商业模型，期末项目占80%，交一个能跑的AI原生产品  &lt;br /&gt;  &lt;br /&gt;虽然很fancy，但有一点小小提示：  &lt;br /&gt;  &lt;br /&gt;对刚进CS殿堂或者想系统性吃透AI原生开发的新同学来说，这门课就是当前全球最硬、最完整的神课，能让你直接对齐2030年的生产力  &lt;br /&gt;  &lt;br /&gt;但如果你已经天天Cursor+Claude Code+Vercel v0打仗的老兵，深度确实差点，更多是拿来对对表、补补漏  &lt;br /&gt;  &lt;br /&gt;  &lt;br /&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 />
      <guid isPermaLink="true">https://itindex.net/detail/63103-%E6%96%AF%E5%9D%A6%E7%A6%8F-%E5%A4%A7%E5%AD%A6-%E7%8E%B0%E4%BB%A3</guid>
      <pubDate>Tue, 09 Dec 2025 11:21:59 CST</pubDate>
    </item>
    <item>
      <title>我发现了一段感情能长久的关键：</title>
      <link>https://itindex.net/detail/63032-%E5%8F%91%E7%8E%B0-%E6%84%9F%E6%83%85-%E9%95%BF%E4%B9%85</link>
      <description>&lt;p&gt;  &lt;img src="https://ossimg.xinli001.com/20250804/82b28cf132b94d86160c4f81ae83fde8.jpeg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;img src="https://ossimg.xinli001.com/20250804/3a6c69b11020dd6214b14880f77a106d.jpeg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;img src="https://ossimg.xinli001.com/20250804/83dad62a3e05cb2da48ec74124462a6e.jpeg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;img src="https://ossimg.xinli001.com/20250804/c352d1f718a30ddfe0da5ceb04b529d8.jpeg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;img src="https://ossimg.xinli001.com/20250804/eb028edb1c1b4845b2170c1da04f95d3.jpeg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;img src="https://ossimg.xinli001.com/20250804/dbe7f90dc9cfecad8c38f16be39ee75c.jpeg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt; &lt;blockquote&gt;  &lt;p&gt;1. 这个月，你有哪个瞬间感受到“我爱着你”吗？   &lt;br /&gt;   &lt;br /&gt;2. 我们最近有创造出什么共同回忆吗？   &lt;br /&gt;   &lt;br /&gt;3. 你今天过得怎么样？有什么想分享的？   &lt;br /&gt;   &lt;br /&gt;4. 最近我有没有说过什么话让你不高兴？   &lt;br /&gt;   &lt;br /&gt;5. 对肢体接触（牵手、拥抱）的频率感到满意吗？   &lt;br /&gt;   &lt;br /&gt;6. 有空的话，你想和我去尝试什么周末活动？   &lt;br /&gt;   &lt;br /&gt;7. 你希望我用什么样的方式回应你的情绪？   &lt;br /&gt;   &lt;br /&gt;8. 我们有多久没一起干点“没用但开心”的事情了？   &lt;br /&gt;   &lt;br /&gt;9. 你觉得我们各自有足够的个人空间吗？   &lt;br /&gt;   &lt;br /&gt;10. 我最近有哪些变化吗？   &lt;br /&gt;   &lt;br /&gt;11. 如果我改掉一个缺点，你希望是什么？   &lt;br /&gt;   &lt;br /&gt;12. 在你的眼里，我有哪些优点或者天赋？   &lt;br /&gt;   &lt;br /&gt;13. 遇到意见分歧的情况，你觉得怎么处理比较好？   &lt;br /&gt;   &lt;br /&gt;14. 如果闹矛盾了，我们先沟通还是先照顾情绪？   &lt;br /&gt;   &lt;br /&gt;15. 你最近有什么压力是我没有察觉到的？   &lt;br /&gt;   &lt;br /&gt;16. 我做什么事会让你感到开心？   &lt;br /&gt;   &lt;br /&gt;17. 你希望我有事直说还是委婉沟通？   &lt;br /&gt;   &lt;br /&gt;18. 有哪一瞬间让你觉得很难忘？   &lt;br /&gt;   &lt;br /&gt;19. 如果要定“吵架规则”，你想加什么？（比如不隔夜）   &lt;br /&gt;   &lt;br /&gt;20. 除了这些，还有什么是我们应该好好聊聊的？&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;  &lt;br /&gt;  &lt;img src="https://ossimg.xinli001.com/20250804/6b9ed6fe7ca361fa0778f38fd6cf137d.jpeg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;img src="https://ossimg.xinli001.com/20250804/0744f078ce19057f80791479343f320f.jpeg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt; &lt;h6&gt;作者：阿希  &lt;br /&gt;运营：雪莉玫  &lt;br /&gt;监制：Jessica&lt;/h6&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;  &lt;img src="https://ossimg.xinli001.com/20250804/f4668bc57dca6a1f3b50e337b8ad8211.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;『如果您觉得这篇文章对您有帮助，欢迎分享给更多的人，一起传播心理学知识，让世界更美好❤』&lt;/p&gt; &lt;p&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 />
      <guid isPermaLink="true">https://itindex.net/detail/63032-%E5%8F%91%E7%8E%B0-%E6%84%9F%E6%83%85-%E9%95%BF%E4%B9%85</guid>
      <pubDate>Mon, 04 Aug 2025 22:44:32 CST</pubDate>
    </item>
    <item>
      <title>编程语言是如何实现并发的之操作系统篇 · BMPI</title>
      <link>https://itindex.net/detail/62933-%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80-%E5%B9%B6%E5%8F%91-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F</link>
      <description>&lt;div&gt;    &lt;ul&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/?continueFlag=9c9ca4836bf40544b491dee6be45203d#%E4%BB%8E%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E8%BF%90%E8%A1%8C%E7%A8%8B%E5%BA%8F%E8%AF%B4%E8%B5%B7"&gt;从操作系统运行程序说起&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/?continueFlag=9c9ca4836bf40544b491dee6be45203d#%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%9A%84%E6%94%AF%E6%8C%81"&gt;操作系统的支持&lt;/a&gt;        &lt;ul&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/?continueFlag=9c9ca4836bf40544b491dee6be45203d#%E8%B0%83%E5%BA%A6scheduling"&gt;调度(Scheduling)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/?continueFlag=9c9ca4836bf40544b491dee6be45203d#%E7%BA%BF%E7%A8%8Bthread"&gt;线程(Thread)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/?continueFlag=9c9ca4836bf40544b491dee6be45203d#%E7%94%A8%E6%88%B7%E7%BA%BF%E7%A8%8Buser-level-thread"&gt;用户线程(User-level Thread)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/?continueFlag=9c9ca4836bf40544b491dee6be45203d#%E7%BA%BF%E7%A8%8B%E6%A8%A1%E5%9E%8Bthread-model"&gt;线程模型(Thread Model)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/?continueFlag=9c9ca4836bf40544b491dee6be45203d#%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2context-switching"&gt;上下文切换(Context switching)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/?continueFlag=9c9ca4836bf40544b491dee6be45203d#io%E6%A8%A1%E5%9E%8Bio-model"&gt;I/O模型(I/O Model)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/?continueFlag=9c9ca4836bf40544b491dee6be45203d#%E5%B9%B6%E5%8F%91%E8%BF%98%E6%98%AF%E5%B9%B6%E8%A1%8C"&gt;并发还是并行&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/?continueFlag=9c9ca4836bf40544b491dee6be45203d#%E6%80%BB%E7%BB%93"&gt;总结&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;h2&gt;从操作系统运行程序说起&lt;/h2&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;这是一台拥有2个虚拟CPU核心的      &lt;u&gt;Linux&lt;/u&gt;服务器的      &lt;u&gt;系统监控界面&lt;/u&gt;。其中红框①中      &lt;code&gt;PPID&lt;/code&gt;代表父进程ID，      &lt;code&gt;PID&lt;/code&gt;代表进程或线程ID。红框②中      &lt;code&gt;CPU&lt;/code&gt;代表当前线程运行的CPU核心编号。红框③中是程序的运行命令，其中绿色代表的是      &lt;u&gt;线程，白色为进程&lt;/u&gt;。&lt;/p&gt;    &lt;p&gt;以PID为1375的进程为例，它的父进程为1086，可以通过PPID不断追溯至PID为1的      &lt;u&gt;        &lt;code&gt;init&lt;/code&gt;&lt;/u&gt;进程。从这可以看出Linux通过      &lt;u&gt;        &lt;code&gt;fork()&lt;/code&gt;&lt;/u&gt;的系统调用不断的复制出大量的需要被执行的程序进程。&lt;/p&gt;    &lt;p&gt;进程是操作系统进行      &lt;u&gt;资源分配&lt;/u&gt;的一个独立单位，而实际在CPU运行调度的是线程。以进程1375为例，它又创建了7个线程，如下：&lt;/p&gt;    &lt;pre&gt;      &lt;code&gt;$ ls /proc/1375/task/
1375  1429  1430  1431  1432  1433  1488
$ ls /proc/1375/task/1429
arch_status  cgroup      cmdline             cpuset   exe     gid_map  loginuid  mountinfo  ns         oom_score      patch_state  root       sessionid  smaps_rollup  statm    uid_map
attr         children    comm                cwd      fd      io       maps      mounts     numa_maps  oom_score_adj  personality  sched      setgroups  stack         status   wchan
auxv         clear_refs  cpu_resctrl_groups  environ  fdinfo  limits   mem       net        oom_adj    pagemap        projid_map   schedstat  smaps      stat          syscall&lt;/code&gt;&lt;/pre&gt;    &lt;p&gt;其中线程1430与1432是调度运行在2号CPU核心上的，如果持续观察这个监控界面，会发现同一个线程会不定时在两个CPU核心之间来回切换，这实际正是操作系统对这些线程在多核CPU上进行抢占式调度。&lt;/p&gt;    &lt;p&gt;操作系统之所以能用有限的CPU核心去运行非常多的程序，并且用户感觉这些程序是在同时运行。一方面操作系统（内核）可以通过一些方法实现并发处理任务（程序），另外一方面得益于多个CPU核心，操作系统还可以并行处理任务。&lt;/p&gt;    &lt;p&gt;本文并不是研究操作系统是怎么实现并发的，但在搞清楚编程语言是怎么实现并发处理之前，很有必要提前对操作系统支持并发提供的一些重要特性做一个全面的介绍。操作系统为了支持多任务处理，提供了进程管理与调度，同时在I/O上提供了多种访问文件或网络的系统调用方式。&lt;/p&gt;    &lt;h2&gt;操作系统的支持&lt;/h2&gt;    &lt;pre&gt;      &lt;code&gt;# 操作系统
## 进程(Process)
### 调度方式
- 抢占式(Preemptive)
- 协作式(Cooperative)
### 执行方式
- 用户线程(User-level Thread)
  - Coroutine
    - Verticle
  - Goroutine
  - Erlang process
  - Green Thread(Java)
- 内核线程(Kernel-level Thread)
- 纤程(Fiber)
## I/O
- 同步(Synchronous)
  - 阻塞式(Blocking)
  - 非阻塞式(Non-blocking)
  - 多路复用(Multiplexing)
  - 信号驱动(Signal Driven)
- 异步(Asynchronous)&lt;/code&gt;&lt;/pre&gt;    &lt;h3&gt;调度(Scheduling)&lt;/h3&gt;    &lt;p&gt;进程调度主要有抢占式调度和协作式调度两种：抢占式(Preemptive)与协作式(Cooperative)。&lt;/p&gt;    &lt;a href="https://www.slanglabs.in/blog/python-microservices-01-tornado-asyncio-lint-test-coverage-project-setup"&gt;      &lt;img alt="&amp;#25250;&amp;#21344;&amp;#24335;&amp;#19982;&amp;#21327;&amp;#20316;&amp;#24335;&amp;#20219;&amp;#21153;&amp;#35843;&amp;#24230;(Preemptive Multitasking vs. Cooperative Multitasking)"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;p&gt;抢占式与协作式任务调度(Preemptive Multitasking vs. Cooperative Multitasking)&lt;/p&gt;    &lt;p&gt;抢占式调度往往在一些重要位置（Sleep Call，Timer Tick）放置了中断信号，通过这个信号通知操作系统调度器(Scheduler)进行进程切换。在抢占式模型中，正在运行的进程可能会被强行挂起，这是由于这些中断信号引发的。&lt;/p&gt;    &lt;p&gt;协作式调度也叫非抢占式调度，是指当前运行的进程通过自身代码逻辑出让CPU控制权。与抢占式调度的区别在于进程运行不会被中断信号打断，除非其主动出让控制权给其他进程。&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;以上描述并没有明确区分进程还是线程，实际在        &lt;u&gt;Linux系统的内核态上&lt;/u&gt;，用户态的线程统一按        &lt;u&gt;轻量级进程(Light-weight process)&lt;/u&gt;来处理，它们与真正的进程的区别是在一个用户态进程中的线程共享了相同的地址空间和其他资源（如打开的文件描述符），但在内核调度上并没有什么区别。&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;线程是进程的运行实例，哪怕在非多线程的进程中，在内核态实际运行进程的还是内核线程，所以接下来介绍下线程的分类。&lt;/p&gt;    &lt;h3&gt;线程(Thread)&lt;/h3&gt;    &lt;p&gt;我们在编程语言中见到的线程，一般指的是与内核线程一一映射的用户态线程，比如Java中的Thread其实就是内核线程。但一些编程语言如Erlang与Go都实现了更轻量级的用户线程。&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;用户线程(User-level Thread)        &lt;ul&gt;          &lt;li&gt;协程(Coroutines - Cooperative User-Level Threads)：应用程序通过线程库自行实现的            &lt;strong&gt;协作式调度&lt;/strong&gt;的用户线程，代表性的有Go语言的Goroutine（1.14之前的版本），Vert.x框架中的Verticle。&lt;/li&gt;          &lt;li&gt;Go Goroutine：Go语言的Goroutine在1.14之前是协程的机制，之后的版本采用了            &lt;a href="https://go.dev/doc/go1.14"&gt;异步抢占式调度(asynchronously preemptible)&lt;/a&gt;。&lt;/li&gt;          &lt;li&gt;Erlang process：Erlang VM(BEAM)管理的用户线程，与协程相比的优势在于它可以做到            &lt;strong&gt;公平调度&lt;/strong&gt;，不会出现协程中某个用户线程占用过多CPU周期。&lt;/li&gt;          &lt;li&gt;绿色线程(Green Thread)：类似于协程，是由            &lt;u&gt;Java JDK实现&lt;/u&gt;的，但因为            &lt;u&gt;早期Linux系统没实现内核态的抢占式调度&lt;/u&gt;，Green Thread只能在Solaris系统上发挥它的威力，最终在JDK 1.3之后被Native Thread取代。所以现行的JDK的线程实际是非常重量级的内核态线程，Java的            &lt;a href="https://github.com/openjdk/loom"&gt;Project Loom&lt;/a&gt;会尝试实现新的Green Thread方案，并且是抢占式的调度方案。&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;      &lt;li&gt;内核线程(Kernel-level Thread)：操作系统内核管理的        &lt;strong&gt;抢占式调度&lt;/strong&gt;的线程，是最终运行在CPU上实际执行任务的最小单元。&lt;/li&gt;      &lt;li&gt;纤程(Fibers)：操作系统内核管理的        &lt;strong&gt;协作式调度&lt;/strong&gt;的线程。这一系统级别的方案最终因硬件和软件的发展        &lt;u&gt;逐渐式微&lt;/u&gt;，现在的用户线程也能达到协作式调度的效果。&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;用户线程与内核线程的区别在于用户线程的调度是发生在用户态，内核中无法感知到用户线程的存在，并且调度也发生在用户态，一般是由线程库或编程语言运行时自行实现的。而内核线程的调度是由内核完成的，一般是抢占式调度。&lt;/p&gt;    &lt;h3&gt;用户线程(User-level Thread)&lt;/h3&gt;    &lt;p&gt;用户线程大多是采用协作调度的方式实现，本质上是      &lt;strong&gt;同步执行在与CPU核心数量相同的内核线程上的&lt;/strong&gt;，不仅能极大的降低了上下文开销，还能最佳的利用多核CPU的计算能力。&lt;/p&gt;    &lt;p&gt;用户线程的轻量除了体现在调度的上下文切换开销上，还体现了在对内存的需求上。如果要在4核心4GB内存的笔记本电脑中测试同时生成100万个线程的话，不同编程语言对内存的需求：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;Elixir: 0.48 GB (Process)&lt;/li&gt;      &lt;li&gt;Golang: 1.91 GB (Goroutine)&lt;/li&gt;      &lt;li&gt;Java: 977 GB (Thread)&lt;/li&gt;      &lt;li&gt;PHP: 6836 GB (Laravel Request)&lt;/li&gt;&lt;/ul&gt;    &lt;blockquote&gt;      &lt;p&gt;数据来源：Programming Elixir        &lt;sup&gt;Chapter 15&lt;/sup&gt;&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;但用户线程的执行最终是由内核线程来完成，所以存在一个从用户线程到内核线程的映射模型。&lt;/p&gt;    &lt;h3&gt;线程模型(Thread Model)&lt;/h3&gt;    &lt;p&gt;可能有人会疑惑，用户线程与内核线程是一一映射的吗？总的来说有以下三种线程模型：&lt;/p&gt;    &lt;a href="https://medium.com/swlh/different-threading-models-why-i-feel-goroutine-is-better-though-with-some-limitations-b73863ba4dae"&gt;      &lt;img alt="&amp;#19981;&amp;#21516;&amp;#30340;&amp;#32447;&amp;#31243;&amp;#27169;&amp;#22411;(Different Threading Models)"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;p&gt;不同的线程模型(Different Threading Models)&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;1x1 (kernel-level threading)：用户线程与内核线程是一一映射的。这是最简单的模型。在这种语境下，用户线程中的线程就是我们常规意义上说的线程，当程序创建一个线程时，也会在内核中创建一个内核线程。目前大多数操作系统如Linux、Solaris、FreeBSD、macOS与iOS内核的线程模型就是这种。&lt;/li&gt;      &lt;li&gt;Nx1 (user-level threading)：多个用户线程与一个内核线程映射。在这种模型中，内核线程只有一个，在应用内部不存在内核线程切换的开销，程序的并发能力是很高的。但一旦某个用户线程被阻塞（发生网络或文件I/O系统调用），其他用户线程也会被阻塞。另外应用也无法从多核CPU上获得更好的并发性。所以实际的使用场景中，这种模型并不常见。&lt;/li&gt;      &lt;li&gt;MxN (hybrid threading)：多个用户线程与多个内核线程映射。这种模型最为复杂，但也是最强大的线程模型，不仅有着很好的并发能力，同时还能获得多核CPU的处理能力。早期的Solaris内核中也支持这种线程模型，但因为其会导致内核调度过于复杂，逐渐被放弃。但在Erlang VM和Go语言的运行时就又实现了这种线程模型。&lt;/li&gt;&lt;/ul&gt;    &lt;a href="https://docs.oracle.com/cd/E19620-01/805-3024/6j2sumi1a/index.html"&gt;      &lt;img alt="&amp;#26089;&amp;#26399;Solaris&amp;#20869;&amp;#26680;&amp;#30340;&amp;#32447;&amp;#31243;&amp;#21644;&amp;#36731;&amp;#37327;&amp;#32423;&amp;#36827;&amp;#31243;(Threads and Lightweight Processes)"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;p&gt;早期Solaris内核的线程和轻量级进程(Threads and Lightweight Processes)&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;轻量级进程(Light-weight process)：Solaris内核中的概念，但也会在其他系统内核中看到类似的概念。指的是用户线程和内核线程之间的接口，也可被认为是一个调度用户线程执行的虚拟CPU。当用户线程发出系统调用时，运行该线程的LWP调用内核并保持绑定到该内核线程至少直到系统调用完成。当LWP在内核中为用户线程执行系统调用时，它会运行一个内核线程。因此，每个LWP都与一个内核线程相关联。只有在用户线程完全由轻量级进程构成时，才可以说轻量级进程就是线程。Go语言中Goroutine的G-P-M调度模型中，P承担了类似LWP的角色。&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;应用程序为什么会费劲的设计出用户线程？操作系统提供的内核线程不香吗？这是因为操作系统内核的线程切换是重量级的操作，它需要进行上下文切换，而这会很耗时。&lt;/p&gt;    &lt;h3&gt;上下文切换(Context switching)&lt;/h3&gt;    &lt;p&gt;在进程间切换需要消耗一定的CPU时钟周期进行相关的状态管理工作，包括寄存器和内存映射的保存与读取、更新各种内部的表等。比如在Linux内核中，上下文切换需要涉及寄存器、栈指针、程序计数器的切换。&lt;/p&gt;    &lt;p&gt;在这篇      &lt;a href="https://blog.tsunanet.net/2010/11/how-long-does-it-take-to-make-context.html"&gt;How long does it take to make a context switch?&lt;/a&gt;中可以看到一个结论是：&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;Context switching is expensive. My rule of thumb is that it’ll cost you about 30µs of CPU overhead…Applications that create too many threads that are constantly fighting for CPU time (such as Apache’s HTTPd or many Java applications) can waste considerable amounts of CPU cycles just to switch back and forth between different threads…I think the sweet spot for optimal CPU use is to have the same number of worker threads as there are hardware threads, and write code in an asynchronous / non-blocking fashion.&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;因为线程调度的上下文切换成本非常昂贵，所以最佳的做法是应用程序使用和CPU核心相同的线程数，这样每个线程都能充分利用CPU核心的时间片，避免了应用内部多个线程的上下文切换开销。&lt;/p&gt;    &lt;p&gt;用户线程的轻量级让应用程序能够极大的提高并发性，但也会有一些问题，比如某个用户线程中发起一个网络请求导致底层的内核线程被阻塞，因为多个用户线程在共用这个内核线程，最终导致大量的用户线程被阻塞。&lt;/p&gt;    &lt;p&gt;解决这个问题需要了解操作系统的I/O模型。&lt;/p&gt;    &lt;h3&gt;I/O模型(I/O Model)&lt;/h3&gt;    &lt;p&gt;当应用程序需要访问文件或者网络资源时，应用内的线程将会花费大量的时间来等待数据的到来。如下图所示：&lt;/p&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;如果把CPU处理计算机指令的速度类比成高铁的速度，那线程一次文件或网络的访问将会和蜗牛一样慢，这相当于你在高铁上让蜗牛去帮你取快递，对CPU来说是巨大的浪费。现代操作系统已经提供了多种I/O模型来解决这个问题。常见的I/O模型有：&lt;/p&gt;    &lt;a href="https://www.4e00.com/blog/linux/2017/09/29/unix-network-programming-charpter-6-io-multiplexing.html"&gt;      &lt;img alt="&amp;#20116;&amp;#31181;I/O&amp;#27169;&amp;#22411;&amp;#23545;&amp;#27604;(Comparison of the five I/O models)"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;p&gt;五种I/O模型对比(Comparison of the five I/O models)&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;同步(Synchronous)        &lt;ul&gt;          &lt;li&gt;阻塞式(Blocking)：同步阻塞式是最常见的I/O模型。线程在访问文件或网络资源时，会因发起了内核的系统调用被挂起，内核会检查文件描述符是否可读，当文件描述符中存在数据时，内核会将数据复制给线程并交回控制权，线程从挂起状态切换成可运行状态等到内核调度运行。&lt;/li&gt;          &lt;li&gt;非阻塞式(Non-blocking)：线程在访问文件或网络资源时，因文件描述符是非阻塞的，线程在检查数据是否可读的阶段是非阻塞的。此模型需要线程不停的通过轮询(polling)的方式检查文件描述符是否可读。但之所以属于同步I/O，是因为在最终读取数据(            &lt;code&gt;recvfrom&lt;/code&gt;)时需要从内核态中拷贝数据(            &lt;code&gt;recvfrom&lt;/code&gt;)到用户态中，这个阶段线程依旧被阻塞住无法处理其他指令。&lt;/li&gt;          &lt;li&gt;多路复用(Multiplexing)：和非阻塞式的区别在于，多路复用模型的线程可以同时访问多个文件描述符，这很适合构建高并发的Web服务器或中间件。但此模型会在检查文件描述符时会被阻塞(            &lt;u&gt;              &lt;code&gt;select&lt;/code&gt;&lt;/u&gt;)，并且在读取数据(            &lt;code&gt;recvfrom&lt;/code&gt;)时也会被阻塞。和多路复用模型相似的是使用多线程和阻塞I/O，但当线程产生很多时会消耗大量的内存资源以及线程调度产生的上下文切换开销，所以多路复用模型一般只使用单线程模型。&lt;/li&gt;          &lt;li&gt;信号驱动(Signal Driven)：和上面的模型区别在于，之前的模型都需要线程主动轮询，信号驱动模型需要监听内核的            &lt;code&gt;SIGIO&lt;/code&gt;事件，通过注册事件处理函数，之后线程可以继续执行其他任务。当数据可读时，线程处理函数会以阻塞的方式从内核态复制数据到用户态。&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;      &lt;li&gt;异步(Asynchronous)：此模型和同步模型最大的区别在于，不仅在获取文件操作符时不会被阻塞，数据从内核态复制到用户态也不会被阻塞，因为内核会去做这个复制数据的工作，线程只需要在回调函数中使用数据即可。&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;关于I/O模型的更多细节，请参考：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;        &lt;a href="https://rickhw.github.io/2019/02/27/ComputerScience/IO-Models/"&gt;Study Notes - I/O Models&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch06lev1sec2.html"&gt;I/O Models&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;blockquote&gt;      &lt;p&gt;思考一个问题：如果用户线程不可避免的需要被挂起进（如访问共享资源但没有获得锁）而导致内核线程被挂起，如何调度可以让此内核线程上的用户线程可以继续运行？&lt;/p&gt;&lt;/blockquote&gt;    &lt;h2&gt;并发还是并行&lt;/h2&gt;    &lt;p&gt;前面讨论了很多和I/O相关的概念，并不是所有的计算机任务都是和I/O相关(I/O bound)的，比如很多算法都需要CPU做大量的计算，这时候CPU核心根本不会因为等待外部资源而空转，如果在这种计算密集型(CPU bound)任务中使用多线程技术，那么就会产生大量的线程上下文切换开销，最终会导致处理任务的性能变慢。&lt;/p&gt;    &lt;p&gt;在这篇      &lt;a href="https://www.ardanlabs.com/blog/2018/12/scheduling-in-go-part3.html"&gt;Scheduling In Go : Part III - Concurrency&lt;/a&gt;文章中，作者对比了两种类型工作在并发和并行模式的对比，并提供了一些经验总结：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;CPU密集型(CPU bound)：如果任务是CPU密集型的，那么使用并行的方式来解决问题，这样可以最大的利用CPU核心的算力。如果使用并发的方式去处理，反而会增加        &lt;u&gt;复杂度&lt;/u&gt;。&lt;/li&gt;      &lt;li&gt;I/O密集型(I/O bound)：如果任务时I/O密集型的，那么使用并发的方式来解决问题，这样可以提升单个CPU核心的吞吐量(Throughput)。&lt;/li&gt;&lt;/ul&gt;    &lt;blockquote&gt;      &lt;p&gt;并发(Concurrent)与并行(Parallel)：并发是指同时处理(dealing with)很多事情，并行是指同时做(doing)很多事情。并行是并发的特殊情况，只能在计算机多核环境中实现。&lt;/p&gt;      &lt;p&gt;同步(Sync)与异步(Async)：一种编程模型。区别在于同步是可预测(predictable)的，异步是不可预测(unpredictable)的编程模型。&lt;/p&gt;&lt;/blockquote&gt;    &lt;h2&gt;总结&lt;/h2&gt;    &lt;p&gt;本篇从操作系统的视角介绍编程语言实现并发的底层概念，包括进程调度与I/O模型等。下篇开始介绍常见的      &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/"&gt;并发模型&lt;/a&gt;。&lt;/p&gt;    &lt;div&gt;      &lt;p&gt;        &lt;strong&gt;更新日志&lt;/strong&gt;2022-04-15：根据此        &lt;a href="https://www.v2ex.com/t/846178#reply20"&gt;讨论帖&lt;/a&gt;修改更新。（感谢        &lt;a href="https://www.v2ex.com/member/lxdlam"&gt;@lxdlam&lt;/a&gt;）
2022-04-10：初稿发布。&lt;/p&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 />
      <guid isPermaLink="true">https://itindex.net/detail/62933-%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80-%E5%B9%B6%E5%8F%91-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F</guid>
      <pubDate>Sat, 07 Sep 2024 07:31:49 CST</pubDate>
    </item>
    <item>
      <title>如何发现并处理MySQL主从延迟问题</title>
      <link>https://itindex.net/detail/62863-%E5%8F%91%E7%8E%B0-mysql-%E5%BB%B6%E8%BF%9F</link>
      <description>&lt;p&gt;在 Percona MySQL 支持团队中，我们经常看到客户抱怨复制延迟的问题。当然，这对 MySQL 用户来说并不是什么新鲜事，多年来我们在 MySQL 性能博客上发表过一些关于这个主题的文章（过去有两篇特别受欢迎的文章：&amp;quot;Reasons for MySQL Replication Lag&amp;quot; 和 “Managing Slave Lag with MySQL Replication&amp;quot;），两篇文章均由 Percona 首席执行官 Peter Zaitsev 撰写）。    &lt;br /&gt; &lt;/p&gt;  &lt;p&gt;译者注：Percona 公司是做 MySQL 发行版的，MySQL 有三大发行版，MySQL、MariaDB、Percona，《高性能 MySQL》这本神作就是出自 Percona 的专家团队。&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; &lt;/p&gt;  &lt;p&gt;MySQL 复制有两个线程：IO_THREAD 和 SQL_THREAD。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;IO_THREAD 连接到 master，从 master 读取 binlog 事件，并将其复制到名为 relay log 的本地日志文件中。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;另一方面，SQL_THREAD 在从节点上读取 relay log，然后尽可能快地处理这些日志。每当复制出现延迟时，首先要弄清延迟发生在 IO_THREAD 还是 SQL_THREAD。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;通常情况下，I/O 线程不会造成巨大的复制延迟，因为它只是从主服务器读取 binlog。不过，这取决于网络连接、网络延迟……即服务器之间的速度有多快。Slave 的 I/O 线程可能会因为带宽拥塞而变慢。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;通常，当 Slave IO_THREAD 能够足够快地读取 binlog 时，就容易在 Slave 上堆积 relay log – 此时表明 Slave IO_THREAD 是没问题的。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;另一方面，如果是 Slave SQL_THREAD 导致延迟，大概率是因为来自 replication stream 的 queries 在 Slave 上执行的时间太长。可能的原因包括 Master、Slave 之间的硬件不同、索引不同、工作负载不同。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;此外，Slave OLTP 工作负载有时会因为“锁”而导致复制延迟。例如，对 MyISAM 表的长久读请求会阻塞 SQL 线程，或对 InnoDB 表的任何事务都会创建 IX 锁并阻塞 SQL 线程中的 DDL。此外，还要考虑到在 MySQL 5.6 之前，slave 是单线程的，这也是导致 Slave SQL_THREAD 出现延迟的另一个原因。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;    &lt;strong&gt;MySQL 复制延迟的例子&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;让我通过 master status / slave status 示例向您展示，以确定 Slave 延迟问题到底是由于 IO_THREAD 还是由于 SQL_THREAD。&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;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;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;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;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;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;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;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;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;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;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;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;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;pre&gt;  &lt;code&gt;mysql-master&amp;gt; SHOW MASTER STATUS;&lt;/code&gt;  &lt;code&gt;+------------------+--------------+------------------+------------------------------------------------------------------+&lt;/code&gt;  &lt;code&gt;| File | Position  | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                                                |&lt;/code&gt;  &lt;code&gt;+------------------+--------------+------------------+------------------------------------------------------------------+&lt;/code&gt;  &lt;code&gt;| mysql-bin.018196 | 15818564     |                  | bb11b389-d2a7-11e3-b82b-5cf3fcfc8f58:1-2331947                   |&lt;/code&gt;  &lt;code&gt;+------------------+--------------+------------------+------------------------------------------------------------------+&lt;/code&gt;  &lt;code&gt;mysql-slave&amp;gt; SHOW SLAVE STATUSG\G&lt;/code&gt;  &lt;code&gt;*************************** 1. row ***************************&lt;/code&gt;  &lt;code&gt;Slave_IO_State: Queueing master event to the relay log&lt;/code&gt;  &lt;code&gt;Master_Host: master.example.com&lt;/code&gt;  &lt;code&gt;Master_User: repl&lt;/code&gt;  &lt;code&gt;Master_Port: 3306&lt;/code&gt;  &lt;code&gt;Connect_Retry: 60&lt;/code&gt;  &lt;code&gt;Master_Log_File: mysql-bin.018192&lt;/code&gt;  &lt;code&gt;Read_Master_Log_Pos: 10050480&lt;/code&gt;  &lt;code&gt;Relay_Log_File: mysql-relay-bin.001796&lt;/code&gt;  &lt;code&gt;Relay_Log_Pos: 157090&lt;/code&gt;  &lt;code&gt;Relay_Master_Log_File: mysql-bin.018192&lt;/code&gt;  &lt;code&gt;Slave_IO_Running: Yes&lt;/code&gt;  &lt;code&gt;Slave_SQL_Running: Yes&lt;/code&gt;  &lt;code&gt;Replicate_Do_DB:&lt;/code&gt;  &lt;code&gt;Replicate_Ignore_DB: &lt;/code&gt;  &lt;code&gt;Replicate_Do_Table:&lt;/code&gt;  &lt;code&gt;Replicate_Ignore_Table:&lt;/code&gt;  &lt;code&gt;Replicate_Wild_Do_Table:&lt;/code&gt;  &lt;code&gt;Replicate_Wild_Ignore_Table:&lt;/code&gt;  &lt;code&gt;Last_Errno: 0&lt;/code&gt;  &lt;code&gt;Last_Error:&lt;/code&gt;  &lt;code&gt;Skip_Counter: 0&lt;/code&gt;  &lt;code&gt;Exec_Master_Log_Pos: 5395871&lt;/code&gt;  &lt;code&gt;Relay_Log_Space: 10056139&lt;/code&gt;  &lt;code&gt;Until_Condition: None&lt;/code&gt;  &lt;code&gt;Until_Log_File:&lt;/code&gt;  &lt;code&gt;Until_Log_Pos: 0&lt;/code&gt;  &lt;code&gt;Master_SSL_Allowed: No&lt;/code&gt;  &lt;code&gt;Master_SSL_CA_File:&lt;/code&gt;  &lt;code&gt;Master_SSL_CA_Path:&lt;/code&gt;  &lt;code&gt;Master_SSL_Cert:&lt;/code&gt;  &lt;code&gt;Master_SSL_Cipher:&lt;/code&gt;  &lt;code&gt;Master_SSL_Key:&lt;/code&gt;  &lt;code&gt;Seconds_Behind_Master: 230775&lt;/code&gt;  &lt;code&gt;Master_SSL_Verify_Server_Cert: No&lt;/code&gt;  &lt;code&gt;Last_IO_Errno: 0&lt;/code&gt;  &lt;code&gt;Last_IO_Error:&lt;/code&gt;  &lt;code&gt;Last_SQL_Errno: 0&lt;/code&gt;  &lt;code&gt;Last_SQL_Error:&lt;/code&gt;  &lt;code&gt;Replicate_Ignore_Server_Ids:&lt;/code&gt;  &lt;code&gt;Master_Server_Id: 2&lt;/code&gt;  &lt;code&gt;Master_UUID: bb11b389-d2a7-11e3-b82b-5cf3fcfc8f58:2-973166&lt;/code&gt;  &lt;code&gt;Master_Info_File: /var/lib/mysql/i1/data/master.info&lt;/code&gt;  &lt;code&gt;SQL_Delay: 0&lt;/code&gt;  &lt;code&gt;SQL_Remaining_Delay: NULL&lt;/code&gt;  &lt;code&gt;Slave_SQL_Running_State: Reading event from the relay log&lt;/code&gt;  &lt;code&gt;Master_Retry_Count: 86400&lt;/code&gt;  &lt;code&gt;Master_Bind:&lt;/code&gt;  &lt;code&gt;Last_IO_Error_Timestamp:&lt;/code&gt;  &lt;code&gt;Last_SQL_Error_Timestamp:&lt;/code&gt;  &lt;code&gt;Master_SSL_Crl:&lt;/code&gt;  &lt;code&gt;Master_SSL_Crlpath:&lt;/code&gt;  &lt;code&gt;Retrieved_Gtid_Set: bb11b389-d2a7-11e3-b82b-5cf3fcfc8f58:2-973166&lt;/code&gt;  &lt;code&gt;Executed_Gtid_Set: bb11b389-d2a7-11e3-b82b-5cf3fcfc8f58:2-973166,&lt;/code&gt;  &lt;code&gt;ea75c885-c2c5-11e3-b8ee-5cf3fcfc9640:1-1370&lt;/code&gt;  &lt;code&gt;Auto_Position: 1&lt;/code&gt;&lt;/pre&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;这清楚地表明，Slave IO_THREAD 滞后，显然 Slave SQL_THREAD 也因此滞后，从而导致复制延迟。正如你所看到的，Master 日志文件是 mysql-bin.018196（来自 SHOW MASTER STATUS），而 Slave IO_THREAD 在 mysql-bin.018192（来自 Slave status 的 Master_Log_File）上，这表明 Slave IO_THREAD 正在从该文件读取数据，而在 Master 上，它正在写入 mysql-bin.018196，因此 Slave IO_THREAD 落后了 4 个 binlog。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;与此同时，Slave SQL_THREAD 正在读取同一个文件，即 mysql-bin.018192（Slave status 中的 Relay_Master_Log_File），这表明 Slave SQL_THREAD 正在以足够快的速度应用事件，但它也滞后了，这可以从显示 Slave status 输出中的 Read_Master_Log_Pos 与 Exec_Master_Log_Pos 之间的差值观察到。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;show slave status 的输出中 Master_Log_File 和 Relay_Master_Log_File 值相同，我们可以根据 Read_Master_Log_Pos - Exec_Master_Log_Pos 计算 Slave SQL_THREAD 的滞后时间。这样就能大致了解 Slave SQL_THREAD 应用事件(apply event)的速度。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;如上所述，如果 Slave IO_THREAD 滞后，那么 Slave SQL_THREAD 当然也会滞后。有关显示 Slave 状态输出字段的详细说明，请点击此处。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;此外，Seconds_Behind_Master 显示了以秒为单位的巨大延迟。不过，这可能会产生误导，因为它只度量最近执行的 relay log 与最近被 IO_THREAD 下载的 relay log 条目之间的时间戳差异。如果 Master 上有更多的 relay log，Slave 并不会将它们计入 Seconds_behind_master 的计算中。你可以使用 Percona 工具包中的 pt-heartbeat 更准确地测量 Slave 日志的滞后情况。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;至此，我们学会了如何检查复制延迟——无论是 Slave IO_THREAD 还是 Slave SQL_THREAD。现在，让我来提供一些提示和建议，看看到底是什么原因导致了这种延迟。&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;通常，Slave IO_THREAD 滞后是因为主/从之间的网络速度太慢。大多数情况下，启用 Slave 压缩协议（slave_compressed_protocol）有助于缓解 Slave IO_THREAD 的滞后。还有一个建议是禁用 Slave 上的 binlog 记录，因为它也是 IO 密集型的，除非你需要它来进行时间点恢复。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;    &lt;strong&gt;要尽量减少 Slave SQL_THREAD 的滞后，重点是优化查询&lt;/strong&gt;。我的建议是启用配置选项 log_slow_slave_statements，这样 Slave 执行的耗时超过 long_query_time 的查询就会被记录到慢日志中。为了收集更多有关查询性能的信息，我还建议将配置选项 log_slow_verbosity 设置为&amp;quot;full”。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;这样，我们就能看到是否有 Slave SQL_thread 执行的查询需要很长时间才能完成。关于如何在特定时间段内使用上述选项启用慢查询日志，你可以点击这里查看我之前的文章。需要提醒的是，log_slow_slave_statements 变量是在 Percona Server 5.1 中首次引入的，现在从 5.6.11 版起已成为 Vanilla MySQL 的一部分。在上游版本的 MySQL 中，log_slow_slave_statements 被作为命令行选项引入，而 log_slow_verbosity 是 Percona Server 的特定功能。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;如果使用基于行的 binlog 格式，在 Slave SQL_THREAD 上出现延迟的另一个原因是：如果任何数据库表缺少主键或唯一键，就会在 Slave SQL_THREAD 上扫描表的所有行进行 DML，从而导致复制延迟，因此要确保所有表都有主键或唯一键。有关详细信息，请查看此错误报告 http://bugs.mysql.com/bug.php?id=53375 您可以在 Slave 上使用以下查询来确定哪些数据库表缺少主键或唯一键。&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;pre&gt;    &lt;code&gt;mysql&amp;gt; SELECT t.table_schema,t.table_name,engine&lt;/code&gt;    &lt;code&gt;FROM information_schema.tables t INNER JOIN information_schema .columns c&lt;/code&gt;    &lt;code&gt;ont.table_schema=c.table_schema and t.table_name=c.table_name&lt;/code&gt;    &lt;code&gt;GROUP BY t.table_schema,t.table_name&lt;/code&gt;    &lt;code&gt;HAVINGsum(if(column_keyin(&amp;apos;PRI&amp;apos;,&amp;apos;UNI&amp;apos;), 1,0))=0;&lt;/code&gt;&lt;/pre&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;在 MySQL 5.6 中，针对这种情况进行了一项改进，在使用内存散列的情况下，slave_rows_search_algorithms 可以解这个问题。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;请注意，当我们读取巨大的 RBR 事件时，Seconds_Behind_Master 并没有更新，因此 “滞后” 可能仅仅与此有关 – 我们还没有完成对事件的读取。例如，在基于行的复制中，庞大的事务可能会导致 Slave 端出现延迟，比如，如果你有一个 1000 万行的表，而你执行了 DELETE FROM table WHERE id &amp;lt; 5000000 操作，500 万行将被发送到 Slave 端，每一行都是单独的，速度会慢得令人痛苦。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;因此，如果必须不时地从庞大的表中删除最旧的行，那么使用分区可能是一个不错的选择，在某些工作负载中，使用 DROP 旧分区可能比使用 DELETE 更好，而且只有语句会被复制，因为这将是 DDL 操作。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;为了更好地解释这个问题，假设分区 1 保存的行的 ID 从 1 到 1000000，分区 2 的 ID 从 1000001 到 2000000，以此类推，所以与其通过语句 DELETE FROM table WHERE ID&amp;lt;=1000000 进行删除，不如执行 ALTER TABLE DROP partition1。有关更改分区操作，请查阅手册 - 也请查阅我的同事 Roman 的这篇精彩文章，其中解释了复制延迟的可能原因。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;pt-stalk 是 Percona 工具包中最优秀的工具之一，它可以在出现问题时收集诊断数据。你可以按如下方式设置 pt-stalk，这样只要出现 Slave 滞后，它就能记录诊断信息，我们随后就可以对这些信息进行分析，看看到底是什么原因导致了滞后。&lt;/p&gt;  &lt;p&gt; ------- pt-plug.sh contents&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;#!/bin/bash&lt;/code&gt;  &lt;code&gt;trg_plugin() {&lt;/code&gt;  &lt;code&gt;mysqladmin $EXT_ARGV ping &amp;amp;&amp;gt; /dev/null&lt;/code&gt;  &lt;code&gt;mysqld_alive=$?&lt;/code&gt;  &lt;code&gt;if [[ $mysqld_alive == 0 ]]&lt;/code&gt;  &lt;code&gt;then&lt;/code&gt;  &lt;code&gt;seconds_behind_master=$(mysql $EXT_ARGV -e &amp;quot;show slave status&amp;quot; --vertical | grep Seconds_Behind_Master | awk &amp;apos;{print $2}&amp;apos;)&lt;/code&gt;  &lt;code&gt;echo $seconds_behind_master&lt;/code&gt;  &lt;code&gt;else&lt;/code&gt;  &lt;code&gt;echo 1&lt;/code&gt;  &lt;code&gt;fi&lt;/code&gt;  &lt;code&gt;}&lt;/code&gt;  &lt;code&gt;# Uncomment below to test that trg_plugin function works as expected&lt;/code&gt;  &lt;code&gt;#trg_plugin&lt;/code&gt;  &lt;code&gt;-------&lt;/code&gt;  &lt;code&gt;-- That&amp;apos;s the pt-plug.sh file you would need to create and then use it as below with pt-stalk:&lt;/code&gt;  &lt;code&gt;$ /usr/bin/pt-stalk --function=/root/pt-plug.sh --variable=seconds_behind_master --threshold=300 --cycles=60 --notify-by-email=muhammad@example.com --log=/root/pt-stalk.log --pid=/root/pt-stalk.pid --daemonize&lt;/code&gt;&lt;/pre&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;你可以调整阈值，目前是 300 秒，结合 -cycles 选项，这意味着如果 seconds_behind_master 值大于等于 300，持续 60 秒或更长时间，pt-stalk 就会开始捕获数据。添加 --notify-by-email 选项后，pt-stalk 捕获数据时就会通过电子邮件通知。你可以相应调整 pt-stalk 的阈值，这样它就会在问题发生时触发采集诊断数据。&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;滞后 Slave 是一个棘手的问题，但也是 MySQL 复制中的常见问题。在这篇文章中，我试图涵盖 MySQL 复制 Slave 延迟的大多数方面。如果你知道复制延迟的其他原因，请在评论区与我分享。&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 />
      <guid isPermaLink="true">https://itindex.net/detail/62863-%E5%8F%91%E7%8E%B0-mysql-%E5%BB%B6%E8%BF%9F</guid>
      <pubDate>Fri, 13 Oct 2023 13:53:30 CST</pubDate>
    </item>
    <item>
      <title>​5万多中国人研究发现：有这个习惯的人，不容易得癌症</title>
      <link>https://itindex.net/detail/62794-%E4%B8%AD%E5%9B%BD%E4%BA%BA-%E7%A0%94%E7%A9%B6-%E5%8F%91%E7%8E%B0</link>
      <description>&lt;div&gt;  &lt;p&gt;▎药明康德内容团队编辑&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;中国是名副其实的“  &lt;strong&gt;癌症大国&lt;/strong&gt;”。  &lt;br /&gt;  &lt;p&gt;世界卫生组织国际癌症研究机构（IARC）发布的全球癌症负担数据显示，2020年全球新发癌症   &lt;strong&gt;1929万例&lt;/strong&gt;，导致   &lt;strong&gt;996万&lt;/strong&gt;人死亡。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;其中，   &lt;strong&gt;23.7%&lt;/strong&gt;（457万）的新发癌症和   &lt;strong&gt;30.2%&lt;/strong&gt;（300万）的癌症死亡发生在中国，   &lt;strong&gt;肺癌&lt;/strong&gt;是第一大“杀手”。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;对于中国人来讲，该怎样降低患癌症，尤其是肺癌的风险呢？一项发表在   &lt;em&gt;International Journal of Behavioral Nutrition and Physical Activity&lt;/em&gt;、涉及5万多名中国人的研究发现，   &lt;strong&gt;多进行身体活动与癌症风险降低有关，包括整体患癌、肺癌和结直肠癌&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;来自江苏省疾病预防控制中心和南京医科大学等机构的研究人员，对中国慢性病前瞻性研究（CKB）的数据进行了分析，共纳入了   &lt;strong&gt;52938名30-79岁&lt;/strong&gt;的参与者。参与者在加入研究时都没有患癌症，平均年龄是   &lt;strong&gt;52.1岁&lt;/strong&gt;，58.0%为女性。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;CKB项目由中国医学科学院与英国牛津大学联合在中国10个省（区）开展，共涉及51万余人，目的是从   &lt;strong&gt;遗传、环境和生活方式&lt;/strong&gt;等多个环节深入研究   &lt;strong&gt;危害中国人群健康的各类重大慢性病的致病因素、发病机理及流行规律和趋势&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;通过调查问卷，研究人员统计了参与者的身高、体重等   &lt;strong&gt;基本健康信息&lt;/strong&gt;；新鲜蔬果、红肉等不同食物的食用量，婚姻状况，吸烟状态，饮酒量，身体活动量等   &lt;strong&gt;生活方式信息&lt;/strong&gt;；癌症   &lt;strong&gt;家族史&lt;/strong&gt;信息；以及随访期间   &lt;strong&gt;不同类型癌症&lt;/strong&gt;的患病信息。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;统计结果显示，   &lt;strong&gt;25.1%&lt;/strong&gt;有癌症家族史；与身体活动量最少的1/4参与者相比，   &lt;strong&gt;身体活动量最多的1/4参与者&lt;/strong&gt;，大多是男性和年轻人，他们也不容易发生超重或肥胖。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;在长达   &lt;strong&gt;10年&lt;/strong&gt;多的随访期间，   &lt;strong&gt;共新发癌&lt;/strong&gt;   &lt;strong&gt;症3674例&lt;/strong&gt;，其中胃癌794例、肺癌722例、结直肠癌458例、肝癌338例、乳腺癌250例、食管癌231例。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;刨除其它因素影响后，研究人员发现   &lt;strong&gt;多进行身体活动与参与者癌症风险降低有关&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;与身体活动量最少的1/4参与者相比，   &lt;strong&gt;身体活动量最多的1/4参与者&lt;/strong&gt;：&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;    &lt;p&gt;     &lt;strong&gt;整体患癌&lt;/strong&gt;风险降低11%；&lt;/p&gt;&lt;/li&gt;   &lt;li&gt;    &lt;p&gt;     &lt;strong&gt;肺癌和结直肠癌&lt;/strong&gt;患病风险分别降低25%和26%；&lt;/p&gt;&lt;/li&gt;   &lt;li&gt;    &lt;p&gt;     &lt;strong&gt;其它类型癌症&lt;/strong&gt;风险也略有降低，但并不明显。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;身体活动量每增加   &lt;strong&gt;15.2MET-小时/天&lt;/strong&gt;，分别与整体患癌风险降低5%，以及肺癌和结直肠癌风险降低11%和14%相关。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;研究结果还显示，身体活动量对参与者   &lt;strong&gt;整体患癌&lt;/strong&gt;风险的影响，在   &lt;strong&gt;女性和不吸烟&lt;/strong&gt;的参与者中更显著：&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;    &lt;p&gt;在     &lt;strong&gt;男性和女性&lt;/strong&gt;中，分别与身体活动量最少的1/4参与者相比，身体活动量最多的1/4参与者，     &lt;strong&gt;整体患癌风险分别降低5%和8%&lt;/strong&gt;。&lt;/p&gt;&lt;/li&gt;   &lt;li&gt;    &lt;p&gt;在     &lt;strong&gt;从不吸烟和曾经吸烟&lt;/strong&gt;的参与者中，分别与身体活动量最少的1/4参与者相比，身体活动量最多的1/4参与者，     &lt;strong&gt;整体患癌风险分别降低7%和5%&lt;/strong&gt;。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;研究人员分析，身体活动与癌症风险降低之间的关联可能与多种因素有关。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;首先，较高的身体活动量   &lt;strong&gt;与较低水平&lt;/strong&gt;的胰岛素样生长因子（IGF）-1、空腹血糖以及较高水平的胰岛素样生长因子结合蛋白（IGFBP）-3有关。这意味着   &lt;strong&gt;身体活动可以通过改善胰岛素敏感性和葡萄糖代谢来降低患癌风险&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;其次，多项研究发现性激素与多种癌症的发生、发展有关。而较高的身体活动可以   &lt;strong&gt;通过增加性激素结合球蛋白&lt;/strong&gt;（SHBG）   &lt;strong&gt;的水平来调节性激素水平&lt;/strong&gt;，进而降低患癌风险。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;第三，身体活动可能会   &lt;strong&gt;改变炎症细胞因子或脂肪因子&lt;/strong&gt;（例如，C-反应蛋白、脂联素和白细胞介素-6），进而   &lt;strong&gt;降低全身炎症水平&lt;/strong&gt;，这也有助于降低患癌风险。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;此外，身体活动还可能通过   &lt;strong&gt;减少氧化应激、增加肺通气量、增加迷走神经张力、缩短肠道转运时间&lt;/strong&gt;等，降低患癌风险。不过相关机制还没有明确，还需要更多研究探索。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;需要注意的是，这项研究是观察性研究，   &lt;strong&gt;只是显示了身体活动量与癌症风险之间的关联，并没有表明因果关系&lt;/strong&gt;。而且研究也存在一些局限性，如部分数据依赖参与者回忆等，可能也会对研究结果产生影响。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;研究最后指出，近几十年来，   &lt;strong&gt;中国人的生活方式发生变化，久坐不动的人越来越多&lt;/strong&gt;。据统计，有31.0%的中国人没有达到推荐的身体活动量，即每周至少150分钟的中等强度或至少75分钟的高强度身体活动，或者两者的等量结合。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;癌症是导致中国人健康和寿命受损的主要原因之&lt;/strong&gt;一。这项研究提示我们，   &lt;strong&gt;应增加身体活动量，以降低患癌风险&lt;/strong&gt;。除此以外，多进行身体活动还有助于降低心血管疾病、糖尿病等疾病的发生、发展以及死亡风险。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;根据IARC建议，   &lt;strong&gt;想要降低患癌风险，除了要多进行身体活动外，还应做到以下几方面&lt;/strong&gt;：&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;不吸烟，不使用任何形式烟草&lt;/strong&gt;。除了肺癌，吸烟还会增加17种不同类型癌症的风险，包括泌尿生殖系统癌症、头颈部癌症、消化系统癌症，以及造血系统癌症等。&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;    &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;远离二手烟&lt;/strong&gt;。二手烟，是儿童、女性和不吸烟的成年人患肺癌的危险因素，里面含有超过4000种有害物质，比如焦油、尼古丁、苯丙芘、一氧化碳、甲醛等，其中很多都已经被证实是致癌物质。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;保持健康体重&lt;/strong&gt;。超重或肥胖、体内脂肪过多，可能会改变性激素（雌激素或睾丸激素）水平、导致胰岛素水平升高、引发炎症等，进而增加十多种癌症风险。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;健康饮食&lt;/strong&gt;。食物多样，谷类为主；多吃蔬果、奶类、大豆；适量吃坚果、鱼、禽、蛋和瘦肉；不吃加工肉类；限制红肉和肥肉；少盐少油，不喝或少喝含糖饮料。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;不饮酒&lt;/strong&gt;。酒精进入身体后，会产生有毒化学物质（1类致癌物乙醛），直接破坏细胞DNA和蛋白质；还会增加某些激素的水平，增加癌症风险。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;保护皮肤免受紫外线照射&lt;/strong&gt;。避免中午晒太阳；即使是多云天气，去户外时也要涂抹广谱防晒霜；外出时要穿好防晒装备；不使用室内紫外线日光浴设备。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;减少环境致癌物暴露&lt;/strong&gt;。避免接触砷、石棉、铅、辐射、苯和室外空气污染等。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;母乳喂养和谨慎使用激素替代疗法&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;接种疫苗和预防感染&lt;/strong&gt;。全球近五分之一的癌症是由病毒、细菌等持续感染引起的，包括人乳头瘤病毒（HPV）、乙型肝炎病毒（HBV）、丙型肝炎病毒（HCV）和幽门螺杆菌。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;进行癌症筛查&lt;/strong&gt;。筛查可以在早期发现某些癌症，此时治疗更有效。对于一些癌症，也有癌前病变阶段，可以通过筛查早发现、早治疗，以防止癌症发展。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;参考资料&lt;/p&gt;  &lt;p&gt;[1] Jian Su,et al.,(2022). Association between physical activity and cancer risk among Chinese adults: a 10-year prospective study. International Journal of Behavioral Nutrition and Physical Activity,DOI: 10.1186/s12966-022-01390-1.&lt;/p&gt;  &lt;p&gt;[2] Latest global cancer data: Cancer burden rises to 19.3 million new cases and 10.0 million cancer deaths in 2020. Retrieved Jun 20,2023,from https://www.iarc.fr/fr/news-events/latest-global-cancer-data-cancer-burden-rises-to-19-3-million-new-cases-and-10-0-million-cancer-deaths-in-2020/&lt;/p&gt;  &lt;p&gt;[3] Find out more about the 12 ways recommendations. Retrieved Jun 20,2023,from https://cancer-code-europe.iarc.fr/index.php/en/ecac-12-ways&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;免责声明：药明康德内容团队专注介绍全球生物医药健康研究进展。本文仅作信息交流之目的，文中观点不代表药明康德立场，亦不代表药明康德支持或反对文中观点。本文也不是治疗方案推荐。如需获得治疗方案指导，请前往正规医院就诊。  &lt;p&gt;&lt;/p&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 />
      <guid isPermaLink="true">https://itindex.net/detail/62794-%E4%B8%AD%E5%9B%BD%E4%BA%BA-%E7%A0%94%E7%A9%B6-%E5%8F%91%E7%8E%B0</guid>
      <pubDate>Tue, 27 Jun 2023 15:29:24 CST</pubDate>
    </item>
    <item>
      <title>科学家发现柠檬汁干预结石形成的原因</title>
      <link>https://itindex.net/detail/62666-%E7%A7%91%E5%AD%A6%E5%AE%B6-%E5%8F%91%E7%8E%B0-%E6%9F%A0%E6%AA%AC%E6%B1%81</link>
      <description>肾结石是容易复发的常见病，最常见的肾结石种类是草酸钙（CaOx）结石。有证据表明，定期饮用柠檬汁可以干预结石的发展，但其原理尚不清楚。南京中医药大学研究人员在《Nano Letters》期刊上发表的论文，揭示了背后的机制。柠檬汁的有效成分是类囊泡纳米粒子，他们发现，柠檬类囊泡可以阻断草酸钙结石诱导的细胞内质网应激反应，将受激的胞内钙信号恢复稳态而不会影响正常的细胞状态，间接抑制了结石形成。该研究为临床口服柠檬汁防治肾结石的可行性提供了实验证据。
 &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 />
      <guid isPermaLink="true">https://itindex.net/detail/62666-%E7%A7%91%E5%AD%A6%E5%AE%B6-%E5%8F%91%E7%8E%B0-%E6%9F%A0%E6%AA%AC%E6%B1%81</guid>
      <pubDate>Tue, 07 Mar 2023 15:34:20 CST</pubDate>
    </item>
    <item>
      <title>一款学生开发的游戏，戳穿了当下年轻人的残酷现实 - 游研社</title>
      <link>https://itindex.net/detail/62462-%E5%AD%A6%E7%94%9F-%E5%BC%80%E5%8F%91-%E6%B8%B8%E6%88%8F</link>
      <description>&lt;div&gt;    &lt;blockquote&gt;      &lt;strong&gt;2022年以来听到最扎心的一句话：‘你失去了梦想，但变成了他们想要的样子。’&lt;/strong&gt;&lt;/blockquote&gt;    &lt;p&gt;pupu很小的时候就在玩游戏了。&lt;/p&gt;    &lt;p&gt;她在上小学的时候就拥有了一台自己的PSP，并因此接触过上个掌机时代的许多优秀作品，这是她游戏生涯的启蒙，甚至还因为总偷偷在被窝玩导致近视加重了些。&lt;/p&gt;    &lt;p&gt;那时她最喜欢的一款作品叫《美少女梦工厂5》，年纪太小她不知道怎么下载汉化版本，也理所当然的读不懂日文。但这款游戏依旧深深地吸引了她，靠着边学边猜边查字典，身为小学生的她硬生生的打通了这款游戏。&lt;/p&gt;    &lt;p&gt;十多年后，pupu依旧清晰地记着这个场景，她就是从这款游戏开始，产生了      &lt;strong&gt;“我长大后也要做游戏！”&lt;/strong&gt;的冲动。&lt;/p&gt;    &lt;p&gt;而这冲动延续到现在，      &lt;strong&gt;pupu正就读于美国卡耐基梅隆大学娱乐技术专业进行硕士深造&lt;/strong&gt;，这是当今地球上最好的、专为培养游戏开发人才的学府圣地之一。在本专业之外，学校总共诞生过15位诺奖得主，连李开复都算不上校友里最出名的那一批人。&lt;/p&gt;    &lt;p&gt;回顾玩《美少女梦工厂5》时激动的心情，pupu说：&lt;/p&gt;    &lt;p&gt;“游戏的魅力和趣味可以跨越语言的障碍，激励玩家不断的去学习和掌握，真是一件很奇妙的事。而且当时国内比较缺少这种女性向游戏。如果更多玩家能感受到游戏的这份魅力就好了。”&lt;/p&gt;    &lt;p&gt;《美少女梦工厂5》&lt;/p&gt;    &lt;p&gt;“      &lt;strong&gt;只是那时我太小还不知道，「做游戏」这件事究竟有多难。&lt;/strong&gt;”&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;2&lt;/strong&gt;&lt;/p&gt;    &lt;h1&gt;刘小宇是个很乖的孩子。&lt;/h1&gt;    &lt;br /&gt;初三的他，正每天都很努力的学习，但爸爸妈妈还有很高的期待，总对他说：“学习好，才有好未来。”这是绝大多数中国家长的正常想法，伴随着“望子成龙”“学以至仕”这样最朴素的愿望，他们希望孩子好一点，再好一点，去见识他们不曾经历的山海的模样。    &lt;p&gt;“可是，可是....”刘小宇想，      &lt;strong&gt;“我想要的....似乎不是他们口中的那种未来.....？”&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;唉，别多想了，写作业吧先，省的爸妈又来唠叨。&lt;/p&gt;    &lt;p&gt;睁开双眼，刘小宇身处于自己家中，墙上密密麻麻的贴着大小不一的各种奖状，游戏机锁在靠墙的玻璃柜里，与几排教辅书《5年中考3年模拟》放在一起。私自带回的小猫不见了，客厅里只剩下它住过的纸箱还没扔，妈妈说是它自己偷跑出门的.....这么小一只猫，也知道离家出走吗？刘小宇不明白。&lt;/p&gt;    &lt;p&gt;      &lt;img height="500" width="500"&gt;&lt;/img&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;/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;/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;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;3&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;和刘小宇很像，pupu从小也是个学习较好、自我感觉让父母挺省心的孩子。不过，虽然符合了父母和身边长辈的期许，      &lt;strong&gt;但其实pupu悄悄的也有了自己的一点小心思&lt;/strong&gt;。&lt;/p&gt;    &lt;p&gt;因为父母管得严，升到初二之后，pupu再想打游戏基本就成了奢望。但这并没有挡住她的热情，即便玩不到，她偶尔也会处于自己幻想的小世界中。&lt;/p&gt;    &lt;p&gt;pupu也有个写游戏创意的涂鸦本子，有时会趁上课走神的功夫偷偷写点幻想中的剧情，有时会在课本上把历史人物涂鸦成自己幻想中的角色——很多人小时候都这么干过。晚上写作业时，pupu会尽快写完，然后偷偷看会儿喜欢的游戏视频。甚至、甚至，母亲总以为她每次洗澡都要花一个小时磨磨唧唧的，但其实pupu并没有洗澡，只是打开花洒掩盖偷偷玩游戏的声响罢了。&lt;/p&gt;    &lt;p&gt;pupu自小酷爱各种模拟经营游戏，抛开《美少女梦工厂》不谈，《双点医院》、《模拟人生》系列、以及一些更古早的作品比如《中华客栈》都是她的心头好。在这些游戏中，尚未长大的她仿佛短时间内经历了一遍他人的人生，尝试过各种产业、身份、境遇，这让她深深感受到了“游戏”这种媒介伴随的乐趣，和区别于其他媒介的高自由度、沉浸感。&lt;/p&gt;    &lt;p&gt;      &lt;img height="480" width="640"&gt;&lt;/img&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;因此，临近高中毕业时，pupu郑重的与父母就自己的愿望展开了多次会谈。&lt;/p&gt;    &lt;p&gt;pupu的父母是相对比较开明的人，但他们也几乎完全不了解电子游戏到底是什么，身边朋友和社会上的言论让他们对游戏有着较深的忌讳。pupu用尽了十几年来积攒的智慧，一遍遍向父母阐述游戏的正面价值、自己的热爱所在、以及当下国内外游戏行业发展较好的前景。最终他们选择尊重女儿的意愿，同意pupu去报考“游戏专业”——毕竟去往大型互联网公司就业也不错，虽不是老师、医生什么的，但时代变了嘛，有稳定高薪就行。&lt;/p&gt;    &lt;p&gt;其实相比于在大型游戏公司上班，pupu更倾向于去做自由自在（但收入不稳）的独立游戏——但她没敢告诉父母——不过这已经是了不起的第一步了。&lt;/p&gt;    &lt;p&gt;那时是pupu最快乐的日子之一，她一直期盼自己所向往的能得到家人的支持和理解。怀着这样的信念，pupu踏上了飞越大洋的飞机，去往了美国。&lt;/p&gt;    &lt;p&gt;她希望未来自己能亲身参与一些最喜欢的模拟类游戏的创作。而在大学期间，pupu终于找到了一个这样的机会。&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;4&lt;/strong&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;strong&gt;是他主动提出要走的&lt;/strong&gt;，契机是最近的职级晋升失败。确实，确实，刘小宇工作够努力，水平也没得说，甚至在面谈中，上级都直白的告诉他“你干得很不错”。但是，但是，“哎呀，你也知道最近两年的大环境，不裁员就谢天谢地了，哪还能有升职的呢？”&lt;/p&gt;    &lt;p&gt;“盘子就那么大，有人涨薪就有人要降薪甚至被辞退....你也不希望因为一己私欲让朋友同事卷铺盖走人吧？”PUA，又见PUA。&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;&lt;/p&gt;    &lt;p&gt;但现在刘小宇冲不动了。就在此刻，他刚从上级的办公室出来，内心对前途充满绝望。老实说他一开始就不喜欢现在的工作，只是顺着父母的安排一路做下来了。在这过程中他每天忙到两脚不沾地、水都来不及喝一口，但这些家人并不知道，只觉着他有份体面的工作就行。&lt;/p&gt;    &lt;p&gt;就在刚刚的谈话结尾，上级对他说：&lt;/p&gt;    &lt;p&gt;      &lt;img height="162" width="369"&gt;&lt;/img&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;。他想起小时候画满了游戏创意的涂鸦本子，大学时与同学做了一半的demo至今还藏在硬盘某个角落，刘小宇确信demo总有一天会成为一个真正的游戏.....&lt;/p&gt;    &lt;p&gt;或许现在是时候了。&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;5&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;pupu求学时，国内游戏行业虽然早已兴起，但还没什么游戏专业，所以出国学习是她最好的选择。      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;pupu当下正在读研的「美国卡耐基梅隆大学」，国内一般玩家可能比较陌生，但提到她本科学校      &lt;strong&gt;「美国南加州大学」&lt;/strong&gt;听说过得人应该就很多了。pupu在这学的是计算机游戏专业，也是声名在外的“世界第一游戏专业”所在。      &lt;strong&gt;《光遇》《风之旅人》制作人陈星汉就毕业于该学校&lt;/strong&gt;，B站一些游戏UP主如@白痴毛、@魔王酱maou_、@渗透之C菌，也都曾或正在这所学校就读。&lt;/p&gt;    &lt;p&gt;      &lt;img height="360" width="352"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;虽然因碰上疫情，将近两年半的时间只能参与线上课程，但pupu的校园生活已经顶幸运了。&lt;/p&gt;    &lt;p&gt;她遇到了许多志同道合、同样热爱游戏的同学一起创作，除了游戏开发与设计的专业课程外，学校还有一些游戏类社团可以加入。就比如每学期大伙一起脑暴选题创作个游戏、时常聚在一起讨论玩法的桌游评鉴社、亦或是密室逃脱社团，每年做几个密室节日时以供同学们体验。学校游戏创作氛围很好，pupu度过了相当快乐的时光。&lt;/p&gt;    &lt;p&gt;相比于国内，pupu觉着美国对待「独立游戏」更加鼓励和包容，这里没有国内一般社会上对游戏的尖锐矛盾对立，很多游戏不止会考虑到游戏性，还会作为创作者映射、表达观点的媒介，或对某些社会现象发声。&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;就比如本科期间，pupu终于参与到的一款心心念念的模拟类游戏创作。&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;这是一款“种田”游戏，但和大多种田游戏不同，玩家在游戏里扮演的不再是善良淳朴的村民，而是遭人类厌恶的怪物一族。怪物们对人类完全没有恶意，但却总是会遭受一些偏见、甚至某些激进派人类的攻打。在此过程中玩家要做的，就是帮助怪物伙伴解决困难，彼此扶持着建设家园。&lt;/p&gt;    &lt;p&gt;      &lt;img height="608" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img height="608" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img height="810" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;用游戏里的怪物遭遇，来映射现实美国社会上的歧视和对立问题&lt;/strong&gt;，这也太酷了吧！pupu很高兴能参与到这样一个项目，作为社会问题的反抗者，用自己的游戏去一点点改变世界的状况，她觉着这种方式既新鲜又很有意义。&lt;/p&gt;    &lt;p&gt;      &lt;img height="608" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;“真是充满梦幻的玫瑰色校园生活呐！”&lt;/p&gt;    &lt;p&gt;或许也正是受这段经历影响，后来，当有一天pupu也站到了游戏制作人的位置上，      &lt;strong&gt;一个大胆的企划在她心中萌芽而生。&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;        &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;6&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;“要和父母摊牌吗？”&lt;/strong&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;不同于快乐学习的pupu，人生重要的十字路口，刘小宇面临了不得不跨破的抉择。&lt;/p&gt;    &lt;p&gt;关上房门，刘小宇躺在床上愣愣的看着天花板，真想就这么栽过去啊~睡到自然醒~。房间另一侧的桌子上，电脑正显示着一行行代码，这就是他偷偷在做的游戏demo，偶尔爸爸妈妈也会撞见他捣鼓这些代码，但看不懂是什么所以也没过问。&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;&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;不同于父母的不理解，女友的烦恼有更多现实层面的思考。相比于上班，自己做游戏并不是件有稳定回报的事，全身心投入开发，做了几年，不断思考、测试、迭代的作品，最终或许也并不赚钱。&lt;/p&gt;    &lt;p&gt;但生活是有稳定支出的，女友也只是个刚毕业没几年的普通人，考虑到车子、房子、还有以后的小孩.....女友不敢想，她觉着刘小宇是拿他们的人生在赌。&lt;/p&gt;    &lt;p&gt;      &lt;img height="810" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img height="384" width="1080"&gt;&lt;/img&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;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;        &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;7&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;em&gt;“所以刘小宇接下来怎么样了？他真去做游戏了吗？成功了吗？”&lt;/em&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;em&gt;“主角性格也太刚了吧？忍一忍，先摸摸鱼工作，等两年，慢慢做游戏不好吗？”&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;      &lt;em&gt;“希望作者给主角安排一个好的结局。我已经放弃了，希望游戏里的他别再放弃了😢。期待完成版！加油加油！”&lt;/em&gt;&lt;/p&gt;    &lt;hr&gt;&lt;/hr&gt;    &lt;p&gt;打开游戏商店网页，玩家的各种评论浮现在眼前，pupu满脸兴奋。她自己也没意料到，完成度这么低的一个游戏demo居然收获了不错的评价，很多玩家沉浸到了刘小宇的故事中，并获得了共情。&lt;/p&gt;    &lt;p&gt;      &lt;img height="593" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;是的，      &lt;strong&gt;刘小宇是一个虚拟角色，他来自2N工作室游戏《听我说》，而制作人正是pupu&lt;/strong&gt;。&lt;/p&gt;    &lt;p&gt;作为一个游戏角色，刘小宇有着既定的结局、要走的道路，他的所作所为、经历的一切，都是开发者自身的映射。但他自己不知道这些。&lt;/p&gt;    &lt;p&gt;作为一个少见的“游戏专业”学生，pupu将自己人生经历的切片裁剪了出来，润色出刘小宇的故事。而2N工作室其他成员也对刘小宇投射了情感，他们以自己的亲身经历为媒，共同捏塑了这个角色。&lt;/p&gt;    &lt;p&gt;虽然成长路径风格完全不同，但某种程度上说，pupu和刘小宇其实是同一个人。&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;pupu有着五光十色的校园生活，而受尽艰难苦苦求索的刘小宇，则是她人生另一面的写照。&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img height="260" width="506"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;“小猫也会离家出走吗？”&lt;/p&gt;    &lt;p&gt;      &lt;img height="260" width="506"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;“我看是被你带坏的吧！”&lt;/p&gt;    &lt;p&gt;      &lt;img height="260" width="506"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;“你还年轻，好好干未来有的是机会。”&lt;/p&gt;    &lt;p&gt;      &lt;img height="260" width="506"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;“没有困难的工作，只有勇敢的狗勾！”&lt;/p&gt;    &lt;p&gt;      &lt;img width="height="&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;“做游戏能当饭吃？”&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;2N工作室是由一群大学生临近毕业时组成的团队，《听我说》是他们利用课外时间做的游戏。&lt;/strong&gt;今年年初，他们中一些人看到了腾讯GWB独立游戏大奖赛的消息，然后一些同学、朋友、朋友的朋友自发组织了起来，“我们也要参赛！”“冇错冇错！没游戏我们就现成做一个！”&lt;/p&gt;    &lt;p&gt;说干就干，分散在杭州、合肥、匹兹堡、洛杉矶和纽约的一群人很快拉起了线上会议，每个人都提一些想做的项目，所有人共同参与投票。最终，pupu的提案获得了大家的一致认可，她想做一款“      &lt;strong&gt;描绘独立游戏创业过程的，伴随「玫瑰」和「荆棘」的游戏&lt;/strong&gt;”      &lt;strong&gt;。&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;然后时间又过三个月，这提案变成了我们可以试玩的游戏demo，《听我说》。&lt;/p&gt;    &lt;p&gt;      &lt;img height="293" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;本质上说，《听我说》是一款像素画风、重叙事的      &lt;strong&gt;弹幕射击游戏&lt;/strong&gt;（没想到吧！），并且还融入了些      &lt;strong&gt;roguelike要素&lt;/strong&gt;。&lt;/p&gt;    &lt;p&gt;目前游戏开发进度约30%，讲述了主人公刘小宇前半段人生，      &lt;strong&gt;从按部就班的学习、工作，到逐渐产生反抗意识，并决心辞去工作，加入独立游戏行业，创作自己所热爱的游戏的故事。&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img height="600" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;游戏一共9个章节，但目前试玩版仅有前四章的部分剧情，这也是我们前面故事戛然而止的原因。每个章节游戏都分为“场景探索阶段”和“战斗阶段”，玩家通过前期场景探索获取装备道具、经历故事剧情、发现有关主角刘小宇的生活线索，再以此为凭借参与后续各种      &lt;strong&gt;“由言语组成的战斗”。&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;每个章节的结尾都伴随着一场激烈的「语言冲突」。在游戏中，这一次次的言语冲突被具象化为了战斗场景，坚持一定时间或达成通关条件才能进入下一个章节。&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#21016;&amp;#23567;&amp;#23431;&amp;#22312;&amp;#20844;&amp;#21496;&amp;#37324;&amp;#30340;&amp;#22330;&amp;#26223;&amp;#65292;&amp;#20276;&amp;#38543;&amp;#30528;&amp;#20919;&amp;#28448;&amp;#21516;&amp;#20107;&amp;#20204;&amp;#30340;&amp;#20919;&amp;#22066;&amp;#28909;&amp;#35773;" height="599" title="&amp;#21016;&amp;#23567;&amp;#23431;&amp;#22312;&amp;#20844;&amp;#21496;&amp;#37324;&amp;#30340;&amp;#22330;&amp;#26223;&amp;#65292;&amp;#20276;&amp;#38543;&amp;#30528;&amp;#20919;&amp;#28448;&amp;#21516;&amp;#20107;&amp;#20204;&amp;#30340;&amp;#20919;&amp;#22066;&amp;#28909;&amp;#35773;" width="1080"&gt;&lt;/img&gt;刘小宇在公司里的场景，伴随着冷漠同事们的冷嘲热讽&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#21016;&amp;#23567;&amp;#23431;&amp;#36973;&amp;#21463;&amp;#22899;&amp;#21451;&amp;#30340;&amp;#25335;&amp;#38382;" height="605" title="&amp;#21016;&amp;#23567;&amp;#23431;&amp;#36973;&amp;#21463;&amp;#22899;&amp;#21451;&amp;#30340;&amp;#25335;&amp;#38382;" width="1080"&gt;&lt;/img&gt;刘小宇遭受女友的拷问&lt;/p&gt;    &lt;p&gt;“谁不辛苦呢？为了我们的未来你忍忍吧！”      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;和我们一般理解中的“弹幕射击”不同，在《听我说》中，玩家面对的是      &lt;strong&gt;“文字弹幕”&lt;/strong&gt;。&lt;/p&gt;    &lt;p&gt;当被这些负面气息满满的弹幕击中时，刘小宇不仅生命值会下降，      &lt;strong&gt;“热情、自信、决心”三项核心属性也会受到一定损害&lt;/strong&gt;。而伴随着核心属性损害，玩家还会受到“移动速度缓慢”、“防御力减弱”等debuff——就如同我们真实生活中，受到质疑和嘲讽时那样。&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#25991;&amp;#23383;&amp;#24377;&amp;#24149;&amp;#65292;&amp;#31171;&amp;#22836;&amp;#29256;&amp;#33433;&amp;#20848;&amp;#26421;&amp;#38706;&amp;#21644;&amp;#20182;&amp;#8220;&amp;#31105;&amp;#24524;&amp;#30340;&amp;#22235;&amp;#37325;&amp;#23384;&amp;#22312;&amp;#8221;" height="603" title="&amp;#25991;&amp;#23383;&amp;#24377;&amp;#24149;&amp;#65292;&amp;#31171;&amp;#22836;&amp;#29256;&amp;#33433;&amp;#20848;&amp;#26421;&amp;#38706;&amp;#21644;&amp;#20182;&amp;#8220;&amp;#31105;&amp;#24524;&amp;#30340;&amp;#22235;&amp;#37325;&amp;#23384;&amp;#22312;&amp;#8221;" width="1080"&gt;&lt;/img&gt;文字弹幕，秃头版芙兰朵露和他“禁忌的四重存在”&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#28216;&amp;#25103;&amp;#23646;&amp;#24615;&amp;#20540;&amp;#21644;&amp;#35013;&amp;#22791;" height="606" title="&amp;#28216;&amp;#25103;&amp;#23646;&amp;#24615;&amp;#20540;&amp;#21644;&amp;#35013;&amp;#22791;" width="1080"&gt;&lt;/img&gt;游戏属性值和装备&lt;/p&gt;    &lt;p&gt;这使得整个游戏过程其实相当艰难。抛开较高的操作难度不谈，游戏剧情和表达营造的困境更令人痛苦，是一段      &lt;strong&gt;不同于魂like的、在精神上饱受折磨的“受苦”体验。&lt;/strong&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img height="234" width="460"&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;p&gt;      &lt;img height="613" width="1080"&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;p&gt;      &lt;img alt="&amp;#31532;&amp;#20108;&amp;#31456;&amp;#25112;&amp;#26007;&amp;#22330;&amp;#26223;" height="599" title="&amp;#31532;&amp;#20108;&amp;#31456;&amp;#25112;&amp;#26007;&amp;#22330;&amp;#26223;" width="1080"&gt;&lt;/img&gt;第二章战斗场景&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#31532;&amp;#20108;&amp;#31456;&amp;#25112;&amp;#26007;&amp;#22330;&amp;#26223;" height="599" title="&amp;#31532;&amp;#20108;&amp;#31456;&amp;#25112;&amp;#26007;&amp;#22330;&amp;#26223;" width="1080"&gt;&lt;/img&gt;第二章战斗场景&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#31532;&amp;#19977;&amp;#31456;&amp;#25112;&amp;#26007;&amp;#22330;&amp;#26223;" height="278" title="&amp;#31532;&amp;#19977;&amp;#31456;&amp;#25112;&amp;#26007;&amp;#22330;&amp;#26223;" width="522"&gt;&lt;/img&gt;第三章战斗场景&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#31532;&amp;#22235;&amp;#31456;&amp;#25112;&amp;#26007;&amp;#22330;&amp;#26223;" height="311" title="&amp;#31532;&amp;#22235;&amp;#31456;&amp;#25112;&amp;#26007;&amp;#22330;&amp;#26223;" width="522"&gt;&lt;/img&gt;第四章战斗场景&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;在游戏设计过程中，对《听我说》影响最大的参考来源是《传说之下》，虽然其游戏内的弹幕攻击和《听我说》的语言弹幕表达形式有所不同，但      &lt;strong&gt;《传说之下》每个人物的攻击形式都能强烈体现出人物特征这点，是2N工作室希望极力学习还原的&lt;/strong&gt;。&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#12298;&amp;#20256;&amp;#35828;&amp;#20043;&amp;#19979;&amp;#12299;&amp;#21516;&amp;#20154;&amp;#22270;" height="675" title="&amp;#12298;&amp;#20256;&amp;#35828;&amp;#20043;&amp;#19979;&amp;#12299;&amp;#21516;&amp;#20154;&amp;#22270;" width="1080"&gt;&lt;/img&gt;《传说之下》同人图&lt;/p&gt;    &lt;p&gt;“更重要的是，我们希望玩家在游玩过我们的游戏后，也会和体验《传说之下》后一样，      &lt;strong&gt;因游戏中对主角故事的沉浸式体验，在生活中进行更多思考。&lt;/strong&gt;”pupu介绍说。      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#30171;&amp;#65292;&amp;#22826;&amp;#30171;&amp;#20102;" height="607" title="&amp;#30171;&amp;#65292;&amp;#22826;&amp;#30171;&amp;#20102;" width="1080"&gt;&lt;/img&gt;痛，太痛了&lt;/p&gt;    &lt;p&gt;而需额外说明的是，《听我说》战斗环节压迫力十足，即使有满身神装，没有熟练操作的情况下也很容易暴毙。      &lt;strong&gt;每当游戏角色失败，意味着玩家“屈服于质疑的言语”&lt;/strong&gt;，生活“重新回归了正轨”，游戏都会以如下画面作为终结，即——      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#27987;&amp;#27987;&amp;#30340;&amp;#24773;&amp;#32490;&amp;#36755;&amp;#20986;&amp;#65292;2022&amp;#24180;&amp;#20197;&amp;#26469;&amp;#21548;&amp;#21040;&amp;#26368;&amp;#25166;&amp;#24515;&amp;#30340;&amp;#19968;&amp;#21477;&amp;#35805;" height="538" title="&amp;#27987;&amp;#27987;&amp;#30340;&amp;#24773;&amp;#32490;&amp;#36755;&amp;#20986;&amp;#65292;2022&amp;#24180;&amp;#20197;&amp;#26469;&amp;#21548;&amp;#21040;&amp;#26368;&amp;#25166;&amp;#24515;&amp;#30340;&amp;#19968;&amp;#21477;&amp;#35805;" width="1080"&gt;&lt;/img&gt;浓浓的情绪输出，2022年以来听到最扎心的一句话&lt;/p&gt;    &lt;p&gt;还好关卡失败就能重新挑战，而非一般roguelike那样重头再来。或许这是pupu为玩家留下的最后一丝温柔。      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;8&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;这里你可能也有点好奇——      &lt;strong&gt;一群还没毕业的大学生，连正式工作都没参与过，怎么就已经在想“辞职去做独立游戏”了呢？&lt;/strong&gt;      &lt;strong&gt;&lt;/strong&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;img height="566" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;2N工作室全员会议，成员分散在世界各地，很长时间里大部分甚至都没彼此见过，总是线上沟通。&lt;/p&gt;    &lt;p&gt;在pupu的童年里，虽然父母也因学业对她玩游戏做出诸多限制，但当她一次次向父母表明心意和热爱后，父母最终逐渐接受了她的想法，甚至愿意送她去读游戏专业。&lt;/p&gt;    &lt;p&gt;但是，在父母心中，所谓的“做游戏”依旧是与“在互联网大厂工作，有体面的生活和高薪”画等号，而非“自己做独立游戏，面对数不清的风险”。&lt;/p&gt;    &lt;p&gt;实际上，      &lt;strong&gt;现实里的pupu至今还没有对父母坦白自己想从事于独立游戏的勇气&lt;/strong&gt;。&lt;/p&gt;    &lt;p&gt;她觉着应该再等等、再等等......大概，总会有机会的吧？等做出了不错的作品，他们应该会理解。&lt;/p&gt;    &lt;p&gt;      &lt;img height="752" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;“我猪肉佬何尝不想成为一名伟大的舞蹈家。”&lt;/p&gt;    &lt;p&gt;2N工作室团队里有一位美术同学，她曾有过个相当不错的游戏创意，也真心考虑把游戏做出来，但身边人对她说的却是：“你这个专业还是先去大公司实习比较好”、“你自己做怎么可能成功”、“女孩子不要搞那么累”......所以最初立项投票时，她也义无反顾的支持了pupu的提案。&lt;/p&gt;    &lt;p&gt;又或是游戏中的一些彩蛋，如刘小宇房间里挂的《挺进地牢》海报，他偷偷看的小说是《斗罗大陆》，这些都是2N工作室成员们“夹带私货”融合的个人经历。      &lt;strong&gt;“刘小宇不是一个人，他更像我们组里每一个人的影子。”&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img height="596" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;实际上，虽然只是一支临时搭起、全由学生组成的团队，但2N工作室阵容却意外的有些“豪华”：&lt;/p&gt;    &lt;p&gt;策划和两名程序是pupu的同学，他们都是卡耐基梅隆大学娱乐技术专业的研一新生；&lt;/p&gt;    &lt;p&gt;负责场景、立绘和封面图的两位美术，刚刚毕业于纽约视觉艺术学院；&lt;/p&gt;    &lt;p&gt;另一位美术同学，现在正在加利福尼亚大学圣克鲁兹分校游戏专业学习；&lt;/p&gt;    &lt;p&gt;负责UI的同学，毕业于卡耐基梅隆大学人机交互专业；&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;img alt="2N&amp;#24037;&amp;#20316;&amp;#23460;&amp;#65292;&amp;#21363;&amp;#8220;&amp;#29275;&amp;#29275;&amp;#24037;&amp;#20316;&amp;#23460;&amp;#8221;" height="279" title="2N&amp;#24037;&amp;#20316;&amp;#23460;&amp;#65292;&amp;#21363;&amp;#8220;&amp;#29275;&amp;#29275;&amp;#24037;&amp;#20316;&amp;#23460;&amp;#8221;" width="413"&gt;&lt;/img&gt;2N工作室，即“牛牛工作室”&lt;/p&gt;    &lt;p&gt;这名字来源是，因为大家认可彼此的能力，      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;每当项目完成交接的时候，都会收获一股夸夸群友“牛牛牛”的夸赞&lt;/p&gt;    &lt;p&gt;所有同学都很优秀。某种程度上说，这是一群被国内各大企业（尤其是游戏公司）争抢最激烈的“天之骄子”。在毕业时，大概率能轻松收到多个一线大厂的offer，得到一份刘小宇那样体面且高薪的工作——但他们偏偏更想做自己的游戏——还是在临近本科毕业的这个夏天。&lt;/p&gt;    &lt;p&gt;      &lt;img height="311" width="522"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;试玩《听我说》的话推荐看一眼这个制作名单，2N工作室他们自己也觉着非常可爱，牛牛是所有成员都喜欢的吉祥物，所有开发者随牛牛登场。&lt;/p&gt;    &lt;p&gt;实际上，      &lt;strong&gt;面对现实，大部分的团队成员毕业后是否会投身独立游戏行业也是个未知数。&lt;/strong&gt;虽然尚未真正踏入游戏行业，但通过各种独立游戏人的故事，他们已深刻了解过独立游戏人面临的压力和困境，明白自己所向往的未来有多“离经叛道”。&lt;/p&gt;    &lt;p&gt;因此，      &lt;strong&gt;在故事最后，pupu倾向于给刘小宇安排一个好的结局&lt;/strong&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;img height="602" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;20世纪末21世纪初，人们习惯把那些用音乐对抗世界、坚决不随波逐流的年轻人称为      &lt;strong&gt;『摇滚青年』&lt;/strong&gt;。而倘若以此角度评判，      &lt;strong&gt;2N工作室这群人实在太摇滚了。&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;        &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;9&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;总的来说，我们相当推荐大家更多关注下他们的游戏。      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;虽然游戏目前还远远没有完成，当前试玩版战斗关卡体验也有不少欠缺，但我们依旧愿意推荐这部作品。&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img height="454" width="804"&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;p&gt;      &lt;img height="351" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img height="384" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;      &lt;strong&gt;《听我说》目前仅在WeGame可以试玩，但后续还会出手机版，TapTap页面最近也刚刚建立。&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;同时，他们也在寻找更多志同道合的朋友加入（主要是美术）。如果你对这群年轻人和《听我说》感兴趣，也可以顺着游戏商店页找到他们的联系方式，真正的亲身参与到这样一款游戏的创作（但他们许多人有时差，可能回复不很及时）。&lt;/p&gt;    &lt;p&gt;      &lt;img height="1029" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;pupu觉着，独立游戏就是纯粹的，是一条自我表达、放飞灵感的道路。虽然注定充满艰辛，但她和2N工作室同学们都正跃跃欲试着。&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#12298;&amp;#21548;&amp;#25105;&amp;#35828;&amp;#12299;wegame&amp;#29609;&amp;#23478;&amp;#35780;&amp;#27979;" height="197" title="&amp;#12298;&amp;#21548;&amp;#25105;&amp;#35828;&amp;#12299;wegame&amp;#29609;&amp;#23478;&amp;#35780;&amp;#27979;" width="1018"&gt;&lt;/img&gt;《听我说》wegame玩家评测&lt;/p&gt;    &lt;p&gt;人的痛苦来源于见识了美好而不可得的纠结感情。也正因如此，我们才会为这些赤诚的愿景和冲动所感动。大多数人或许终其一生都难具那样的勇气。      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;但时至今日，70、80一代依旧，会回味他们年轻时那些『摇滚青年』的味道。&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#36825;&amp;#23601;&amp;#26159;2N&amp;#24037;&amp;#20316;&amp;#23460;" height="742" title="&amp;#36825;&amp;#23601;&amp;#26159;2N&amp;#24037;&amp;#20316;&amp;#23460;" width="720"&gt;&lt;/img&gt;这就是2N工作室&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;      &lt;img alt="&amp;#36825;&amp;#23601;&amp;#26159;pupu" height="1257" title="&amp;#36825;&amp;#23601;&amp;#26159;pupu" width="720"&gt;&lt;/img&gt;这就是pupu&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&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 />
      <guid isPermaLink="true">https://itindex.net/detail/62462-%E5%AD%A6%E7%94%9F-%E5%BC%80%E5%8F%91-%E6%B8%B8%E6%88%8F</guid>
      <pubDate>Thu, 20 Oct 2022 07:17:22 CST</pubDate>
    </item>
    <item>
      <title>编程语言是如何实现并发的之操作系统篇 · 构建我的被动收入</title>
      <link>https://itindex.net/detail/62403-%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80-%E5%B9%B6%E5%8F%91-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F</link>
      <description>&lt;div&gt;    &lt;ul&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E4%BB%8E%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E8%BF%90%E8%A1%8C%E7%A8%8B%E5%BA%8F%E8%AF%B4%E8%B5%B7"&gt;从操作系统运行程序说起&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%9A%84%E6%94%AF%E6%8C%81"&gt;操作系统的支持&lt;/a&gt;        &lt;ul&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E8%B0%83%E5%BA%A6scheduling"&gt;调度(Scheduling)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E7%BA%BF%E7%A8%8Bthread"&gt;线程(Thread)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E7%94%A8%E6%88%B7%E7%BA%BF%E7%A8%8Buser-level-thread"&gt;用户线程(User-level Thread)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E7%BA%BF%E7%A8%8B%E6%A8%A1%E5%9E%8Bthread-model"&gt;线程模型(Thread Model)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2context-switching"&gt;上下文切换(Context switching)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#io%E6%A8%A1%E5%9E%8Bio-model"&gt;I/O模型(I/O Model)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E5%B9%B6%E5%8F%91%E8%BF%98%E6%98%AF%E5%B9%B6%E8%A1%8C"&gt;并发还是并行&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E6%80%BB%E7%BB%93"&gt;总结&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;h2&gt;从操作系统运行程序说起&lt;/h2&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;这是一台拥有2个虚拟CPU核心的      &lt;u&gt;Linux&lt;/u&gt;服务器的      &lt;u&gt;系统监控界面&lt;/u&gt;。其中红框①中      &lt;code&gt;PPID&lt;/code&gt;代表父进程ID，      &lt;code&gt;PID&lt;/code&gt;代表进程或线程ID。红框②中      &lt;code&gt;CPU&lt;/code&gt;代表当前线程运行的CPU核心编号。红框③中是程序的运行命令，其中绿色代表的是      &lt;u&gt;线程，白色为进程&lt;/u&gt;。&lt;/p&gt;    &lt;p&gt;以PID为1375的进程为例，它的父进程为1086，可以通过PPID不断追溯至PID为1的      &lt;u&gt;        &lt;code&gt;init&lt;/code&gt;&lt;/u&gt;进程。从这可以看出Linux通过      &lt;u&gt;        &lt;code&gt;fork()&lt;/code&gt;&lt;/u&gt;的系统调用不断的复制出大量的需要被执行的程序进程。&lt;/p&gt;    &lt;p&gt;进程是操作系统进行      &lt;u&gt;资源分配&lt;/u&gt;的一个独立单位，而实际在CPU运行调度的是线程。以进程1375为例，它又创建了7个线程，如下：&lt;/p&gt;    &lt;pre&gt;      &lt;code&gt;$ ls /proc/1375/task/
1375  1429  1430  1431  1432  1433  1488
$ ls /proc/1375/task/1429
arch_status  cgroup      cmdline             cpuset   exe     gid_map  loginuid  mountinfo  ns         oom_score      patch_state  root       sessionid  smaps_rollup  statm    uid_map
attr         children    comm                cwd      fd      io       maps      mounts     numa_maps  oom_score_adj  personality  sched      setgroups  stack         status   wchan
auxv         clear_refs  cpu_resctrl_groups  environ  fdinfo  limits   mem       net        oom_adj    pagemap        projid_map   schedstat  smaps      stat          syscall&lt;/code&gt;&lt;/pre&gt;    &lt;p&gt;其中线程1430与1432是调度运行在2号CPU核心上的，如果持续观察这个监控界面，会发现同一个线程会不定时在两个CPU核心之间来回切换，这实际正是操作系统对这些线程在多核CPU上进行抢占式调度。&lt;/p&gt;    &lt;p&gt;操作系统之所以能用有限的CPU核心去运行非常多的程序，并且用户感觉这些程序是在同时运行。一方面操作系统（内核）可以通过一些方法实现并发处理任务（程序），另外一方面得益于多个CPU核心，操作系统还可以并行处理任务。&lt;/p&gt;    &lt;p&gt;本文并不是研究操作系统是怎么实现并发的，但在搞清楚编程语言是怎么实现并发处理之前，很有必要提前对操作系统支持并发提供的一些重要特性做一个全面的介绍。操作系统为了支持多任务处理，提供了进程管理与调度，同时在I/O上提供了多种访问文件或网络的系统调用方式。&lt;/p&gt;    &lt;h2&gt;操作系统的支持&lt;/h2&gt;    &lt;pre&gt;      &lt;code&gt;# 操作系统
## 进程(Process)
### 调度方式
- 抢占式(Preemptive)
- 协作式(Cooperative)
### 执行方式
- 用户线程(User-level Thread)
  - Coroutine
    - Verticle
  - Goroutine
  - Erlang process
  - Green Thread(Java)
- 内核线程(Kernel-level Thread)
- 纤程(Fiber)
## I/O
- 同步(Synchronous)
  - 阻塞式(Blocking)
  - 非阻塞式(Non-blocking)
  - 多路复用(Multiplexing)
  - 信号驱动(Signal Driven)
- 异步(Asynchronous)&lt;/code&gt;&lt;/pre&gt;    &lt;h3&gt;调度(Scheduling)&lt;/h3&gt;    &lt;p&gt;进程调度主要有抢占式调度和协作式调度两种：抢占式(Preemptive)与协作式(Cooperative)。&lt;/p&gt;    &lt;a href="https://www.slanglabs.in/blog/python-microservices-01-tornado-asyncio-lint-test-coverage-project-setup"&gt;      &lt;img alt="&amp;#25250;&amp;#21344;&amp;#24335;&amp;#19982;&amp;#21327;&amp;#20316;&amp;#24335;&amp;#20219;&amp;#21153;&amp;#35843;&amp;#24230;(Preemptive Multitasking vs. Cooperative Multitasking)"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;p&gt;抢占式与协作式任务调度(Preemptive Multitasking vs. Cooperative Multitasking)&lt;/p&gt;    &lt;p&gt;抢占式调度往往在一些重要位置（Sleep Call，Timer Tick）放置了中断信号，通过这个信号通知操作系统调度器(Scheduler)进行进程切换。在抢占式模型中，正在运行的进程可能会被强行挂起，这是由于这些中断信号引发的。&lt;/p&gt;    &lt;p&gt;协作式调度也叫非抢占式调度，是指当前运行的进程通过自身代码逻辑出让CPU控制权。与抢占式调度的区别在于进程运行不会被中断信号打断，除非其主动出让控制权给其他进程。&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;以上描述并没有明确区分进程还是线程，实际在        &lt;u&gt;Linux系统的内核态上&lt;/u&gt;，用户态的线程统一按        &lt;u&gt;轻量级进程(Light-weight process)&lt;/u&gt;来处理，它们与真正的进程的区别是在一个用户态进程中的线程共享了相同的地址空间和其他资源（如打开的文件描述符），但在内核调度上并没有什么区别。&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;线程是进程的运行实例，哪怕在非多线程的进程中，在内核态实际运行进程的还是内核线程，所以接下来介绍下线程的分类。&lt;/p&gt;    &lt;h3&gt;线程(Thread)&lt;/h3&gt;    &lt;p&gt;我们在编程语言中见到的线程，一般指的是与内核线程一一映射的用户态线程，比如Java中的Thread其实就是内核线程。但一些编程语言如Erlang与Go都实现了更轻量级的用户线程。&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;用户线程(User-level Thread)        &lt;ul&gt;          &lt;li&gt;协程(Coroutines - Cooperative User-Level Threads)：应用程序通过线程库自行实现的            &lt;strong&gt;协作式调度&lt;/strong&gt;的用户线程，代表性的有Go语言的Goroutine（1.14之前的版本），Vert.x框架中的Verticle。&lt;/li&gt;          &lt;li&gt;Go Goroutine：Go语言的Goroutine在1.14之前是协程的机制，之后的版本采用了            &lt;a href="https://go.dev/doc/go1.14"&gt;异步抢占式调度(asynchronously preemptible)&lt;/a&gt;。&lt;/li&gt;          &lt;li&gt;Erlang process：Erlang VM(BEAM)管理的用户线程，与协程相比的优势在于它可以做到            &lt;strong&gt;公平调度&lt;/strong&gt;，不会出现协程中某个用户线程占用过多CPU周期。&lt;/li&gt;          &lt;li&gt;绿色线程(Green Thread)：类似于协程，是由            &lt;u&gt;Java JDK实现&lt;/u&gt;的，但因为            &lt;u&gt;早期Linux系统没实现内核态的抢占式调度&lt;/u&gt;，Green Thread只能在Solaris系统上发挥它的威力，最终在JDK 1.3之后被Native Thread取代。所以现行的JDK的线程实际是非常重量级的内核态线程，Java的            &lt;a href="https://github.com/openjdk/loom"&gt;Project Loom&lt;/a&gt;会尝试实现新的Green Thread方案，并且是抢占式的调度方案。&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;      &lt;li&gt;内核线程(Kernel-level Thread)：操作系统内核管理的        &lt;strong&gt;抢占式调度&lt;/strong&gt;的线程，是最终运行在CPU上实际执行任务的最小单元。&lt;/li&gt;      &lt;li&gt;纤程(Fibers)：操作系统内核管理的        &lt;strong&gt;协作式调度&lt;/strong&gt;的线程。这一系统级别的方案最终因硬件和软件的发展        &lt;u&gt;逐渐式微&lt;/u&gt;，现在的用户线程也能达到协作式调度的效果。&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;用户线程与内核线程的区别在于用户线程的调度是发生在用户态，内核中无法感知到用户线程的存在，并且调度也发生在用户态，一般是由线程库或编程语言运行时自行实现的。而内核线程的调度是由内核完成的，一般是抢占式调度。&lt;/p&gt;    &lt;h3&gt;用户线程(User-level Thread)&lt;/h3&gt;    &lt;p&gt;用户线程大多是采用协作调度的方式实现，本质上是      &lt;strong&gt;同步执行在与CPU核心数量相同的内核线程上的&lt;/strong&gt;，不仅能极大的降低了上下文开销，还能最佳的利用多核CPU的计算能力。&lt;/p&gt;    &lt;p&gt;用户线程的轻量除了提现在调度的上下文切换开销上，还体现了在对内存的需求上。如果要在4核心4GB内存的笔记本电脑中测试同时生成100万个线程的话，不同编程语言对内存的需求：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;Elixir: 0.48 GB (Process)&lt;/li&gt;      &lt;li&gt;Golang: 1.91 GB (Goroutine)&lt;/li&gt;      &lt;li&gt;Java: 977 GB (Thread)&lt;/li&gt;      &lt;li&gt;PHP: 6836 GB (Laravel Request)&lt;/li&gt;&lt;/ul&gt;    &lt;blockquote&gt;      &lt;p&gt;数据来源：Programming Elixir        &lt;sup&gt;Chapter 15&lt;/sup&gt;&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;但用户线程的执行最终是由内核线程来完成，所以存在一个从用户线程到内核线程的映射模型。&lt;/p&gt;    &lt;h3&gt;线程模型(Thread Model)&lt;/h3&gt;    &lt;p&gt;可能有人会疑惑，用户线程与内核线程是一一映射的吗？总的来说有以下三种线程模型：&lt;/p&gt;    &lt;a href="https://medium.com/swlh/different-threading-models-why-i-feel-goroutine-is-better-though-with-some-limitations-b73863ba4dae"&gt;      &lt;img alt="&amp;#19981;&amp;#21516;&amp;#30340;&amp;#32447;&amp;#31243;&amp;#27169;&amp;#22411;(Different Threading Models)"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;p&gt;不同的线程模型(Different Threading Models)&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;1x1 (kernel-level threading)：用户线程与内核线程是一一映射的。这是最简单的模型。在这种语境下，用户线程中的线程就是我们常规意义上说的线程，当程序创建一个线程时，也会在内核中创建一个内核线程。目前大多数操作系统如Linux、Solaris、FreeBSD、macOS与iOS内核的线程模型就是这种。&lt;/li&gt;      &lt;li&gt;Nx1 (user-level threading)：多个用户线程与一个内核线程映射。在这种模型中，内核线程只有一个，在应用内部不存在内核线程切换的开销，程序的并发能力是很高的。但一旦某个用户线程被阻塞（发生网络或文件I/O系统调用），其他用户线程也会被阻塞。另外应用也无法从多核CPU上获得更好的并发性。所以实际的使用场景中，这种模型并不常见。&lt;/li&gt;      &lt;li&gt;MxN (hybrid threading)：多个用户线程与多个内核线程映射。这种模型最为复杂，但也是最强大的线程模型，不仅有着很好的并发能力，同时还能获得多核CPU的处理能力。早期的Solaris内核中也支持这种线程模型，但因为其会导致内核调度过于复杂，逐渐被放弃。但在Erlang VM和Go语言的运行时就又实现了这种线程模型。&lt;/li&gt;&lt;/ul&gt;    &lt;a href="https://docs.oracle.com/cd/E19620-01/805-3024/6j2sumi1a/index.html"&gt;      &lt;img alt="&amp;#26089;&amp;#26399;Solaris&amp;#20869;&amp;#26680;&amp;#30340;&amp;#32447;&amp;#31243;&amp;#21644;&amp;#36731;&amp;#37327;&amp;#32423;&amp;#36827;&amp;#31243;(Threads and Lightweight Processes)"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;p&gt;早期Solaris内核的线程和轻量级进程(Threads and Lightweight Processes)&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;轻量级进程(Light-weight process)：Solaris内核中的概念，但也会在其他系统内核中看到类似的概念。指的是用户线程和内核线程之间的接口，也可被认为是一个调度用户线程执行的虚拟CPU。当用户线程发出系统调用时，运行该线程的LWP调用内核并保持绑定到该内核线程至少直到系统调用完成。当LWP在内核中为用户线程执行系统调用时，它会运行一个内核线程。因此，每个LWP都与一个内核线程相关联。只有在用户线程完全由轻量级进程构成时，才可以说轻量级进程就是线程。Go语言中Goroutine的G-P-M调度模型中，P承担了类似LWP的角色。&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;应用程序为什么会费劲的设计出用户线程？操作系统提供的内核线程不香吗？这是因为操作系统内核的线程切换是重量级的操作，它需要进行上下文切换，而这会很耗时。&lt;/p&gt;    &lt;h3&gt;上下文切换(Context switching)&lt;/h3&gt;    &lt;p&gt;在进程间切换需要消耗一定的CPU时钟周期进行相关的状态管理工作，包括寄存器和内存映射的保存与读取、更新各种内部的表等。比如在Linux内核中，上下文切换需要涉及寄存器、栈指针、程序计数器的切换。&lt;/p&gt;    &lt;p&gt;在这篇      &lt;a href="https://blog.tsunanet.net/2010/11/how-long-does-it-take-to-make-context.html"&gt;How long does it take to make a context switch?&lt;/a&gt;中可以看到一个结论是：&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;Context switching is expensive. My rule of thumb is that it’ll cost you about 30µs of CPU overhead…Applications that create too many threads that are constantly fighting for CPU time (such as Apache’s HTTPd or many Java applications) can waste considerable amounts of CPU cycles just to switch back and forth between different threads…I think the sweet spot for optimal CPU use is to have the same number of worker threads as there are hardware threads, and write code in an asynchronous / non-blocking fashion.&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;因为线程调度的上下文切换成本非常昂贵，所以最佳的做法是应用程序使用和CPU核心相同的线程数，这样每个线程都能充分利用CPU核心的时间片，避免了应用内部多个线程的上下文切换开销。&lt;/p&gt;    &lt;p&gt;用户线程的轻量级让应用程序能够极大的提高并发性，但也会有一些问题，比如某个用户线程中发起一个网络请求导致底层的内核线程被阻塞，因为多个用户线程在共用这个内核线程，最终导致大量的用户线程被阻塞。&lt;/p&gt;    &lt;p&gt;解决这个问题需要了解操作系统的I/O模型。&lt;/p&gt;    &lt;h3&gt;I/O模型(I/O Model)&lt;/h3&gt;    &lt;p&gt;当应用程序需要访问文件或者网络资源时，应用内的线程将会花费大量的时间来等待数据的到来。如下图所示：&lt;/p&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;如果把CPU处理计算机指令的速度类比成高铁的速度，那线程一次文件或网络的访问将会和蜗牛一样慢，这相当于你在高铁上让蜗牛去帮你取快递，对CPU来说是巨大的浪费。现代操作系统已经提供了多种I/O模型来解决这个问题。常见的I/O模型有：&lt;/p&gt;    &lt;a href="https://www.4e00.com/blog/linux/2017/09/29/unix-network-programming-charpter-6-io-multiplexing.html"&gt;      &lt;img alt="&amp;#20116;&amp;#31181;I/O&amp;#27169;&amp;#22411;&amp;#23545;&amp;#27604;(Comparison of the five I/O models)"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;p&gt;五种I/O模型对比(Comparison of the five I/O models)&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;同步(Synchronous)        &lt;ul&gt;          &lt;li&gt;阻塞式(Blocking)：同步阻塞式是最常见的I/O模型。线程在访问文件或网络资源时，会因发起了内核的系统调用被挂起，内核会检查文件描述符是否可读，当文件描述符中存在数据时，内核会将数据复制给线程并交回控制权，线程从挂起状态切换成可运行状态等到内核调度运行。&lt;/li&gt;          &lt;li&gt;非阻塞式(Non-blocking)：线程在访问文件或网络资源时，因文件描述符是非阻塞的，线程在检查数据是否可读的阶段是非阻塞的。此模型需要线程不停的通过轮询(polling)的方式检查文件描述符是否可读。但之所以属于同步I/O，是因为在最终读取数据(            &lt;code&gt;recvfrom&lt;/code&gt;)时需要从内核态中拷贝数据(            &lt;code&gt;recvfrom&lt;/code&gt;)到用户态中，这个阶段线程依旧被阻塞住无法处理其他指令。&lt;/li&gt;          &lt;li&gt;多路复用(Multiplexing)：和非阻塞式的区别在于，多路复用模型的线程可以同时访问多个文件描述符，这很适合构建高并发的Web服务器或中间件。但此模型会在检查文件描述符时会被阻塞(            &lt;u&gt;              &lt;code&gt;select&lt;/code&gt;&lt;/u&gt;)，并且在读取数据(            &lt;code&gt;recvfrom&lt;/code&gt;)时也会被阻塞。和多路复用模型相似的是使用多线程和阻塞I/O，但当线程产生很多时会消耗大量的内存资源以及线程调度产生的上下文切换开销，所以多路复用模型一般只使用单线程模型。&lt;/li&gt;          &lt;li&gt;信号驱动(Signal Driven)：和上面的模型区别在于，之前的模型都需要线程主动轮询，信号驱动模型需要监听内核的            &lt;code&gt;SIGIO&lt;/code&gt;事件，通过注册事件处理函数，之后线程可以继续执行其他任务。当数据可读时，线程处理函数会以阻塞的方式从内核态复制数据到用户态。&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;      &lt;li&gt;异步(Asynchronous)：此模型和同步模型最大的区别在于，不仅在获取文件操作符时不会被阻塞，数据从内核态复制到用户态也不会被阻塞，因为内核会去做这个复制数据的工作，线程只需要在回调函数中使用数据即可。&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;关于I/O模型的更多细节，请参考：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;        &lt;a href="https://rickhw.github.io/2019/02/27/ComputerScience/IO-Models/"&gt;Study Notes - I/O Models&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch06lev1sec2.html"&gt;I/O Models&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;blockquote&gt;      &lt;p&gt;思考一个问题：如果用户线程不可避免的需要被挂起进（如访问共享资源但没有获得锁）而导致内核线程被挂起，如何调度可以让此内核线程上的用户线程可以继续运行？&lt;/p&gt;&lt;/blockquote&gt;    &lt;h2&gt;并发还是并行&lt;/h2&gt;    &lt;p&gt;前面讨论了很多和I/O相关的概念，并不是所有的计算机任务都是和I/O相关(I/O bound)的，比如很多算法都需要CPU做大量的计算，这时候CPU核心根本不会因为等待外部资源而空转，如果在这种计算密集型(CPU bound)任务中使用多线程技术，那么就会产生大量的线程上下文切换开销，最终会导致处理任务的性能变慢。&lt;/p&gt;    &lt;p&gt;在这篇      &lt;a href="https://www.ardanlabs.com/blog/2018/12/scheduling-in-go-part3.html"&gt;Scheduling In Go : Part III - Concurrency&lt;/a&gt;文章中，作者对比了两种类型工作在并发和并行模式的对比，并提供了一些经验总结：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;CPU密集型(CPU bound)：如果任务是CPU密集型的，那么使用并行的方式来解决问题，这样可以最大的利用CPU核心的算力。如果使用并发的方式去处理，反而会增加        &lt;u&gt;复杂度&lt;/u&gt;。&lt;/li&gt;      &lt;li&gt;I/O密集型(I/O bound)：如果任务时I/O密集型的，那么使用并发的方式来解决问题，这样可以提升单个CPU核心的吞吐量(Throughput)。&lt;/li&gt;&lt;/ul&gt;    &lt;blockquote&gt;      &lt;p&gt;并发(Concurrent)与并行(Parallel)：并发是指同时处理(dealing with)很多事情，并行是指同时做(doing)很多事情。并行是并发的特殊情况，只能在计算机多核环境中实现。&lt;/p&gt;      &lt;p&gt;同步(Sync)与异步(Async)：一种编程模型。区别在于同步是可预测(predictable)的，异步是不可预测(unpredictable)的编程模型。&lt;/p&gt;&lt;/blockquote&gt;    &lt;h2&gt;总结&lt;/h2&gt;    &lt;p&gt;本篇从操作系统的视角介绍编程语言实现并发的底层概念，包括进程调度与I/O模型等。下篇开始介绍常见的      &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/"&gt;并发模型&lt;/a&gt;。&lt;/p&gt;    &lt;div&gt;      &lt;p&gt;        &lt;strong&gt;更新日志&lt;/strong&gt;2022-04-15：根据此        &lt;a href="https://www.v2ex.com/t/846178#reply20"&gt;讨论帖&lt;/a&gt;修改更新。（感谢        &lt;a href="https://www.v2ex.com/member/lxdlam"&gt;@lxdlam&lt;/a&gt;）
2022-04-10：初稿发布。&lt;/p&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 />
      <guid isPermaLink="true">https://itindex.net/detail/62403-%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80-%E5%B9%B6%E5%8F%91-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F</guid>
      <pubDate>Sun, 04 Sep 2022 14:26:12 CST</pubDate>
    </item>
    <item>
      <title>[分享发现] 随科技发展，人力劳动会持续贬值，岗位会持续减少</title>
      <link>https://itindex.net/detail/62303-%E5%88%86%E4%BA%AB-%E5%8F%91%E7%8E%B0-%E7%A7%91%E6%8A%80</link>
      <description>&lt;h3&gt;许多工作岗位会直接消失&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;随着科技发展机器(人工智能)的能力会越来越强。机器(人工智能)能替代的人力劳动将会越来越多&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;重复的劳动将会越来越少&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;h3&gt;你的工作岗位会因为什么原因消失？&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;strong&gt;技术升级应用融合时，直接把岗位干掉，你的岗位还存在只是因为某些新的技术还未能完全被升级应用&lt;/strong&gt;（例如：收营员，资料整理，信息采集等岗位，   &lt;strong&gt;他们许多岗位实际上已经有自动化的方案了，只是因为许多企业，公司还未能及时更新技术而已，而这些公司也不得不更新，因为不更新就没有竞争力，没有竞争力就要死&lt;/strong&gt;）（   &lt;strong&gt;PS：相信大家都见过许多岗位存在的意义其实不大，因为只要有程序员存在很快就能写下一个自动化实现的程序&lt;/strong&gt;）&lt;/li&gt;
  &lt;li&gt;   &lt;strong&gt;你所在的公司在行业大逃杀游戏中求生失败&lt;/strong&gt;（许多行业巨头是完全可以垄断市场的，据云计算平台举例，几年前可能还有许多中小型企业存在，例如   &lt;strong&gt;景安网络&lt;/strong&gt; 但是随着   &lt;strong&gt;阿里云&lt;/strong&gt;等一系列巨头的产生，   &lt;strong&gt;景安网络&lt;/strong&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;）&lt;/li&gt;
  &lt;li&gt;而未来这种简单人力劳动岗位会不断减少（例如：司机，快递员，外卖员，厨师等）&lt;/li&gt;
  &lt;li&gt;一旦这些简单人力劳动人员的工作岗位被裁剪，他们必然只能向复杂人力劳动的工作岗位发起冲锋，然而复杂劳动岗位的容量也是有限的，很难容下这么多人员。。。。那么复杂人力劳动也会不断贬值&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;pre&gt;    &lt;code&gt;例如过往许多事务许多人工操作，现在只需要写一个程序就能自动化执行，这就是由少量写程序的程序员（复杂人力劳动）代替了很多个简单人力劳动
&lt;/code&gt;&lt;/pre&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 />
      <guid isPermaLink="true">https://itindex.net/detail/62303-%E5%88%86%E4%BA%AB-%E5%8F%91%E7%8E%B0-%E7%A7%91%E6%8A%80</guid>
      <pubDate>Wed, 15 Jun 2022 06:59:13 CST</pubDate>
    </item>
    <item>
      <title>编程语言是如何实现并发的之并发模型篇 · 构建我的被动收入</title>
      <link>https://itindex.net/detail/62279-%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80-%E5%B9%B6%E5%8F%91-%E5%B9%B6%E5%8F%91</link>
      <description>&lt;div&gt;    &lt;div&gt;      &lt;p&gt;        &lt;strong&gt;初稿征集意见中&lt;/strong&gt;本文处于初稿状态，可能存在很多错误，如果你有不同的看法，欢迎不吝赐教，先行感谢！&lt;/p&gt;&lt;/div&gt;    &lt;ul&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#%E5%B8%B8%E8%A7%81%E7%9A%84%E5%B9%B6%E5%8F%91%E6%A8%A1%E5%9E%8B"&gt;常见的并发模型&lt;/a&gt;        &lt;ul&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#%E5%A4%9A%E8%BF%9B%E7%A8%8Bmultiprocessing"&gt;多进程(Multiprocessing)&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#%E5%A4%9A%E7%BA%BF%E7%A8%8Bmultithreaded"&gt;多线程(Multithreaded)&lt;/a&gt;            &lt;ul&gt;              &lt;li&gt;                &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98%E9%80%9A%E4%BF%A1shared-memory-communication"&gt;共享内存通信(Shared memory communication)&lt;/a&gt;                &lt;ul&gt;                  &lt;li&gt;                    &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#lock"&gt;Lock&lt;/a&gt;&lt;/li&gt;                  &lt;li&gt;                    &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#stm"&gt;STM&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;              &lt;li&gt;                &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#%E6%B6%88%E6%81%AF%E4%BC%A0%E9%80%92%E9%80%9A%E4%BF%A1message-passing-communication"&gt;消息传递通信(Message passing communication)&lt;/a&gt;                &lt;ul&gt;                  &lt;li&gt;                    &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#csp"&gt;CSP&lt;/a&gt;&lt;/li&gt;                  &lt;li&gt;                    &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#actor"&gt;Actor&lt;/a&gt;                    &lt;ul&gt;                      &lt;li&gt;                        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#vertx"&gt;Vert.x&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#%E4%BA%8B%E4%BB%B6%E9%A9%B1%E5%8A%A8event-driven"&gt;事件驱动(Event Driven)&lt;/a&gt;            &lt;ul&gt;              &lt;li&gt;                &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#event-loop-with-multiplexing"&gt;Event Loop with Multiplexing&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E7%9A%84%E5%AE%9E%E7%8E%B0"&gt;编程语言的实现&lt;/a&gt;        &lt;ul&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#java"&gt;Java&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#go"&gt;Go&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#erlangelixir"&gt;Erlang/Elixir&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#clojure"&gt;Clojure&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#%E8%B5%B0%E5%90%91%E9%AB%98%E5%B9%B6%E5%8F%91"&gt;走向高并发&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#%E6%80%BB%E7%BB%93"&gt;总结&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/concurrency-model/#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"&gt;参考资料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;在      &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/"&gt;操作系统篇&lt;/a&gt;中介绍了从操作系统的视角中不同编程语言实现并发的共同的一些概念。本文将会介绍常见的并发模型及不同编程语言是如何实现的。&lt;/p&gt;    &lt;h2&gt;常见的并发模型&lt;/h2&gt;    &lt;pre&gt;      &lt;code&gt;## 并发模型
### 多进程(Multiprocessing)
- Fork
### 多线程(Multithreaded)
- 共享内存通信
  - Lock
    - Java/Go/Clojure/C
  - STM
    - Clojure
- 消息传递通信
  - CSP
    - Go
  - Actor
    - Erlang/OTP
    - Scala/Akka
    - Vert.x    
### 事件驱动(Event Driven)
- Event Loop 
  with Multiplexing
  - Nginx
  - Node.js
  - Redis
  - Twisted(Python)
  - Netty(Java)&lt;/code&gt;&lt;/pre&gt;    &lt;h3&gt;多进程(Multiprocessing)&lt;/h3&gt;    &lt;p&gt;多进程模型是利用操作系统的进程模型来实现并发的。典型的是Apache Web Server，每个用户请求接入的时候都会创建一个进程，这样应用就可以同时支持多个用户。&lt;/p&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;如上图，在Linux系统中PID为1的名为P0的进程通过      &lt;code&gt;fork()&lt;/code&gt;系统调用创建了3个子进程。在多处理器的系统中，这些子进程可以并行运行在多个处理器上，当然这些进程也可以被同一个处理器通过      &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2context-switching"&gt;上下文切换&lt;/a&gt;进行CPU分时共享。&lt;/p&gt;    &lt;p&gt;在图中M1、M2与M3都代表内存资源，在多进程中如果不同进程想共享内存中的数据必须通过      &lt;a href="https://en.wikipedia.org/wiki/Inter-process_communication"&gt;进程间通信&lt;/a&gt;的方式来实现。&lt;/p&gt;    &lt;p&gt;多进程模型的缺点在于创建进程的开销非常高，如果进程过多会很快消耗光系统资源，并且上下文切换在进程间的开销也很高，在      &lt;a href="https://www.bmpi.dev/dev/deep-in-program-language/how-to-implement-concurrency/os-scheduling/#%E5%B9%B6%E5%8F%91%E8%BF%98%E6%98%AF%E5%B9%B6%E8%A1%8C"&gt;I/O密集型任务&lt;/a&gt;的应用中，此并发模型很难满足需求。&lt;/p&gt;    &lt;h3&gt;多线程(Multithreaded)&lt;/h3&gt;    &lt;p&gt;在操作系统的视角看，比如Linux中，在进程中创建线程是通过      &lt;code&gt;clone()&lt;/code&gt;系统调用来实现，这和创建子进程的区别不大。线程与进程的区别在于同一个进程内的线程共享着进程分配的资源，线程不被分配资源，只是操作系统调度执行任务的抽象的最小单元。&lt;/p&gt;    &lt;p&gt;比如下图中，PID为10的进程P0通过      &lt;code&gt;clone()&lt;/code&gt;系统调用创建了3个线程，这些线程都可以访问进程分配的内存资源M0。&lt;/p&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;我们也可以通过      &lt;code&gt;htop&lt;/code&gt;命令在Linux中看到这些进程及线程的运行信息，比如下图中所示PID为339328进程（它是一个基于JVM的Clojure应用）及其创建的线程信息：&lt;/p&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;也可以通过      &lt;code&gt;/proc&lt;/code&gt;文件系统获取进程创建的线程的信息：&lt;/p&gt;    &lt;div&gt;      &lt;pre&gt;        &lt;code&gt;$ ls /proc/339328/task/1043773339340339342339344339346339348339350339357339359339361339363339367339380339388788478975443991563339328339341339343339345339347339349339353339358339360339362339364339378339382424498975439991561&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;p&gt;相比多进程模型来说，因为线程比进程创建的系统开销小，所以多线程模型是很常见的实现并发的方式。但此种模型存在一个必须解决的问题，就是线程间通信的问题。但线程为什么要通信呢？那是因为大部分业务系统问题的解空间在用冯·诺伊曼计算机去实现的时候，都存在并发计算时线程间数据共享的问题。要数据共享有两种方式：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;共享内存通信(Shared memory communication)：不同线程间可以访问同一内存地址空间，并可修改此地址空间的数据。&lt;/li&gt;      &lt;li&gt;消息传递通信(Message passing communication)：不同线程间只能通过收发消息的形式去通信，数据只能被拥有它的线程修改。&lt;/li&gt;&lt;/ul&gt;    &lt;h4&gt;共享内存通信(Shared memory communication)&lt;/h4&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;因为线程间共享内存资源，在访问临界区域时会出现数据竞争（发生竞态条件，即代码的行为取决于各操作的时序）的问题，如果不能正确的处理此问题，程序会产生线程不安全的问题，最终导致程序崩溃或无法正常运行。&lt;/p&gt;    &lt;p&gt;解决竞态条件的方式是对数据进行同步(      &lt;a href="https://en.wikipedia.org/wiki/Synchronization_(computer_science)"&gt;Synchronize&lt;/a&gt;)访问。要实现同步访问常见的方式有：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;锁(        &lt;a href="https://en.wikipedia.org/wiki/Lock_(computer_science)"&gt;Lock&lt;/a&gt;)：通过锁定临界区域来实现同步访问。&lt;/li&gt;      &lt;li&gt;信号量(        &lt;a href="https://en.wikipedia.org/wiki/Semaphore_(programming)"&gt;Semaphores&lt;/a&gt;)：可以通过信号量的增减控制对一个或多个线程对临界区域的访问。&lt;/li&gt;      &lt;li&gt;同步屏障(        &lt;a href="https://en.wikipedia.org/wiki/Barrier_(computer_science)"&gt;Barriers&lt;/a&gt;)：通过设置屏障控制不同线程执行周期实现同步访问。&lt;/li&gt;&lt;/ul&gt;    &lt;h5&gt;Lock&lt;/h5&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;锁(Lock)，也叫互斥量(Mutex)。线程在操作临界区域资源时，需要先获取锁，然后才能操作，当操作完成后，需要释放锁。此模型利用了对底层硬件运行过程的形式化，这让其即简单又复杂。从锁的种类就可以看出来其复杂性：&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;li&gt;偏向/轻量级/重量锁&lt;/li&gt;      &lt;li&gt;分段锁&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;对锁的使用不当还会产生死锁问题(      &lt;a href="https://en.wikipedia.org/wiki/Deadlock"&gt;Deadlock&lt;/a&gt;)。在实际开发过程中，能不用锁就不用锁，可以考虑使用一些轻量级的替代方案如原子变量(Atomic)，或      &lt;a href="https://www.baeldung.com/lock-free-programming"&gt;无锁(lock-free)非阻塞(non-blocking)算法&lt;/a&gt;实现的数据结构。&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;原子变量的更新为何是线程安全的？因为CPU提供了CAS(        &lt;a href="https://en.wikipedia.org/wiki/Compare-and-swap"&gt;Compare-and-swap&lt;/a&gt;)的指令来更新原子变量，这条指令从硬件上确保了此操作是线程安全的。&lt;/p&gt;&lt;/blockquote&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;ul&gt;      &lt;li&gt;不支持分布式内存模型，只解决了进程内的并发同步；&lt;/li&gt;      &lt;li&gt;不好调试与测试，想用好不容易；&lt;/li&gt;&lt;/ul&gt;    &lt;h5&gt;STM&lt;/h5&gt;    &lt;p&gt;锁模型是一种悲观的并发同步机制，但实际上冲突发生的概率并不高，所以乐观的并发同步机制性能更好。STM(Software transactional memory)就是这样一种用来代替锁模型的乐观并发同步机制。STM是用软件的方式去实现事务内存(Transactional memory)，而事务内存中的事务(Transactional)正是关系型数据库中的概念，一个事务必须满足      &lt;a href="https://en.wikipedia.org/wiki/ACID"&gt;ACID&lt;/a&gt;性质，如下图所示：&lt;/p&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;在t0时刻，T1、T2与T3线程同时获取要操作的同一数据的快照v0，之后T1线程在自己的事务里于t1时刻提交自己的写入值v1，之后T2线程在自己的事务里提交自己的写入值v2，由于在提交时刻会做冲突检测，此事务发现操作数据的快照已经发生变化，于是回滚自己的提交。之后开启新的事务重新获取最新的快照v1，并于时刻t2成功提交自己的写入值v2。在线程v3中由于是读取操作，并没有数据修改，所以在它的事务中使用的是最早的快照v0。&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;在STM的事务中尽可能避免副作用，比如在事务中去修改原子变量这种操作，可能会导致事务回滚失败。&lt;/p&gt;    &lt;p&gt;STM实现的一种方式是基于MVCC(      &lt;a href="https://en.wikipedia.org/wiki/Multiversion_concurrency_control"&gt;Multiversion concurrency control&lt;/a&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;ul&gt;      &lt;li&gt;在事务内需要避免产生副作用；&lt;/li&gt;      &lt;li&gt;不支持分布式内存模型，只解决了进程内的并发同步；&lt;/li&gt;&lt;/ul&gt;    &lt;h4&gt;消息传递通信(Message passing communication)&lt;/h4&gt;    &lt;p&gt;在锁模型中，生产者和消费者之间的通信是通过共享内存而完成的，要实现安全通信，必须给共享内存所属的临界区加锁。那如果生产者和消费者是通过消息传递完成通信的呢？那样我们就可以摆脱锁模型的限制了。&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;Do not communicate by sharing memory. Instead, share memory by communicating. Communication forces coordination. (Ivo Balbaert)&lt;/p&gt;&lt;/blockquote&gt;    &lt;h5&gt;CSP&lt;/h5&gt;    &lt;p&gt;通信顺序进程(      &lt;a href="https://en.wikipedia.org/wiki/Communicating_sequential_processes"&gt;CSP(Communicating sequential processes)&lt;/a&gt;)是一种形式语言，用来描述基于消息传递通信的安全并发模型。如下图所示：&lt;/p&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;这些任务块之间的通信是基于通道(Channel)来完成的，当创建了一个通道之后，不同的任务块就可以通过持有这个通道来通信，通道可以被不同的任务块共享。通道两端任务块的通信可以是同步的，也可以是异步的。&lt;/p&gt;    &lt;p&gt;在这里的任务块不是如Java里重量级的线程类，在运行时是非常轻量级的代码块。这些代码块可以被调度到不同的线程中，最终被多个CPU内核并发执行。&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;ul&gt;      &lt;li&gt;不支持分布式内存模型，只解决了进程内的并发同步；&lt;/li&gt;&lt;/ul&gt;    &lt;h5&gt;Actor&lt;/h5&gt;    &lt;p&gt;演员模型(      &lt;a href="https://en.wikipedia.org/wiki/Actor_model"&gt;Actor&lt;/a&gt;)是一种类似面向对象编程思想的安全并发模型。在面向对象的世界里，对象是一种封装了状态及行为的实体，对象间通过消息去通信（通过对象调用其方法）。而在Actor模型中，一切皆Actor，每个Actor中都有自己的状态，其他Actor只能通过通信的方式来获取或修改被通信Actor的状态。Actor通信的方式类似收发邮件，它有自己的收件箱，如下图所示：&lt;/p&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;在上述图中，我们可以看到相比CSP模型，Actor模型可以跨节点在分布式集群中运行。实际上Actor模型的代表Erlang正是天然分布式容错的编程语言。&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;p&gt;此模型的缺点：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;存在信箱满后消息丢失的问题;&lt;/li&gt;&lt;/ul&gt;    &lt;h6&gt;Vert.x&lt;/h6&gt;    &lt;p&gt;      &lt;a href="https://vertx.io/"&gt;Vert.x&lt;/a&gt;是一个基于JVM的反应式模型的工具包，在解决并发同步的问题上它采用了类似Actor模型的方式，如下图所示：&lt;/p&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;在它的架构里最基本的计算单元名为Verticle，这些Verticle之间通过事件总线(Event Bus)进行异步通信，当然也可以像Actor一样跨节点通信。和Actor模型不同的地方在于Vert.x支持多种语言，因为Event Bus解耦了实现Verticle的语言限制。&lt;/p&gt;    &lt;h3&gt;事件驱动(Event Driven)&lt;/h3&gt;    &lt;p&gt;在多线程方式实现的并发模型中，我们解决问题的方式是通过创建更多的线程来提高系统的并发处理能力。但线程创建的开销及线程间上下文调度切换的开销并不是很小，所以纵使系统的硬件资源很充足，也存在一定的上限。那么有没有可能只创建一个线程，而且这个线程可以同时处理很多个任务呢？当然是可以的，这正是基于I/O多路复用的事件循环处理并发模型的解法，通过单线程来并发处理I/O密集型的任务。&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;Less is more.&lt;/p&gt;&lt;/blockquote&gt;    &lt;h4&gt;Event Loop with Multiplexing&lt;/h4&gt;    &lt;p&gt;      &lt;img alt=""&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;此模型巧妙的利用了系统内核提供的I/O多路复用系统调用，将多个socket连接转换成一个事件队列(event queue)，只需要单个线程即可循环处理这个事件队列。当然这个线程是有可能被阻塞或长期占用的，针对这种类型的任务处理可以单独使用一个      &lt;a href="https://www.nginx.com/blog/thread-pools-boost-performance-9x/"&gt;线程池&lt;/a&gt;去做，这样就不会阻塞Event Loop的线程了。&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;ul&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;Java&lt;/h3&gt;    &lt;p&gt;Java是一门面向对象的编程语言，标准库对并发的支持是      &lt;strong&gt;基于共享内存通信的锁模型&lt;/strong&gt;，因此用Java的标准库来实现高并发是一件非常有挑战的事情，想不踩坑太难。&lt;/p&gt;    &lt;p&gt;想深入了解Java的并发模型，可以参考      &lt;a href="https://book.douban.com/subject/10484692/"&gt;《Java并发编程实战》&lt;/a&gt;。&lt;/p&gt;    &lt;p&gt;当然基于Java的三方库实现了很多并发模型，如：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;Actor:        &lt;a href="https://doc.akka.io/docs/akka/current/?language=java"&gt;Akka&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;Event Loop with Multiplexing        &lt;ul&gt;          &lt;li&gt;            &lt;a href="https://netty.io/"&gt;Netty&lt;/a&gt;&lt;/li&gt;          &lt;li&gt;            &lt;a href="https://github.com/nginx-clojure/nginx-clojure/"&gt;Nginx-Clojure&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;h3&gt;Go&lt;/h3&gt;    &lt;p&gt;在Go流行的时期流传着一个故事：一个PHP的普通开发者在一周内学会了Go语言，之后开发出了一个高并发的Web应用，要用Java实现同样的性能，至少需要多年的经验。&lt;/p&gt;    &lt;p&gt;暂且不论这个故事是否合理，但它展示了Go语言的两大亮点：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;语法简单易学；&lt;/li&gt;      &lt;li&gt;天然支持高并发模型；&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;Go在语言层面实现了      &lt;strong&gt;CSP并发模型&lt;/strong&gt;，因此能让开发者以非常低的成本写出高并发的Web应用。在对CSP并发模型的实现中，Go任务块一般是一个函数，这个函数的调度是由Go语言的调度器来完成，可以被调度在不同的线程中。如果在这个函数中出现了阻塞线程的如网络I/O的操作，调度器会委托给Netpoller去执行，而Netpoller的底层正是对操作系统I/O多路复用技术的封装。&lt;/p&gt;    &lt;p&gt;Go高并发的秘诀在于它的G-P-M运行时调度模型，详细的设计可参考这篇文章：      &lt;a href="https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part2.html"&gt;Scheduling In Go : Part II - Go Scheduler&lt;/a&gt;。&lt;/p&gt;    &lt;h3&gt;Erlang/Elixir&lt;/h3&gt;    &lt;p&gt;Erlang是一门天然分布式、高并发、容错的编程语言，它是      &lt;strong&gt;Actor并发模型&lt;/strong&gt;的代表编程语言。Elixir是基于Erlang虚拟机(BEAM)的一种不纯粹的、动态类型的函数式语言。它们自然原生支持Actor并发模型，所以在开发高并发的分布式容错应用时，可以考虑使用Elixir，它强大的并发模型及富有表达力的语法可以提供非常好的开发体验。&lt;/p&gt;    &lt;p&gt;Erlang的虚拟机在运行时实现了      &lt;u&gt;软实时抢占式调度&lt;/u&gt;，详细的信息可参考这篇文章：      &lt;a href="https://jlouisramblings.blogspot.com/2013/01/how-erlang-does-scheduling.html"&gt;How Erlang does scheduling&lt;/a&gt;。&lt;/p&gt;    &lt;h3&gt;Clojure&lt;/h3&gt;    &lt;p&gt;Clojure是基于JVM平台的Lisp方言，是不纯粹的、动态类型的函数式语言（这点倒和Elixir类似）。Clojure可以直接调用Java的库，这让其可支持非常多的并发模型，但最有特色的就是它的标准库实现了STM的并发模型，官方提供的异步库      &lt;a href="https://github.com/clojure/core.async"&gt;core.async&lt;/a&gt;也实现了CSP的并发模型。当然还可以通过      &lt;a href="https://github.com/nginx-clojure/nginx-clojure/"&gt;Nginx-Clojure&lt;/a&gt;实现基于I/O多路复用的高并发模型。&lt;/p&gt;    &lt;p&gt;Clojure支持非常多的并发原语，想了解可参考这篇文章：      &lt;a href="https://ericnormand.me/guide/clojure-concurrency"&gt;Clojure Concurrency Tutorial&lt;/a&gt;。&lt;/p&gt;    &lt;h2&gt;走向高并发&lt;/h2&gt;    &lt;p&gt;1999年的时候      &lt;a href="https://en.wikipedia.org/wiki/C10k_problem"&gt;C10K&lt;/a&gt;的问题被提出，当时在单机上并发处理上万的连接是一件富有挑战的事情，最终借助操作系统提供的一些支持如进程调度与I/O模型，通过一些高并发的模型如I/O多路复用，我们可以在单机上支持上万甚至更多的并发连接。&lt;/p&gt;    &lt;p&gt;二十多年过去了，互联网从Web1走向了      &lt;a href="https://www.bmpi.dev/dev/glimpse-of-web3/"&gt;Web3&lt;/a&gt;，联网的设备从PC走向了IoT，我们已经到了万物互联的时代。C10K的问题已经转变为      &lt;strong&gt;C10M&lt;/strong&gt;的问题，如何在单机上支持百万乃至千万的连接呢？&lt;/p&gt;    &lt;p&gt;在这篇      &lt;a href="https://phoenixframework.org/blog/the-road-to-2-million-websocket-connections"&gt;The Road to 2 Million Websocket Connections in Phoenix&lt;/a&gt;中我们可以看到如何用Elixir的Web框架Phoenix在一台40核128GB内存的机器上支撑两百万的Websocket长链接，最终因Linux内核的限制而无法进一步提高并发链接数，并没有达到服务器的极限。&lt;/p&gt;    &lt;p&gt;Migratorydata甚至使用Java在一台12核96GB内存的机器上支撑了上千万的Websocket长连接，更多细节见这两篇文章：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;        &lt;a href="https://migratorydata.com/blog/migratorydata-solved-the-c10m-problem/"&gt;How MigratoryData solved the C10M problem: 10 Million Concurrent Connections on a Single Commodity Server&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://arxiv.org/pdf/1712.09876.pdf"&gt;Reliable Messaging to Millions of Users with MigratoryData&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;当单机并发达10K时，内核是解决方案，当单机并发达10M时，内核是瓶颈。比如Linux内核需要32GB内存来维护上千万的Socket连接。所以在单机千万级的解决方案需要在内核之外的应用层去做更多的事情，感兴趣的读者可以看这篇文章：      &lt;a href="http://highscalability.com/blog/2013/5/13/the-secret-to-10-million-concurrent-connections-the-kernel-i.html"&gt;The Secret to 10 Million Concurrent Connections -The Kernel is the Problem, Not the Solution&lt;/a&gt;。&lt;/p&gt;    &lt;h2&gt;总结&lt;/h2&gt;    &lt;p&gt;在软件开发过程中，安全至关重要。编程的两大安全难题是      &lt;u&gt;线程安全与内存安全&lt;/u&gt;。这个系列的两篇文章都是在尝试介绍不同编程语言是如何解决线程安全从而更容易的实现高并发。&lt;/p&gt;    &lt;p&gt;另外一个想借助这篇文章分享的一个观点是：问题可以被更复杂的方案去解决，当然也可以通过另一种截然不同的思路去更简单的解决。当你觉得一个方案很复杂的时候，试着去找一个完全不同方向的方案，也许会更容易一些。&lt;/p&gt;    &lt;h2&gt;参考资料&lt;/h2&gt;    &lt;ul&gt;      &lt;li&gt;        &lt;a href="https://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch06lev1sec2.html"&gt;I/O Models&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://web.archive.org/web/20160423223903/http://concur.rspace.googlecode.com/hg/talk/concur.html#slide-5"&gt;Concurrency is not Parallelism (it’s better)&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.loginradius.com/blog/engineering/callback-vs-promises-vs-async-await/"&gt;Callback vs Promises vs Async Await&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://betterprogramming.pub/sync-vs-async-vs-concurrent-vs-parallel-5754cdb60f66"&gt;Sync vs. Async vs. Concurrent vs. Parallel&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.thegeekstuff.com/2013/11/linux-process-and-threads/"&gt;What are Linux Processes, Threads, Light Weight Processes, and Process State&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://gist.github.com/jboner/2841832"&gt;Latency Numbers Every Programmer Should Know&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://www.cs.uaf.edu/2015/fall/cs301/lecture/11_16_thread_user.html"&gt;Cooperative User-Level Threads (Coroutines)&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://en.m.wikipedia.org/wiki/Green_threads"&gt;Green threads - Wikipedia&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://stackoverflow.com/questions/5878231/what-exactly-makes-erlang-process-green-thread-coroutine-lighter-than-kernel"&gt;multithreading&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://news.ycombinator.com/item?id=193440"&gt;Ask HN: Erlang and network connections?&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://en.wikipedia.org/wiki/Thread_(computing)#Threading_models"&gt;Thread (computing) - Wikipedia&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://berb.github.io/diploma-thesis/community/index.html"&gt;Concurrent Programming for Scalable Web Architectures&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="http://tutorials.jenkov.com/java-concurrency/concurrency-models.html"&gt;Concurrency Models&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="http://java.ociweb.com/mark/stm/article.html"&gt;Software Transactional Memory&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://naghavi.me/blog/vertx-concurrency-model/"&gt;Vert.x concurrency model&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop"&gt;The event loop - JavaScript | MDN&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://v8.dev/blog/fast-async"&gt;Faster async functions and promises · V8&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://mp.weixin.qq.com/s/9g0wVT-5PpmXRoKJZo-skA"&gt;透过 rust 探索系统的本原：并发篇&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://zhuanlan.zhihu.com/p/137339439"&gt;并发模型&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://book.douban.com/subject/26337939/"&gt;七周七并发模型&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;div&gt;      &lt;p&gt;        &lt;strong&gt;更新日志&lt;/strong&gt;2022-05-27：初稿发布。        &lt;br /&gt;2022-05-07：开始写作。&lt;/p&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 />
      <guid isPermaLink="true">https://itindex.net/detail/62279-%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80-%E5%B9%B6%E5%8F%91-%E5%B9%B6%E5%8F%91</guid>
      <pubDate>Sun, 29 May 2022 07:15:54 CST</pubDate>
    </item>
    <item>
      <title>在阿里巴巴，我们如何先于用户发现和定位 Kubernetes 集群问题？</title>
      <link>https://itindex.net/detail/62138-%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4-%E7%94%A8%E6%88%B7-%E5%8F%91%E7%8E%B0</link>
      <description>&lt;div&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;em&gt; 作者：彭南光(光南)&lt;/em&gt;  &lt;br /&gt;  &lt;blockquote&gt;   &lt;p&gt;本文整理自阿里云高级研发工程师彭南光(光南) 在 KubeCon China 2021 大会的演讲实录，分享了阿里巴巴是如何通过自研通用链路探测+定向巡检工具 KubeProbe 应对大规模集群的稳定性挑战的。关于阿里云云原生团队在本次 KubeCon 上分享的全部内容沉淀于电子书《云原生与云未来的新可能》当中，可点击文末“阅读原文”下载。&lt;/p&gt;&lt;/blockquote&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;快速发现和定位问题的能力是快速恢复系统的基石，只有先做到快速发现和定位问题，才能谈如何解决问题，尽量减少用户损失。那么如何在复杂的大规模场景中，做到真正的先于用户发现和定位问题呢？我会将我们在管理大型 Kubernetes 集群过程中快速发现和定位问题的一些经验和实践带给大家——我们是如何通过自研通用链路探测+定向巡检工具 KubeProbe 应对遇到的大规模集群的稳定性挑战的。   &lt;strong&gt;链路探测：&lt;/strong&gt;模拟广义用户行为，探测链路和系统是否异常  &lt;strong&gt;定向检测：&lt;/strong&gt;检查集群异常指标，发现未来存在或可能存在的风险点  &lt;strong&gt;系统增强：&lt;/strong&gt;发现问题提速增效，根因分析  &lt;strong&gt;发现问题之后：&lt;/strong&gt;后置检查和自愈，Chat-Ops   &lt;strong&gt;01&lt;/strong&gt;  &lt;p&gt;   &lt;em&gt;    &lt;strong&gt;业务背景和挑战&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;em&gt;Cloud Native&lt;/em&gt;&lt;/p&gt;  &lt;br /&gt;  &lt;p&gt;阿里云云原生应用平台的容器服务团队，拥有 ACK 、ASI 等产品，管理了大规模的 Kubernetes 集群，不仅向外部公有云用户提供 Kubernetes 服务，还承担了阿里巴巴集团上云，阿里巴巴应用全面容器化的工作。   &lt;br /&gt;   &lt;br /&gt;目前，整个阿里巴巴的业务都跑在 Kubernetes 集群上并实现了云原生和容器化，例如：天猫/淘宝/高德/考拉/饿了么等等。容器服务作为阿里云的管控底座，各种云服务也运行在这些集群之上，例如视频云/dataworks /MSE 微服务引擎/MQ 消息队列等等。我们需要对这些基础设施的稳定性负责。&lt;/p&gt; 现在，云原生的架构越来越流行，越来越多的产品和应用开始选择云原生架构，这里有一张图，大致示意了现代的云原生应用架构，应用生于云上，长于云上，各级提供分层的服务，这种分层的服务能够让业务和应用专注于业务层，屏蔽平台和基础设施层的复杂概念。  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;从稳定性的角度来讲，这种应用的架构分层，上层应用的稳定性就会开始依赖底层基础设施的支持；另外，大一统的基座既为大规模的资源调度优化和在离线混部提供场景，也对基础设施团队维护大规模集群的稳定性问题提出极大的挑战。  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;img&gt;&lt;/img&gt; 这里有两张形象的图示可以展现出云原生应用架构下的业务应用和平台层基础设施的关系，Kubernetes 集群是非常复杂的，一个单集群的链路组件就有数十个甚至上百个之多，何况是大规模的多集群管理呢？但运行在上层的业务同学并不会感知到复杂，因为我们已经把复杂包掉了，留给用户的是一个简单的统一接口。就像淘宝这样的应用其实是非常复杂的，但在用户看来只是一个简单的提交订单而已，按键背后蕴含着极其复杂的内容。为什么做到这样？因为我们把复杂留给了自己，把简单交给了用户。 很多时候，好的应用开发者不一定是基础设施专家，云原生让业务专注业务，基础设施专注基础设施。同时，业务很多时候也只能关心业务自身的稳定性，业务大多数时候没有能力关心，或者是不希望投入大量的人力关心基础设施和平台层的稳定性，所以，关于平台层和基础设施的稳定性问题上，我们需要把复杂留给自己，把简单留给用户，为用户提供稳定的平台层服务。同时，更加关心全局稳定性和全局的可用性，而不是单点可用性。  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;img&gt;&lt;/img&gt;  &lt;br /&gt;容器服务是阿里巴巴集团业务以及阿里云管控/云服务的底座，上面跑着各种各样的业务，如电商业务/中间件/二方业务/搜索/阿里云云服务等等。此外还有数百个自研和开源的组件，每年数十万次的组件变更/数千个集群/数十万台节点，甚至大的集群单集群节点规模已过万。业务架构更是纷繁复杂，有单租集群、多租集群、vc 集群、联邦集群等等，同时还有各种在离线混布、统一调度、大促活动。在运行时也存在多种形态，如 runC，runD 等等。  &lt;br /&gt;因此组件的繁杂、变更频繁、用户场景各异、集群规模庞大、业务架构复杂……都给业务带来了挑战：  &lt;br /&gt;  &lt;strong&gt;挑战一：如何降低系统风险。&lt;/strong&gt;场景复杂，业务形态各异，任何一个不起眼细节的遗漏或环节的处置不慎都有可能导致伤害的扩大化；  &lt;br /&gt;  &lt;strong&gt;挑战二：如何对用户集群的稳定性负责。&lt;/strong&gt;如何先于用户发现和定位问题成为容器服务生产稳定性建设的重中之重，也是全局高可用体系的基石。 系统是如此的复杂，任何一个不起眼的细节遗漏或处理不慎都有可能导致非预期的伤害，我们要怎样才能降低系统风险呢？另外我们又是如何对形态各异的用户集群运行时全局稳定性负责的呢？如何才能先于用户发现和定位这些集群中已经存在或即将发生的问题，是保障集群的稳定性建设的重中之重，也是 Kubernetes 全局高可用体系的基石。   &lt;strong&gt;02&lt;/strong&gt;  &lt;p&gt;   &lt;em&gt;    &lt;strong&gt;思考和方案&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;em&gt;Cloud Native&lt;/em&gt;&lt;/p&gt;  &lt;br /&gt;基于这些挑战，我们做了一些思考和预设。下图是一个极度简化的用户发布扩容链路，虽说极度简化，但实际我们仍可以看出，链路还是比较复杂的。  &lt;br /&gt;为了保障这次用户的扩容/发布链路畅通，我们首先带来几个预设：  &lt;strong&gt;   &lt;br /&gt;&lt;/strong&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;br /&gt;  &lt;strong&gt;预设 1：&lt;/strong&gt;链路复杂组件众多，各组件分别升级迭代，数据监控无法无死角覆盖全部场景；  &lt;br /&gt;  &lt;strong&gt;预设 2：&lt;/strong&gt;即使链路中各组件/节点监控数据正常，也不能保证集群整体链路 100% 可用，只有经过实际业务全链路探测才能确定实际可用的结论；  &lt;br /&gt;  &lt;strong&gt;预设 3：&lt;/strong&gt;反证法在证明集群不可用场景一定优于举证法，即使 100% 监控数据正常，但只要发布失败则证明链路不通。 另外，在单集群之外，我们还要关注多集群的管理，下面是一些多集群管控中的不稳定性因素示例，可以看到，多集群场景下，稳定性管控的复杂度会被放大，我们继续带来几个预设：  &lt;br /&gt;  &lt;strong&gt;预设 4：&lt;/strong&gt;在大规模集群场景下数据一致性的问题会愈加显现，并且可能引发严重故障，成为一个显著的不稳定因素；  &lt;br /&gt;  &lt;strong&gt;预设 5：&lt;/strong&gt;集群内的监控告警链路存在自依赖风险，如果集群故障，则监控告警也有可能同时故障。  &lt;br /&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;接下来是我们基于以上预设的一些解决方案。   &lt;strong&gt;1&lt;/strong&gt; 探索和解决方案  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;strong&gt;1.  链路探测&lt;/strong&gt;  &lt;strong&gt;   &lt;br /&gt;&lt;/strong&gt;链路探测即模拟广义上的用户行为，探测链路是否畅通，流程是否无异常。  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;img&gt;&lt;/img&gt;  &lt;br /&gt;想要做到先于用户发现系统问题，我们自己首先要成为系统用户，并且是使用最多、了解最深、无时无刻不在使用和感知系统状态的用户。  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;所谓链路探测，就是模拟广义上的用户行为，去对集群组件链路中的各种等待探测的对象去做探测。此处要特别说明的是，这里的用户并不仅仅指的是狭义上使用系统的同学，而是更广义的用户，或者可以理解和引申成为依赖下游。  &lt;br /&gt;另外，在实现全链路探测的同时，拆解电路，实现全电路中的短路探测也是非常必要的，也是对全链路探测的一个补充。  &lt;br /&gt;  &lt;strong&gt;2.  定向巡检&lt;/strong&gt;  &lt;strong&gt;   &lt;br /&gt;&lt;/strong&gt;定向巡检是指检查和分析大规模集群的异常指标，找到已有或将来可能存在的风险点，就像检修管道一样。  &lt;p&gt;    &lt;img&gt;&lt;/img&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;br /&gt;例如有若干个集群，它分为很多集群组，不同集群组之间的 etcd 冷/热备是否配置齐备，风控限流配置是否正常，webhook 版本是否正常，混部参数是否一致，包括它的证书有效期是不是快要到期了等等。不同的集群组之间可能有所差别，但同类型集群之间是有一个转衡的，因此我们可以定向做一些巡检。 接下来是关于链路探测的一些常见场景：   &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;就像一个游戏策划，如果他连自己制作的游戏都不玩，他可能发现游戏机制的问题，把这个游戏越做越好吗？我们要做到先于用户发现系统问题，那我们自己首先就要先成为系统的用户，并且一定是使用最多的，了解最深的，无时无刻不在使用和感知系统状态的用户。 另外，所谓链路探测，就是让自己成为自己系统的用户，模拟广义上的“用户”行为去对集群/组件/链路里的各种等待探测的对象去做探测。 一定要注意，这里的“用户”并不仅仅指的是狭义上使用系统的同学，而是更广义的用户，或者可以理解引申为依赖下游。 例如业务同学要发布业务，就必然要经过 git 系统，再到发布系统，再到我们底层的基础设施平台，也就是我们的 ASI，这就是一次全链路探测流程。在这里业务同学就是用户，探测对象可以是全链路。 但如果我们把 etcd 看作一个系统服务，那么 APIServer 就是它广义上的用户，我们模拟 APIServer 请求 etcd 这条链路的探测也就有了意义。 另外像 MSE 操作 zookeeper，外部用户通过阿里云控制台创建 ACK 集群，PaaS 平台操作联邦集群，甚至视频云业务方发起一次转码任务，都是一样的道理。  &lt;br /&gt;还有一点要关注的就是，虽然全链路探测看起来很美，但很多时候，全链路探测同时还很长，可能等到失败的时候问题已经很大了。所以，在实现全链路探测的同时，拆解链路，实现全链路中的短链路探测也是非常必要的，也是对全链路探测的一个补充。   &lt;img&gt;&lt;/img&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;上图是定向巡检的场景，相比链路探测关注于链路可用性，定向巡检的核心还是在大规模的集群场景下，数据一致性是非常困难的问题，数据不一致，将导致一些隐患，可能会在未来引发某些不确定性的故障。 所谓定向巡检就是对整个集群或链路中的各项数据、指标做已知原因的检查，找出不一致或数据偏离的点，判断是否可能引发风险，从而做到防患于未然，治未病。  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;br /&gt;比如我们这个里边有同一种类型的集群组，A 集群发现它的证书有效期不到三年，而其他集群的证书有效期都有三年；B 集群的 webhook 版本可能是 v2，而其他集群的 webhook 版本是 v3；C 集群的风控限流配置并没有配一个驱逐 Pod 的限流，但其他集群都配配置了驱逐 Pod 的限流，这肯定是不符合预期的；再比如 D 集群的 etcd 的冷/热备没有配置或者是运行不正常，我们也可以先把它检查出来。   &lt;strong&gt;03&lt;/strong&gt;  &lt;p&gt;   &lt;em&gt;    &lt;strong&gt;系统实现&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;em&gt;Cloud Native&lt;/em&gt;&lt;/p&gt;  &lt;br /&gt;基于上面许许多多的背景预设以及方案，我们设计并实现了一套巡检/探测平台，我们取名为 KubeProbe (并未开源，和现在社区上有类似命名的项目没有任何联系)。  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;我们早期也曾考虑使用社区项目 Kuberhealthy，并为 Kuberhealthy 做过一些代码贡献，修复过一些严重的代码 Bug，最终因为功能上不太适用于我们的场景，我们选择了自研自建。  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;上图是一套中心架构，我们会有一套中心管控系统。用户的用例会通过统一仓库的镜像的方式接入，使用我们通用的 sdk 库，自定义巡检和探测逻辑。我们会在中心管控系统上配置好集群和用例的关系配置，如某用例应该执行在哪些集群组上，并做好各种运行时配置。我们支持了周期触发/手动触发/事件触发(如发布)的用例触发方式。用例触发后会在集群内创建一个执行巡检/探测逻辑的 Pod，这个 Pod 里会执行各种用户自定义的业务巡检/探测逻辑，并在成功和失败后通过直接回调/消息队列的方式通知中心端。中心端会负责告警和用例资源清理的工作。 我举一个例子，比如 Kubelet 在我们的组件运维平台上做分批发布，每批次都会触发一次相关集群的链路探测用例作为后置检查，一旦我们发现某次发布的后置检查失败，我们会阻断掉用户的当前发布，防止伤害扩大，同时第一时间告警以及通知相关同事进入排查，是否组件新版本不符合预期。 同时，我们也支持第三方的事件回调，可以更快的集成进三方系统中。 另外，我们对于某些需要 7*24 小时不间断的高频次短周期探测用例，我们还实现了另外一套常驻分布式架构，这套架构使用一个集群内的 ProbeOperator 监听 Probe Config CRD 变化，在探测 pod 中周而复始的执行探测逻辑。这套架构，完美复用了 KubeProbe 中心端提供的告警/根因分析/发布阻断等等附加功能，同时使用了标准  Operator 的云原生架构设计，常驻体系带来了极大的探测频率提升(因为去掉了创建巡检 pod 和清理数据的开销)基本可以做到对集群的 7*24 小时无缝覆盖，同时便于对外集成。   &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt; 另外还有一个必须要提的非常重要的点，即平台只是提供了一个平台层的能力支持，真正这个东西要起作用，还是要看在这个平台上构建的用例是否丰富，能不能方便的让更多人进来写各种巡检和探测用例。就像测试平台很重要，但测试用例比测试平台更重要这个道理一样。一些通用的 workload 探测，组件探测，固然能发现很多管控链路上的问题，但是更多的问题，甚至业务层的问题暴露，实际上依赖于基础设施和业务层同学的共同努力。 从我们的实践上来说，测试同学和业务同学贡献了很多相关的检查用例，比如测试同学贡献的 ACK &amp;amp; ASK 的创建删除全链路探测巡检，金丝雀业务全链路扩容用例，比如本地生活同学的 PaaS 平台应用检查等等，也得到了很多稳定性上的结果和收益。目前我们维护的巡检/探测用例有数十个，明年有机会破百，巡检/探测次数近 3000 万次，明年可能会过亿。目前可以提前发现 99%以上的集群管控问题和隐患，效果是非常好的。   &lt;strong&gt;04&lt;/strong&gt;  &lt;p&gt;   &lt;em&gt;    &lt;strong&gt;发现问题之后：根因分析和事件处理&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;em&gt;Cloud Native&lt;/em&gt;&lt;/p&gt;  &lt;br /&gt;接下来我们聊聊发现问题之后的事情，这里有一个类似于问诊对话的例子，患者发现 “哎呀我不舒服了！”这就是发现问题。医生参考各种化验单，同时做了信息聚合分析推断，告诉患者“你已经 24 小时没睡觉了，你睡不着是因为你很焦虑，你焦虑的根因是因为后天就要期末考试了。”这便是定位问题根因，然后针对根因去解决这个问题，他告诉患者“不要担心，我刚收到的消息，小学生已经不需要期末考试了。”这个过程一定要快！   &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;来自探测链路的告警内容往往是混沌的，和数据监控告警是有所差异的。就像上文提到的，链路探测告警的告警很可能就是一句患者的我不舒服了，需要你作为医生去判断，为什么他不舒服了呢？根因是什么。而数据监控很多时候本身就代表了原因，比如 Etcd OOM，用已有的 oncall 经验可能得不到最好的效果。 另外快速定位问题和根因分析，是一个树状的搜索，经验加工判断的过程，也就是如何从一个混沌的表象推断出根因，核心是逻辑。 这和健康体检是不同的，健康体检是列出检查项 1，2，3，4，5......然后告诉你一堆数值。很多时候，即使存在体检中心，我们仍然也需要医院的专业医生来为您解读和判断病情，不是吗？ 同时，根因分析/问题自愈的关键在于专家经验的下沉，也就是把专家经验下沉到系统中去，专家经验的下沉带来的最大收益是可复用可输出。你可以想一下，如果我们把一个最专业的医生的能力放进系统里，他是不是更方便的为每一个人分析病情呢？   &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt; 这便是 KubeProbe 发现问题之后的全流程，我们首先会经过一个我们自建的中心化根因分析系统，在这里我们会聚合分析所有和本次失败相关的信息，包括事件/日志/变更/告警/组件升级等等，我们将这些信息进行聚合分析，并对事件做关联处理，最终通过一个树状的分析系统初步定位出某次探测失败的原因，比如说 APIServer 超时或者 etcd 断连等等。 此外我再补充一点，文本联想也是一个很好的根因分析方式，我们可以通过机器学习训练文本识别的方式来联想出和这种失败 case 最关联的根因，这种 AIOps 的工作我们只是略微涉及，还在持续的探索中，我们的数据量非常大，我认为这一定是未来的方向之一。  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;KubeProbe 根因分析和后置处理全流程  &lt;br /&gt; 上图的左下方是某次我们失败的告警，它经过根因分析系统之后发现首先最核心，最关联，最大的原因可能是 APIserver 的连接断开并且当前已经恢复，所以可能只是偶发的网络抖动，我们暂时不用特别关注，但此时可以看到置信度为 90%。 另外还有一些可能的原因都会关联起来。比如某个组件，这次探测它是由某一个组件发布出发的，它的发布人是 XXX，我们可以观察这个发布对 API server 会产生某些影响，是否多次 list watch 不符合预期，然后把 API server list watch 出问题了，置信度有 50%。 当我们得到一个初步的原因之后，我们会进入二次确认系统做二次的原因确认，比如我们判断原因可能是 APIServer 超时/etcd 断联/节点超时等,我们就会自动重新拉取一下 APIServer 接口，看一下此时是否仍然超时，是否恢复，如果恢复了，我们就普通告警，并且告诉用户，现在没事了，但是你得关注。如果没恢复，那这就很严重了，属于最高优先级，直接电话告警。 就是这个思路，如果有系统无法定位的问题，并且持续无法定位，我们也会触发高级别告警，并且会增加相关的根因分析识别树逻辑。 过多的告警等于没有告警，我是最讨厌告警海的。从经验上讲，当我们构建了一套这样的根因分析+二次确认+后置检查系统之后，我们的 Oncall 成本下降了 90% 以上，并且还能够持续下降，终态可以说是无人值守，大家也可以试试类似的工作，可以说是投入小，见效大。自从这些系统建设起来以后，我们可以自豪的说，我们用很小的精力 Oncall 了每一个告警条目（对，是每一条告警，是数千个集群，数千万次探测巡检的每一条告警）并且不会有任何遗漏了。 最后是一些给 Oncall 人员的小甜品，Chat-ops。   &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;基于 NLP 语义识别的 Chat-ops 系统 我们利用钉钉提供的 NLP 机器人，构建了一套比较完善的 Chat-ops 系统，这样之后我们的 Oncall 人员就可以很方便的在告警群里通过聊天的方式操作 KubeProbe 相关功能了，比如：重跑失败探测，查询集群状态，拉取诊断信息，查询探测日志，集群告警静默。  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;br /&gt;上图是我们操作 Chat-ops 系统的过程。这个过程非常方便。  &lt;br /&gt;比如晚上我已经再被窝里了，这时候它给我了一个告警，比如某个集群之前出现了某次失败但当前已经恢复了，需要我关注一下。 既然我关注了，我便希望某一个常用例再跑一次（它可能周期比较长，例如一个钟头），由于短链路的用例可能随时都在跑，此时我便告诉机器人再跑一次，机器人就会识别我的语义，将集群再跑一次。跑完之后，我再通过查询状态看一下这个集群当前的状态怎么样了，这样是非常方便的，有时候你晚上上班了，或者是在路上，或者是在被窝里，都也可以很舒服的去 on-call 一个系统了。  &lt;br /&gt;  &lt;strong&gt;05&lt;/strong&gt;  &lt;p&gt;   &lt;em&gt;    &lt;strong&gt;Demo 示例&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;em&gt;Cloud Native&lt;/em&gt;&lt;/p&gt;  &lt;br /&gt;  &lt;strong&gt;1、发布&lt;/strong&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;strong&gt;2、探测列表&lt;/strong&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;strong&gt;3、探测 Pod 开始运行&lt;/strong&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;strong&gt;4、探测结果&lt;/strong&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;strong&gt;5、根因分析&amp;amp;告警&lt;/strong&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;strong&gt;6、Chat-ops&lt;/strong&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;点击“&lt;/strong&gt;   &lt;strong&gt;阅读原文&lt;/strong&gt;   &lt;strong&gt;”即可下载《云原生与云未来的新可能》电子书全部内容。&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;    &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;br /&gt;  &lt;strong&gt;近期热门&lt;/strong&gt;  &lt;br /&gt;  &lt;strong&gt;HOT TOPIC&lt;/strong&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;strong&gt;#云原生与云未来的新可能#&lt;/strong&gt;  &lt;br /&gt;复制并前往下方链接，即可免费下载电子书  &lt;em&gt;https://developer.aliyun.com/topic/download?id=8265&lt;/em&gt;  &lt;br /&gt;  &lt;p&gt;   &lt;img&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;strong&gt;往期分享实录&lt;/strong&gt;  &lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  &lt;h1&gt;   &lt;a href="http://mp.weixin.qq.com/s?__biz=MzUzNzYxNjAzMg==&amp;mid=2247519754&amp;idx=1&amp;sn=5f1946b0f1423b07f4d17dde4646b587&amp;chksm=fae685c5cd910cd320108a687b8c0557d808ad0e04e81a770553e2311390020978748cb5fd22&amp;scene=21#wechat_redirect" target="_blank"&gt;1、&lt;/a&gt;   &lt;a href="http://mp.weixin.qq.com/s?__biz=MzUzNzYxNjAzMg==&amp;mid=2247519754&amp;idx=1&amp;sn=5f1946b0f1423b07f4d17dde4646b587&amp;chksm=fae685c5cd910cd320108a687b8c0557d808ad0e04e81a770553e2311390020978748cb5fd22&amp;scene=21#wechat_redirect" target="_blank"&gt;云未来、新可能 - 绿色、无处不在、可信的计算&lt;/a&gt;&lt;/h1&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;h1&gt;   &lt;a href="http://mp.weixin.qq.com/s?__biz=MzUzNzYxNjAzMg==&amp;mid=2247514723&amp;idx=1&amp;sn=e7b727239ed9882a550387ee51992ee5&amp;chksm=fae6b1accd9138ba0809f1deef25628bac725df242297009595fd814d34854f03ffcbe10f1bc&amp;scene=21#wechat_redirect" target="_blank"&gt;2、&lt;/a&gt;   &lt;a href="http://mp.weixin.qq.com/s?__biz=MzUzNzYxNjAzMg==&amp;mid=2247520333&amp;idx=1&amp;sn=313faf23bfdf5f5d48a1c01644bd84ce&amp;chksm=fae69b82cd911294328fb416c1d0e2a02bb2827740d75adab89d29f4511f1d8e772875cadd70&amp;scene=21#wechat_redirect" target="_blank"&gt;以一致的体验交付和管理云原生多集群应用&lt;/a&gt;&lt;/h1&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;h1&gt;   &lt;a href="http://mp.weixin.qq.com/s?__biz=MzUzNzYxNjAzMg==&amp;mid=2247512321&amp;idx=1&amp;sn=eb0be8179a384f49f67c58fbd504fd16&amp;chksm=fae6bacecd9133d838fc6a7dc0c6144525031241b1499e5a0573deeccbbc2d6203bd0b4d14e5&amp;scene=21#wechat_redirect" target="_blank"&gt;3、&lt;/a&gt;   &lt;a href="http://mp.weixin.qq.com/s?__biz=MzUzNzYxNjAzMg==&amp;mid=2247520820&amp;idx=1&amp;sn=7496bb389092b8af98c0725db3767496&amp;chksm=fae699fbcd9110ed339d5cfc5836c88eb7c2901fee56d3f469a89fd91852f3ae2d97ce33e349&amp;scene=21#wechat_redirect" target="_blank"&gt;如何在零停机的情况下迁移 Kubernetes 集群&lt;/a&gt;&lt;/h1&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;4、最佳实践：Kubernetes 集群中 DNS 故障的可观测性与根因诊断  &lt;br /&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&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>dev</category>
      <guid isPermaLink="true">https://itindex.net/detail/62138-%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4-%E7%94%A8%E6%88%B7-%E5%8F%91%E7%8E%B0</guid>
      <pubDate>Wed, 02 Mar 2022 00:00:00 CST</pubDate>
    </item>
    <item>
      <title>研究发现 98% 的中国儿童青少年未达心血管健康理想状态</title>
      <link>https://itindex.net/detail/62113-%E7%A0%94%E7%A9%B6-%E5%8F%91%E7%8E%B0-%E4%B8%AD%E5%9B%BD</link>
      <description>根据发表在《美国心脏病学会杂志》上的 &lt;a href="https://www.jacc.org/doi/10.1016/j.jacasi.2021.09.007"&gt;一项研究&lt;/a&gt;，98.3% 的中国儿童青少年 &lt;a href="https://news.sciencenet.cn/htmlnews/2022/2/474083.shtm" target="_blank"&gt;未达心血管健康理想状态&lt;/a&gt;。研究数据来自全国 7 个省市及地区，约 7 万名中小学生参与问卷调查，有近 2 万名学生参与血样采集，通过血样可以检测血脂、血糖等评估心血管健康的指标。经过有效数据的整理，最终纳入近 1 万 5 千多名资料。结果表明，儿童青少年的超重和肥胖状况令人担忧，这个群体的心血管健康状况非常不乐观。全国单纯的肥胖率已经达到 11% 左右，超重和肥胖相加能达到 20% 左右的患病率。全国只有 1.9% 的男性和 1.6% 的女性有理想的心血管健康状况。男性和女性在心血管疾病发病率上存在差异。这种性别差异与多种因素有关，比如生理年龄差异、激素水平差异、肾功能差异、染色体差异等。 &lt;div&gt;
  &lt;a href="http://feeds.feedburner.com/~ff/solidot?a=tHQ7qgklS3Q:HptvlfsdfL8:yIl2AUoC8zA"&gt;   &lt;img border="0" src="http://feeds.feedburner.com/~ff/solidot?d=yIl2AUoC8zA"&gt;&lt;/img&gt;&lt;/a&gt;   &lt;a href="http://feeds.feedburner.com/~ff/solidot?a=tHQ7qgklS3Q:HptvlfsdfL8:7Q72WNTAKBA"&gt;   &lt;img border="0" src="http://feeds.feedburner.com/~ff/solidot?d=7Q72WNTAKBA"&gt;&lt;/img&gt;&lt;/a&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 />
      <guid isPermaLink="true">https://itindex.net/detail/62113-%E7%A0%94%E7%A9%B6-%E5%8F%91%E7%8E%B0-%E4%B8%AD%E5%9B%BD</guid>
      <pubDate>Thu, 17 Feb 2022 20:16:56 CST</pubDate>
    </item>
    <item>
      <title>研究发现社交媒体加重了中年女性的孤独感</title>
      <link>https://itindex.net/detail/62061-%E7%A0%94%E7%A9%B6-%E5%8F%91%E7%8E%B0-%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93</link>
      <description>&lt;div&gt;
  &lt;p&gt;中年是一个忙碌的年龄，也是一个孤独的时期。在工作和家庭的重压下，人们无暇培养友谊，特别是对女性而言。新冠肺炎疫情前，关于孤独的谈论往往以男性为中心。但根据2020年一项对1000多名成年人进行的调查，疫情封锁期间，41岁到57岁（20世纪60年代中期至70年代末出生）的“X世代”女性报告的孤独感上升幅度最大。&lt;/p&gt;
&lt;/div&gt;
 &lt;div&gt;
  &lt;p&gt;其中，与孩子一起生活的女性社交孤立感的增加在该人群中是最大的。&lt;/p&gt;
  &lt;p&gt;对于那些因为家庭生活和工作而疲惫不堪的女性来说，社交媒体通常是发泄和寻求联系最方便的渠道。但许多人说，上网已经让人感到空虚和孤独。38岁的摄影师米兰达·莱因哈特（如图）表示，还没有找到属于自己的“妈妈部落”，自己在家教育孩子，因而更难找到志趣相投的朋友。疫情前，她和一个密友常一起看电视剧。但随着工作和生活变得忙碌，她们便没空一起看了。“哪有时间？哪有精力？疫情给妈妈们增加了太多精神负担。一天下来，我们非常累。”虽然社交媒体帮助她与老朋友保持联系，但也让她五味杂陈。“我可以看到她们的生活，但没有参与其中。社交媒体让我感到不那么与世隔绝，却也更加孤独。”莱因哈特女士曾尝试在社交媒体寻找经历类似的母亲，但由于没有找到一群能面对面的朋友，她有时会觉得自己被晾在一边。&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" height="876" src="http://www.199it.com/wp-content/uploads/2022/01/1643115213-3680-b13f712fdfe1c74.png" width="700"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;笔者在社交媒体一个大型育儿群发布了一个关于中年孤独的问题后，立即收到300多名女性的回复，她们中的大多数人都表达了类似感受。55岁的黛布·法布里齐奥是一名单亲母亲，有两个孩子。去年夏天，在小女儿大学毕业后，她成为“空巢妈妈”。占用已婚朋友的时间总是很棘手，于是她努力组织聚会，找人晚上一起吃饭或散步。“但疫情让这一切都停止了。人人都躲在自己的‘气泡’里。”现在都用社交媒体保持联系，这么做有好有坏。出于健康考虑，她对社交活动一直很谨慎，只能在社交媒体上浏览朋友发布的聚会内容。“看到朋友们在海滩上的照片，我想，‘她们在外面玩了。我本来可以去的’。”&lt;/p&gt;
  &lt;p&gt;2018年美国退休人员协会对45岁以上人群的调查发现，随着中年人和老年人越来越多地使用社交媒体，他们反而感到更孤独。疫情封锁期间对意大利成年人进行的一项研究也发现，社交媒体不能替代面对面的社交互动。&lt;/p&gt;
  &lt;p&gt;因为丈夫工作的缘故，52岁的安迪·马丁5年前从得克萨斯州搬到佐治亚州，但没能建立搬家前那样的深厚人际联系。“孩子上中学时，大多数女性都有自己的家长朋友小团体。”马丁女士说，她很开心疫情封锁期间能够通过社交媒体与远方的亲朋联系，但觉得这种联系是肤浅的。“我知道他们在做什么，但这并不能解决我的孤独问题。”&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;自 环球科技&lt;/p&gt;

 &lt;div&gt;  &lt;div&gt;   &lt;h3&gt;更多阅读：&lt;/h3&gt;   &lt;ul&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/907363.html"&gt;Sainte-Justine：研究发现社交媒体使用时间的增加与青少年抑郁症发病率上升有关&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/705612.html"&gt;杜克大学：研究表明社交媒体的回声室效应实际上可能是一件好事&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/794982.html"&gt;宾夕法尼亚大学：研究发现限制社交媒体使用可减少患抑郁症风险&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/721997.html"&gt;《卫报》：研究发现社交媒体像老虎机“设套”让用户上瘾&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/549538.html"&gt;哥本哈根大学：研究显示过多浏览社交媒体他人完美照片使人沮丧&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/475296.html"&gt;社交媒体研究分享&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/460909.html"&gt;匹兹堡大学：研究显示越常使用社交媒体越容易抑郁&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/898134.html"&gt;纽约大学：研究发现社交媒体上种族仇恨言论越多的地区犯罪率越高&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/563529.html"&gt;皮尤研究中心：社交媒体和新闻机构的官方网站成为人们获取网络新闻最主要的方式&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/465492.html"&gt;Invaluable： 调查显示8090爱逛社交媒体胜于美术馆&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/427259.html"&gt;美国卡耐基梅隆大学：研究表明社交媒体或让你错失心仪工作&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/199300.html"&gt;美国《赫芬顿邮报》：社交媒体和网络游戏是自恋者的聚集地&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/795665.html"&gt;宾夕法尼亚大学：研究显示减少社交媒体使用可降低抑郁和孤独感&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/120398.html"&gt;社交媒体给你更多寂寞&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;     &lt;a href="https://www.199it.com/archives/55596.html"&gt;弗林德斯大学：常用社交媒体的女孩更容易自卑和抑郁&lt;/a&gt;&lt;/li&gt;&lt;/ul&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>生活数据 女性孤独 社交媒体 社交媒体危害 社交媒体研究</category>
      <guid isPermaLink="true">https://itindex.net/detail/62061-%E7%A0%94%E7%A9%B6-%E5%8F%91%E7%8E%B0-%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93</guid>
      <pubDate>Tue, 25 Jan 2022 20:56:52 CST</pubDate>
    </item>
    <item>
      <title>濒临灭绝的鸟类首次被发现单性生殖</title>
      <link>https://itindex.net/detail/61871-%E7%81%AD%E7%BB%9D-%E9%B8%9F%E7%B1%BB-%E5%8F%91%E7%8E%B0</link>
      <description>雌性加州秃鹰 &lt;a href="https://www.nationalgeographic.com/animals/article/in-extremely-rare-event-two-female-birds-make-babies-without-males" target="_blank"&gt;不需要雄性繁殖后代&lt;/a&gt;，该物种和鲨鱼、鳐鱼和蜥蜴一起进入无需交配即可繁殖的生物名单之中。
 &lt;br /&gt;
 &lt;br /&gt;
“秃鹰数据确实有些令人困惑。”在为拯救加州秃鹰（地球上最濒危的生物之一）忙了一整天之后，Oliver Ryder 走回车旁，这可不是他想听到的话。当他的同事 Leona Chemnick 解释了自己看到的情况时，他的恐
惧很快就变成了迷恋。几十年来，科学家一直在试图将加州秃鹰从灭绝边缘拯救回来。1982 年，这些鸟类的全部种群数量下降到只有 22 只。到 2019 年，通过圈养繁殖和放飞工作，种群数量逐渐增加到 500 多只。这需要对圈养的鸟类进行仔细管理，特别是要选出可以繁殖健康后代的雄性和雌性。这就是为什么当科学家更仔细检查基因数据时，他们发现两只雄性鸟类——血统编号为 SB260 和 SB517——没有表现出“鸟爸爸”的遗传贡献。
 &lt;br /&gt;
 &lt;br /&gt;
换句话说，根据 10 月 28 日发表在《Journal of Heredity》上的同行评议 &lt;a href="https://academic.oup.com/jhered/article-lookup/doi/10.1093/jhered/esab052"&gt;论文&lt;/a&gt;，这两只鸟是通过兼单性孤雌生殖（或单性生殖）来到这个世界的。当雌性动物的卵子产生的某些细胞表现得像精子并与卵子融合时，在正常有性繁殖的物种中就会出现这种无性繁殖。虽然这种情况在脊椎动物中很少见，但鲨鱼、鳐鱼和蜥蜴都出现过孤雌生殖。科学家还记录了一些圈养鸟类的自体受精情况，例如火鸡、鸡和中国小鹌鹑，这种现象通常会出现在无法接近雄性的、被圈养的雌性身上。但这是首次记录到加利福尼亚秃鹰中出现这种情况。 &lt;div&gt;
  &lt;a href="http://feeds.feedburner.com/~ff/solidot?a=R9N9yfwyL8g:TGiqzv_a6aI:yIl2AUoC8zA"&gt;   &lt;img border="0" src="http://feeds.feedburner.com/~ff/solidot?d=yIl2AUoC8zA"&gt;&lt;/img&gt;&lt;/a&gt;   &lt;a href="http://feeds.feedburner.com/~ff/solidot?a=R9N9yfwyL8g:TGiqzv_a6aI:7Q72WNTAKBA"&gt;   &lt;img border="0" src="http://feeds.feedburner.com/~ff/solidot?d=7Q72WNTAKBA"&gt;&lt;/img&gt;&lt;/a&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 />
      <guid isPermaLink="true">https://itindex.net/detail/61871-%E7%81%AD%E7%BB%9D-%E9%B8%9F%E7%B1%BB-%E5%8F%91%E7%8E%B0</guid>
      <pubDate>Tue, 02 Nov 2021 18:19:01 CST</pubDate>
    </item>
    <item>
      <title>Burp Suite Pro 2021.10 (macOS, Linux) -- 查找、发现和利用漏洞</title>
      <link>https://itindex.net/detail/61867-burp-suite-pro</link>
      <description>&lt;p&gt;请访问原文链接：  &lt;a href="https://sysin.org/blog/burp-suite-pro-2021/" title="Burp Suite Pro 2021 (macOS, Linux) -- &amp;#26597;&amp;#25214;&amp;#12289;&amp;#21457;&amp;#29616;&amp;#21644;&amp;#21033;&amp;#29992;&amp;#28431;&amp;#27934;"&gt;Burp Suite Pro 2021 (macOS, Linux) -- 查找、发现和利用漏洞&lt;/a&gt;，查看最新版。原创作品，转载请保留出处。&lt;/p&gt; &lt;p&gt;作者：gc(at)sysin.org，主页：  &lt;a href="https://sysin.org"&gt;www.sysin.org&lt;/a&gt;&lt;/p&gt; &lt;h2&gt;  &lt;a href="https://sysin.org/#&amp;#31616;&amp;#20171;" title="&amp;#31616;&amp;#20171;"&gt;&lt;/a&gt;简介&lt;/h2&gt; &lt;p&gt;Burp Suite Professional 是一套用于测试 web 安全性的高级工具集 —- 所有这些都在一个产品中。从一个基本的拦截代理到尖端的 Burp 扫描器，使用 Burp Suite Pro，正确的工具只需点击一下就可以了。&lt;/p&gt; &lt;p&gt;我们强大的自动化让您有更多的机会做您最擅长的，而 Burp Suite 处理容易实现的目标。先进的手动工具将帮助你识别目标更微妙的盲点。&lt;/p&gt; &lt;p&gt;Burp Suite Pro 是由一个研究团队开发的。这意味着在我们发布之前，发现成果已经包含在我们的最新更新中。我们的 pentesting 工具将使您的工作更快，同时让您了解最新的攻击向量。&lt;/p&gt; &lt;h2&gt;  &lt;a href="https://sysin.org/#&amp;#21151;&amp;#33021;&amp;#20171;&amp;#32461;" title="&amp;#21151;&amp;#33021;&amp;#20171;&amp;#32461;"&gt;&lt;/a&gt;功能介绍&lt;/h2&gt; &lt;h3&gt;  &lt;a href="https://sysin.org/#Manual-penetration-testing-features-&amp;#25163;&amp;#21160;&amp;#28183;&amp;#36879;&amp;#27979;&amp;#35797;&amp;#21151;&amp;#33021;" title="Manual penetration testing features &amp;#25163;&amp;#21160;&amp;#28183;&amp;#36879;&amp;#27979;&amp;#35797;&amp;#21151;&amp;#33021;"&gt;&lt;/a&gt;Manual penetration testing features 手动渗透测试功能&lt;/h3&gt; &lt;p&gt;  &lt;img alt="Burp Suite Pro proxy interception" src="https://portswigger.net/burp/pro/features/images/proxy-interception.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Intercept everything your browser sees&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;A powerful proxy/history lets you modify all HTTP(S) communications passing through your browser.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Manage recon data&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;All target data is aggregated and stored in a target site map - with filtering and annotation functions.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Expose hidden attack surface&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Find hidden target functionality with an advanced automatic discovery function for “invisible” content.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Test for clickjacking attacks&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Generate and confirm clickjacking attacks for potentially vulnerable web pages, with specialist tooling.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Work with WebSockets&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;WebSockets messages get their own specific history - allowing you to view and modify them.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Break HTTPS effectively&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Proxy even secure HTTPS traffic. Installing your unique CA certificate removes associated browser security warnings.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Manually test for out-of-band vulnerabilities&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Make use of a dedicated client to incorporate Burp Suite’s out-of-band (OAST) capabilities during manual testing.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Speed up granular workflows&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Modify and reissue individual HTTP and WebSocket messages, and analyze the response - within a single window.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Quickly assess your target&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Determine the size of your target application. Auto-enumeration of static and dynamic URLs, and URL parameters.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Assess token strength&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Easily test the quality of randomness in data items intended to be unpredictable (e.g. tokens).&lt;/p&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;  &lt;a href="https://sysin.org/#Advanced-custom-automated-attacks-&amp;#39640;&amp;#32423;-&amp;#33258;&amp;#23450;&amp;#20041;&amp;#33258;&amp;#21160;&amp;#25915;&amp;#20987;" title="Advanced/custom automated attacks &amp;#39640;&amp;#32423;/&amp;#33258;&amp;#23450;&amp;#20041;&amp;#33258;&amp;#21160;&amp;#25915;&amp;#20987;"&gt;&lt;/a&gt;Advanced/custom automated attacks 高级/自定义自动攻击&lt;/h3&gt; &lt;ul&gt;  &lt;li&gt;Faster brute-forcing and fuzzing&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Deploy custom sequences of HTTP requests containing multiple payload sets. Radically reduce time spent on many tasks.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Query automated attack results&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Capture automated results in customized tables, then filter and annotate to find interesting entries/improve subsequent attacks.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Construct CSRF exploits&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Easily generate CSRF proof-of-concept attacks. Select any suitable request to generate exploit HTML.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Facilitate deeper manual testing&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;See reflected/stored inputs even when a bug is not confirmed. Facilitates testing for issues like XSS.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Scan as you browse&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The option to passively scan every request you make, or to perform active scans on specific URLs.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Automatically modify HTTP messages&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Settings to automatically modify responses. Match and replace rules for both responses and requests.&lt;/p&gt; &lt;p&gt;  &lt;img alt="Burp Suite Pro Intruder payload positions" src="https://portswigger.net/burp/pro/features/images/payload.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;  &lt;a href="https://sysin.org/#Automated-scanning-for-vulnerabilities-&amp;#33258;&amp;#21160;&amp;#25195;&amp;#25551;&amp;#28431;&amp;#27934;" title="Automated scanning for vulnerabilities &amp;#33258;&amp;#21160;&amp;#25195;&amp;#25551;&amp;#28431;&amp;#27934;"&gt;&lt;/a&gt;Automated scanning for vulnerabilities 自动扫描漏洞&lt;/h3&gt; &lt;p&gt;  &lt;img alt="Burp Suite Pro scan results" src="https://portswigger.net/burp/pro/features/images/scan-results.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Harness pioneering AST technology&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;High signal: low noise. Scan with pioneering, friction-free,   &lt;a href="https://portswigger.net/burp/application-security-testing/oast" rel="noopener" target="_blank"&gt;out-of-band-application security testing (OAST)&lt;/a&gt;.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Conquer client-side attack surfaces&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Hybrid AST and built-in JavaScript analysis engine help to find holes in client-side attack surfaces.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Fuel vulnerability coverage with research&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Cutting-edge scan logic from PortSwigger Research combines with coverage of over 100 generic bugs.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Fine-tune scan control&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Get fine-grained control, with a user-driven scanning methodology. Or, run “point-and-click” scans.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Remediate bugs effectively&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Custom descriptions and step-by-step remediation advice for every bug, from   &lt;a href="https://portswigger.net/research" rel="noopener" target="_blank"&gt;PortSwigger Research&lt;/a&gt;.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Configure scan behavior&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Customize what you audit, and how. Skip specific checks, fine-tune insertion points, and much more.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Navigate difficult applications&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Crawl more complex targets. Burp Suite’s crawler identifies locations based on content - not just URL.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Effectively apply IAST&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Source identification and vulnerability reporting simplified, with optional code instrumentation.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Experience browser-driven scanning&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Browser-driven scanning is already striding toward better coverage of tricky targets like AJAX-heavy single page apps.&lt;/p&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;  &lt;a href="https://sysin.org/#Productivity-tools-&amp;#29983;&amp;#20135;&amp;#21147;&amp;#24037;&amp;#20855;" title="Productivity tools &amp;#29983;&amp;#20135;&amp;#21147;&amp;#24037;&amp;#20855;"&gt;&lt;/a&gt;Productivity tools 生产力工具&lt;/h3&gt; &lt;ul&gt;  &lt;li&gt;Deep-dive message analysis&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Show follow-up, analysis, reference, discovery, and remediation in a feature-rich HTTP editor.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Utilize both built-in and custom configurations&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Access predefined configurations for common tasks, or save and reuse custom configurations.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Multiply project options&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Auto-save all working projects to disk, and add configurations to pre-saved projects.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Make code more readable&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Automatically pretty-print code formats including JSON, JavaScript, CSS, HTML, and XML.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Easily remediate scan results&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;See source, discovery, contents, and remediation, for every bug, with aggregated application data.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Simplify scan reporting&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Customize with HTML/XML formats. Report all evidence identified, including issue details.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Speed up data transformation&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Decode or encode data, with multiple built-in operations (e.g. Hex, Octal, Base64).&lt;/p&gt; &lt;p&gt;  &lt;img alt="Burp Suite Pro pretty-printing" src="https://portswigger.net/burp/pro/features/images/pretty-print.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;hr&gt;&lt;/hr&gt; &lt;h3&gt;  &lt;a href="https://sysin.org/#Extensions-&amp;#25193;&amp;#23637;" title="Extensions &amp;#25193;&amp;#23637;"&gt;&lt;/a&gt;Extensions 扩展&lt;/h3&gt; &lt;p&gt;  &lt;img alt="PortSwigger BApp Store" src="https://portswigger.net/burp/pro/features/images/bapp-store.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Create custom extensions&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Extender API ensures universal adaptability. Code custom extensions to make Burp work for you.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Logger++&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;For in-depth vulnerability detail, ordered and arranged in an easily accessible table, make use of   &lt;a href="https://portswigger.net/bappstore/470b7057b86f41c396a97903377f3d81" rel="noopener" target="_blank"&gt;Logger++&lt;/a&gt;.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Autorize&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;When testing for authorization vulnerabilities, save time and perform repeat requests with   &lt;a href="https://portswigger.net/bappstore/f9bbac8c4acf4aefa4d7dc92a991af2f" rel="noopener" target="_blank"&gt;Autorize&lt;/a&gt;.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Turbo Intruder&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Configured in Python, with a custom HTTP stack,   &lt;a href="https://portswigger.net/bappstore/9abaa233088242e8be252cd4ff534988" rel="noopener" target="_blank"&gt;Turbo Intruder&lt;/a&gt; can unleash thousands of requests per second.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;J2EE Scan&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Expand your Java-specific vulnerability catalogue and hunt the most niche bugs, with   &lt;a href="https://portswigger.net/bappstore/7ec6d429fed04cdcb6243d8ba7358880" rel="noopener" target="_blank"&gt;J2EEScan&lt;/a&gt;.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Access the extension library&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The   &lt;a href="https://portswigger.net/bappstore" rel="noopener" target="_blank"&gt;BApp Store&lt;/a&gt; customizes and extends capabilities. Over 250 extensions, written and tested by Burp users.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Upload Scanner&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Adapt Burp Scanner’s attacks by uploading and testing multiple file-type payloads, with   &lt;a href="https://portswigger.net/bappstore/b2244cbb6953442cb3c82fa0a0d908fa" rel="noopener" target="_blank"&gt;Upload Scanner&lt;/a&gt;.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;AuthMatrix&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Run   &lt;a href="https://portswigger.net/bappstore/30d8ee9f40c041b0bfec67441aad158e" rel="noopener" target="_blank"&gt;AuthMatrix&lt;/a&gt; with Autorize to define your access-level vulnerability authorization check.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Param Miner&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Quickly find unkeyed inputs with   &lt;a href="https://portswigger.net/bappstore/17d2949a985c4b7ca092728dba871943" rel="noopener" target="_blank"&gt;Param Miner&lt;/a&gt; - can guess up to 65,000 parameter names per second.&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;Backslash Powered Scanner&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Find research-grade bugs, and bridge human intuition and automation, with   &lt;a href="https://portswigger.net/bappstore/9cff8c55432a45808432e26dbb2b41d8" rel="noopener" target="_blank"&gt;Backslash Powered Scanner&lt;/a&gt;.&lt;/p&gt; &lt;h2&gt;  &lt;a href="https://sysin.org/#&amp;#19979;&amp;#36733;&amp;#22320;&amp;#22336;" title="&amp;#19979;&amp;#36733;&amp;#22320;&amp;#22336;"&gt;&lt;/a&gt;下载地址&lt;/h2&gt; &lt;p&gt;官方版本：Professional / Community 2021.10  &lt;br /&gt;  百度网盘链接：  &lt;a href="https://pan.baidu.com/s/1jlqpII0Ibu2jwrk82je3JA" rel="noopener" target="_blank"&gt;https://pan.baidu.com/s/1jlqpII0Ibu2jwrk82je3JA&lt;/a&gt;  提取码：pjtm&lt;/p&gt; &lt;p&gt;本站特别版：今天刚刚发布，需要测试验证后更新。&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;p&gt;Burp Suite Pro for macOS    &lt;br /&gt;百度网盘链接：&lt;/p&gt;   &lt;p&gt;集成 keygen，直接运行，无需额外安装 Java    &lt;br /&gt;    &lt;img alt="burp-dmg" src="https://sysin.org/burp-dmg.png"&gt;&lt;/img&gt;&lt;/p&gt;   &lt;p&gt;修复原版图标，Big Sur 图标适配    &lt;br /&gt;    &lt;img alt="burp-icon" src="https://sysin.org/burp-icon.png"&gt;&lt;/img&gt;&lt;/p&gt;   &lt;p&gt;已知问题：首次运行窗口会变得非常小，拖拽，下次启动即可正常。应用程序运行显示的图标是 java 的图标，比较丑陋，因为破解使用 java loader 导致。&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;Burp Suite Pro for Linux    &lt;br /&gt;百度网盘链接：&lt;/p&gt;   &lt;p&gt;安装：    &lt;code&gt;chmod +x burpsuitepro-linux-2021.10.bin &amp;amp;&amp;amp; sudo ./burpsuitepro-linux-2021.10.bin&lt;/code&gt;&lt;/p&gt;   &lt;p&gt;集成安装、注册和卸载    &lt;br /&gt;    &lt;img alt="burp-install" src="https://sysin.org/burp-install.png"&gt;&lt;/img&gt;&lt;/p&gt;   &lt;p&gt;主界面一览    &lt;br /&gt;    &lt;img alt="burp-main" src="https://sysin.org/burp-main.png"&gt;&lt;/img&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>Security macOS Linux HTTP</category>
      <guid isPermaLink="true">https://itindex.net/detail/61867-burp-suite-pro</guid>
      <pubDate>Tue, 02 Nov 2021 10:34:22 CST</pubDate>
    </item>
    <item>
      <title>研究发现全球一半屋顶安装太阳能电池板即可满足整个社会电力需求</title>
      <link>https://itindex.net/detail/61824-%E7%A0%94%E7%A9%B6-%E5%8F%91%E7%8E%B0-%E5%85%A8%E7%90%83</link>
      <description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;屋顶太阳能电池板比2010年时便宜了79%。这些暴跌使得屋顶太阳能光伏发电对那些希望减少对电网的依赖，同时减少碳足迹的家庭和企业更具吸引力。  &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;img alt="15395f7df4484ff.jpg" src="https://static.cnbetacdn.com/article/2021/1015/379319397cb56c0.jpg"&gt;&lt;/img&gt;  &lt;br /&gt;&lt;/p&gt; &lt;p&gt;研究人员发现只需要将世界上50%的屋顶覆盖上太阳能电池板，就可以提供足够的电力来满足世界的年度需求。研究人员设计了一个程序，纳入了3亿多座建筑的数据，并分析了1.3亿平方公里的土地，几乎是地球的整个陆地面积。这项研究估计了这些土地上存在的20万平方公里屋顶上可以产生多少能源，这个面积与英国的面积大致相同。&lt;/p&gt; &lt;p&gt;然后，研究人员通过观察这些屋顶的位置来计算其发电潜力。一般来说，位于高纬度地区的屋顶，如欧洲北部或加拿大，由于冬季和夏季之间日照的巨大差异，其全年的发电潜力可能相差多达40%。然而，位于赤道附近的屋顶，由于日照更加稳定，通常在不同季节的发电潜力只有1%左右的变化。这很重要，因为这些每月潜力的巨大变化会对该地区太阳能发电的可靠性产生重大影响。这意味着日照更不规律的地方需要储能解决方案，这就增加了电力成本。&lt;/p&gt; &lt;p&gt;研究结果强调了屋顶太阳能发电的三个潜在热点。亚洲、欧洲和北美洲。其中，亚洲看起来是安装电池板最便宜的地方，在印度和中国这样的国家，一千瓦时（kWh）的电力，大约相当于48小时使用笔记本电脑消耗的电力，只需0.05便士就可以生产。这要归功于廉价的电池板制造成本，以及阳光充足的气候。同时，实施屋顶太阳能最昂贵的国家是美国、日本和英国。欧洲处于中间位置，整个欧洲大陆的平均成本约为每千瓦时0.096便士。&lt;/p&gt; &lt;p&gt;屋顶太阳能电池板看起来在人口少的地区和在城市中心同样有用。对于那些生活在偏远地区的人来说，太阳能电池板有助于补充甚至取代可能不可靠的当地电网的供应。而对于城市里的人来说，电池板可以大大减少因燃烧化石燃料获取能源而造成的空气污染。&lt;/p&gt;  &lt;p&gt;  &lt;a href="https://m.cnbeta.com/comment/1190509.htm"&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 />
      <guid isPermaLink="true">https://itindex.net/detail/61824-%E7%A0%94%E7%A9%B6-%E5%8F%91%E7%8E%B0-%E5%85%A8%E7%90%83</guid>
      <pubDate>Fri, 15 Oct 2021 02:06:39 CST</pubDate>
    </item>
    <item>
      <title>中国动画现在的发展如何？</title>
      <link>https://itindex.net/detail/61738-%E4%B8%AD%E5%9B%BD%E5%8A%A8%E7%94%BB-%E5%8F%91%E5%B1%95</link>
      <description>&lt;div&gt;
  &lt;div&gt;

   &lt;div&gt;



&lt;/div&gt;

   &lt;div&gt;




    &lt;div&gt;


     &lt;div&gt;

      &lt;strong&gt;
       &lt;img src="https://pic1.zhimg.com/v2-e67a051abc3c44b7b0ab24d72dae386f_l.jpg?source=8673f162"&gt;&lt;/img&gt;
次元研究，次元观测者，知性中二病。微信公众号“次元研究”，全网同名。
       &lt;a href="https://www.zhihu.com/question/21831384/answer/2081202766"&gt;查看知乎原文&lt;/a&gt;
&lt;/strong&gt;

      &lt;div&gt;
       &lt;blockquote&gt;如今的国产动画电影在创作风格上普遍呈现“日美中”三国的混搭，刻薄地说，就是“用中国题材，以美国形式，讲日式二次元故事”。&lt;/blockquote&gt;
       &lt;p&gt;《大圣归来》在 2015 年暑期档斩获的 9.54 亿元票房和因该片而流行开的“自来水”概念，被认为是“国漫崛起”的重要标志（“国漫”这个词将动画与漫画混为一谈，但作为一个已经在大众媒体流传开来的经典误用，本文仅在此使用一次，特此注明）。相比于“昙花一现”的“国产科幻崛起”，仅针对成年观众的国产三维动画长片这一细分门类来说，这六年来创作者与市场给予了一定的持续性正向反馈。如今的大陆电影市场上，国产动画电影是一条热门赛道，不仅是每个档期必备的重要种子选手，催生了如《哪吒：魔童降世》50.35 亿元的票房奇迹，甚至已经在特殊档期能够承载“救市”的期待（如今年 7 月上映的《白蛇 2：青蛇劫起》），制片方借助 IP 实现“电影宇宙”的构建也不再是空谈。&lt;/p&gt;
       &lt;p&gt;可以说，国产动画电影这一类型片种在大陆市场上的持续性输出和商业成功是具有开创性的，无论是从横向还是纵向观察，在任何一个电影市场上都是少见的——完全可以说，国产动画电影的发展，正是近年来“讲述中国故事”这一文化路线的实操成果。&lt;/p&gt;
       &lt;p&gt;然而，这条赛道越发热门，竞争就越发激烈，每年试图分一杯羹的“炮灰”数不胜数。即使是在市场上得到良好反馈的作品，也不一定满足了创作者和观众热情饱满的期待；对国产动画电影的火爆现状终究会归于沉寂的担忧声音，在每一部“出圈”的动画电影上映时都会响起。实际上，当初业界惊呼“产业崛起”时的高涨情绪，经过六年之后，逐渐被某种流于日常的平庸感所攫取：这一行业和类型到了现在，已经没什么“惊奇”可言。&lt;/p&gt;
       &lt;p&gt;虽然作品还在持续不断地推出，票房也都基本达到预期，然而国产动画电影在翻过高山之后，似乎进入到一个波澜不惊的平庸期：目所能及的尝试与突破都已走到尽头，依然信心高涨的创作者们身后，观众和市场仿佛在暗中酝酿一场改换门庭的暗影危机。&lt;/p&gt;
       &lt;img alt="" src="https://pic3.zhimg.com/v2-d35d24cdab0b0b33fa4ca65c030af6d4_720w.jpg?source=8673f162"&gt;&lt;/img&gt;《哪吒之魔童降世》票房破 50 亿海报。图片：《哪吒之魔童降世》电影官方微博       &lt;p&gt;        &lt;strong&gt;国产动画电影的受众到底是谁？&lt;/strong&gt;&lt;/p&gt;
       &lt;p&gt;这个问题荒谬吗？从票房成绩上来看，也许并不。我们可以列出一张 2015 年后比较重要的国产动画电影（非针对儿童市场）票房成绩表：&lt;/p&gt;
       &lt;img alt="" src="https://pic1.zhimg.com/v2-35faa1cb8d149dd646bdc32f795e951b_720w.jpg?source=8673f162"&gt;&lt;/img&gt;       &lt;p&gt;一旦我们将针对儿童市场的《熊出没》系列等片排除出考察范围，国产动画电影的票房成绩显示出一个清晰的基本盘：人民币 3-6 亿。也就是说，如果无法创造全民性的、超越动画电影本身受众范围的“出圈效应”，类似《白蛇》系列这样口碑表现良好的优质 IP 的最终票房射程大致也就在 6 亿左右：虽然这个数字在票房整天“放卫星”的大陆市场毫不起眼，但在动画电影类型中已是极佳的成绩，足以支撑追光动画规划自己的“动画宇宙”；毕竟还有更多作品根本无法企及这一数字，比如创造了足够的话题，却因题材限制致使受众无法扩展的《大护法》，又比如在 2021 年企图借助动画电影风口一飞冲天最终沦为市场失败者的《西游记之再世妖王》（1.13 亿）和《济公之降龙降世》（4064 万）。&lt;/p&gt;
       &lt;p&gt;拨开《哪吒之魔童降世》的“全民神话”，尽管拥有超高的关注度，国产动画电影整体上绝非当今市场特别青睐的类型。真正成功的作品凤毛麟角，想要达到 3-6 亿的基本盘都得费尽心思，类似《哪吒》和《姜子牙》这样的奇迹基本不可复制（实际上，从《姜子牙》的营销投入和观众的期待值来看，16.02 亿的成绩绝非成功）。&lt;/p&gt;
       &lt;p&gt;由此可以解释，为何几乎每部在大陆上映的国产动画电影都不可避免地进行“卖惨”式营销，为何每部作品都是制作方砸锅卖铁苦心孤诣，搞得仿佛一旦失败中国动画就将暗无天日似的，哪怕几年下来观众对这样的营销基本脱敏：虽然这些话术都是俗烂的营销手段，但某种意义上也是现实——制片方肯定掌握更加详细的用户大数据信息，他们的结论就是这个市场不太大。&lt;/p&gt;
       &lt;img alt="" src="https://pic2.zhimg.com/v2-b5567cb7103e81d1b0cb8b7f7e3e380a_720w.jpg?source=8673f162"&gt;&lt;/img&gt;原定于 2020 年大年初一上映的《姜子牙》与《哪吒之魔童降世》的联动海报。图片：《姜子牙》电影官方微博       &lt;p&gt;其实，也可以从近年重要的国产动画电影的选材和创作风格中，勾勒出受众画像。首先，从来没有人把“喜羊羊”和“熊出没”系列当作国产动画崛起的标志，可见其受众群体并不考虑儿童与他们的家长，而是与日本类似，以热爱动漫的青少年和二次元青年人为主；其次则是与美国动画市场类似，主攻在院线上映的动画长片，从角色设置到剧本结构均以迪士尼为师，受众目标是经常光临影院的青年观影群体；其三，选材和文学基础上具有浓郁的网络文学特质，遵循电子游戏的冒险逻辑，品味和审美较为迎合青年男性（哪怕是以女性做主角）——类似“我命由我不由天”“有朝一日权在手”“天道还是人道”的“中二”式男性幻想往往是国产动画电影文本创作的思想底色。&lt;/p&gt;
       &lt;p&gt;有趣的地方是：我们是在勾勒一种类型片的受众吗？不，我们似乎是在精准地筛选出一群特殊而小众的群体。这群人首先有足够的年龄，其次对日式二次元文化有兴趣，又不排斥美国的动画长片文化，又是院线电影的忠实爱好者，既能接受美式三维动画的低龄画风，还热衷于修仙武侠题材的网络文学与中二的成长叙事——这样的用户画像几乎是“缝合怪”，它不是寻找观众的最大公约数，反而是在筛选核心观众，本质上是与尽可能包括所有群体的“合家欢”商业逻辑相违背的。&lt;/p&gt;
       &lt;p&gt;理论上，国产动画电影的风格包罗万象，百花齐放，多元性强，似乎是一个尽量包含了动画爱好者所有能够想到的领域的聚合体，但实际上，它却是一个内在元素时常自相矛盾，对观众来说时而新奇莫名，时而一锅乱炖的“弗兰肯斯坦”。单论创新程度，值得鼓励也颇令人疑惑的事实是：国产动画电影的确走出了一条全新的路径，创造出了一套中国大陆独有的动画电影语汇，的确拍摄出了世界罕见，绝对“中国特色”的动画电影。这甚至与观众不完全相关，与制片方的商业规划也不完全符合，甚至追溯到本源，可能和中国最早的那一批动画导演的个人经历与审美有关。&lt;/p&gt;
       &lt;img alt="" src="https://pic1.zhimg.com/v2-3efbdefd55f4f61901ceb397b0a5171a_720w.jpg?source=8673f162"&gt;&lt;/img&gt;风格颇受宫崎骏影响的《大鱼海棠》剧照。图片：豆瓣电影       &lt;p&gt;总的来说，如今的国产动画电影在创作风格上普遍呈现“日美中”三国的混搭，刻薄地说，就是“用中国题材，以美国形式，讲日式二次元故事”。&lt;/p&gt;
       &lt;p&gt;其一，国产动画电影的创作者不可避免地有爱好日式二次元的背景，这一背景对创作最大的影响是：否认动画是一种只面向儿童的艺术形式，认为动画可以用来讲述任何年龄段都能欣赏的故事。与此同时，却又因为创作者自身年龄的取向，较为专注于写作青少年的个人成长故事。&lt;/p&gt;
       &lt;p&gt;其次，作为在院线上映的电影，从形式上就受到美国动画长片创作风格的影响。首先是剧本写作上的结构式模仿，主打追寻个人价值、认识自我的美式主题诉求与日式成长故事的融合；从人物设置上拷贝美国动画的既有经验，比如必然为主角建设一个跟班小分队，肯定存在一到两个模仿梦工厂动画片的搞笑角色，基本会为主角安排“萌宠”；剧本结构完全按照好莱坞商业电影的三段式逻辑来写作，处处追求“大片”范，最后一幕主角的“重新崛起”已成为固定套路和规范习题；&lt;/p&gt;
       &lt;p&gt;值得一提的是，除了少数画风独特的作品，国产动画电影基本采取美国动画电影低龄非真人比例的三维画风，这一选择是否与技术能力和成本控制有关尚有争议（毕竟如今国产单机游戏开发都已普遍使用虚幻 4 引擎），但却从根本上导致国产动画电影时常以低幼的合家欢画风，表现成熟深刻（抑或是故作深沉的中二伪深度）的故事，无时不在的本质违和感近乎荒谬。&lt;/p&gt;
       &lt;p&gt;其三，在多重因素的鼓励下，国产动画电影大都把自身的创作与“国潮”“传播中华传统文化”“讲述中国故事”绑定，自我规定为中国经典神话 IP 的再创作。《西游记》《封神榜》和《白蛇传》三大源流基本上垄断了目前大多数国产动画电影的选题，导致六年来总数虽不到二十部，但很多人物和故事却已经被反复地、多角度地讲述，观众已经进入疲劳期；而从目前的状况看来，解决疲劳的方式却并不是扩展和拓展题材（哪怕只是寻找其他的中国神话和传统故事），相反是以各种视觉风格和文本解读角度不断重述既有的故事，这一发展方向显然是商业投资人的短视所致。&lt;/p&gt;
       &lt;p&gt;回到一开始的问题，这个市场为什么不太大呢？其实，倒不如反问一句：爱好这么独特的“缝合怪”和“创新产物”的受众群体，真的会很大吗？&lt;/p&gt;
       &lt;img alt="" src="https://pic1.zhimg.com/v2-48d264004f490b3d6fa23abf8d0eed5f_720w.jpg?source=8673f162"&gt;&lt;/img&gt;《姜子牙》中的萌宠“四不像”。图片：豆瓣电影       &lt;p&gt;        &lt;strong&gt;“剧本医生都不想再见到的程度”&lt;/strong&gt;&lt;/p&gt;
       &lt;p&gt;无论是业界还是观众，真正意义上认可国产动画产业的成功，都得从《大圣归来》和《哪吒之魔童降世》算起：国内的舆论环境显然认为在院线上映的电影长片才是“登堂入室”的标准，来自日本的以漫画和电视剧集为主，以“剧场版”“大电影”为辅助的模式并不被国人认可。既然把主战场放在院线，观众必然要以商业电影的标准来看待国产动画电影——那么，六年来我们遇到过几部剧本“合格”，可以被称为“剧本写作”的国产动画电影呢？有一说一，这个数字恐怕不多；虽然整个业界都知道“内容为王”，也绝对不是不重视编剧和剧本质量，每次都和观众保证编剧绝对用心了，然而大多数国产动画电影最后的剧本，恐怕都还是好莱坞的“剧本医生”都不想再见到的程度。&lt;/p&gt;
       &lt;p&gt;首要问题是俗套。鉴于我们的题材集中于《西游记》《封神榜》和《白蛇传》这三个 IP 里，“创意”这个词的定义对国产动画编剧来说显然改变了，从创造变成了阐释，变成对古代故事进行现代解读。可是，为什么几乎每一个剧本的主旨都是寻找自我与自我实现呢？这未免太过于“现代性”了一些，我们的每个主角几乎一开始都不愿意做自己，都遇到了青春期的成长问题，暴躁、易怒、对世界有不一样的理解，满腔反抗精神，拷问自我的价值，从挫折中屡败屡战，寻找人生的解脱道路，并一定在故事的最后“找回了自己”，成为了“标题的那个人”——算了啰嗦了，其实我们的每个主角都是孙悟空，要么是周星驰的，要么是今何在的。&lt;/p&gt;
       &lt;p&gt;当然，每部商业电影都存在主角自我实现这一母题，这固然不错，但相较于漫威宇宙采取的“类型片巡礼”路线——以谍战片、战争片、宫廷史诗片、无厘头喜剧片等各种类型来包裹超级英雄内核，国产动画电影这六年来的实践，大多数只选择了动作冒险片，甚至刻薄地说，是武侠偶像剧这唯一的类型路径。主题陈旧，孙悟空整天拷问自我，不知道自己是谁；剧本类型单一，不按“勇者斗恶龙”的冒险模式走就无法展开剧情；大多数时候，观众希望看到令人眼前一亮的故事基本是一种奢求。&lt;/p&gt;
       &lt;img alt="" src="https://pica.zhimg.com/v2-e8bec215de14356993f29b53144dd91e_720w.jpg?source=8673f162"&gt;&lt;/img&gt;《美国队长 2》从剧作上是一部谍战片。图片：豆瓣电影       &lt;p&gt;然而，哪怕是为了商业诉求上的安全采取既定的动作冒险片模式，兢兢业业完成的话至少不过不失，足以保证电影其他亮点的展现；但部分国产动画电影的剧本写作堪称敷衍，基本只是为了满足套路需求，为事先预设的大场面戏码提供甚至都说不太过去的理由。21 世纪以来网络文学的“升级打怪”套路，或者说电子游戏所带来的清关思维取代了基本的情节写作，借自迪士尼的“萌宠”和借自梦工厂的主角团队内部搞笑吐槽互动取代了基本的人物塑造。&lt;/p&gt;
       &lt;p&gt;2021 年春节档的《新神榜：哪吒重生》被调侃为“靠死人推进剧情”，这个来自“民国蒸汽朋克”世界，开机车的“新哪吒”，连内心挣扎和自我实现戏码都欠奉，整部电影除了依靠亲人受伤和死亡一步步开发“小宇宙”提升战力之外，就不存在心理意义上的“成长”，剧情就是不断铺陈“挫折——变强——挫折——变更强——挫折——变超强”的“逆袭爽剧”，与动作冒险电子游戏的通关过程达成高度的形式一致性，导致电影完全沦为只为展现动作场面和技术能力、毋需观众操作的电子游戏视觉秀。&lt;/p&gt;
       &lt;p&gt;其三，剧作的文学能力和审美品位始终未见提升。堪称“全民观影”的《哪吒之魔童降世》存在的最大争议，就是影片中大量“屎尿屁”风格的喜剧笑料。毫无疑问这是创作者针对商业需求所刻意设计的（也相对放大了导演饺子一贯的品味偏好），事实上也取得了前所未有的票房回报，但是商业电影中负责吸引大众的喜剧元素难道一定要是如此“下三路”的吗？&lt;/p&gt;
       &lt;p&gt;由于国产动画电影的情节和格调基本脱胎于早期网络文学，一定程度上直观暴露了导演和编剧的文化底蕴。类似《姜子牙》中反复提及却流于平面的“人道还是天道”“如何拯救苍生”，《大圣归来》《新神榜：哪吒重生》中被一唱三叹的“弱者逆袭”“强者归位”，这类连网络文学都开始觉得陈腐的“定番”屡次上演，使得国产动画电影始终难以逃脱“中二”的底色，很难立足于经典故事真正讲出现代的新意，缺乏创作者希望拥有的“深刻”。&lt;/p&gt;
       &lt;img alt="" src="https://pic1.zhimg.com/v2-9f6d13e8dd9c78ef97ce4c2fda8353ed_720w.jpg?source=8673f162"&gt;&lt;/img&gt;《白蛇 2：青蛇劫起》中的女性情感刻画。图片：豆瓣电影       &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;img alt="" src="https://pic1.zhimg.com/v2-a9d92c559bfbd12520cee14e06bb7d79_720w.jpg?source=8673f162"&gt;&lt;/img&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;2015 年以来的国产动画产量和票房的崛起，离不开国家文化政策对动漫产业的鼓励与扶持，实际上创作者们也异常自觉地将创作主题集中于传统文化题材，自觉地把自身与“国潮”“讲述中国故事”绑定，始终坚持站在“古风”亚文化的风口。由此可见，说他们沉溺于过往经验、故步自封是不公正的，显然他们足够审时度势，知道要把有限的力气花在哪里——与其下功夫提升观众一时半会看不出来的电影制作水准，不如将精力花在最惹人注意的题材和 IP 上，视觉和剧本只要以公认世界顶级的迪士尼为尊就不会出错；投资人和创作者固然如此精明，但值得反思的问题是，六年来，国产动画电影虽然基本都是国风题材，可是他们真的“讲述中国故事”了吗？&lt;/p&gt;
       &lt;img alt="" src="https://pica.zhimg.com/v2-7e729ab88157a63694f80a0423c3584d_720w.jpg?source=8673f162"&gt;&lt;/img&gt;迪士尼经典动画电影《花木兰》剧照。图片：豆瓣电影       &lt;p&gt;这个问题说得更加直接一点，这些把中国经典神话和名著故事修改成好莱坞式个人成长故事的剧本，讲的是“中国”故事吗？也许，到头来只是一部部由中国人制作的迪士尼《花木兰》而已。这些动画电影在国外有多少影响力呢？甚至于，他们做到在国内范围向国人讲述中国故事的任务了吗？&lt;/p&gt;
       &lt;p&gt;以票房 50.35 亿元的《哪吒之魔童降世》为例，尽管这个例子已经有些老生常谈：一个关于哪吒闹海故事的当代解读，剧本的核心主旨却落在了“家庭价值”之上，很难不令人感到荒谬。如果创作者是想表达传统的家庭价值，中国传统文化宝库中的素材并不缺少，可他们偏偏选择传统文化中反抗父权制的代表哪吒来阐释“父慈子孝”，将原作中哪吒与父权的不共戴天改换成亲情至上，在成长中与父母和解的温情戏码，让本来不服从任何强权的哪吒归顺“天道”，这其中的思维逻辑是如何运转的？&lt;/p&gt;
       &lt;p&gt;有观点认为，现代解读要贴合时代精神，当下家庭价值是一种能够传遍世界的普世价值，这一解读是为了让哪吒的故事走向世界，让更多现代观众和外国观众理解——那么敢问，这部在国内席卷 50.35 亿票房的动画电影，怎么海外票房累计只有 600 多万美元，仅占到全球总票房的 0.5%呢？&lt;/p&gt;
       &lt;p&gt;抛开国产电影海外宣发的不易，最终这个拥护家庭价值的、属于世界的哪吒，还是没有走向世界（倒是一路破坏到底的孙悟空更容易被世界理解一些）。说到底，还是不要给他们戴上“文化输出”的高帽，他们当初选择让哪吒拥护家庭价值的根本原因，只不过是他们认为好莱坞的商业剧本模式是好的，而按照这个剧本模式写作的话，必然需要一个温和的价值观基底，那么直接沿用美国动画电影的“家庭观”是最方便的罢了——票房成绩也证明了他们的远见。&lt;/p&gt;
       &lt;img alt="" src="https://pic1.zhimg.com/v2-fe1e00c3f67df2626f38dc1e00ed7312_720w.jpg?source=8673f162"&gt;&lt;/img&gt;家庭价值是《哪吒之魔童降世》的重要主题。图片：《哪吒之魔童降世》预告片截图       &lt;p&gt;只不过，这一点都不“国潮”，还是一部迪士尼的《花木兰》，而且是 2020 年的真人版；当初迪士尼动画版《花木兰》，甚至在跨文化视野上做得还很多元——别人在北美讲跨文化的中国故事，我们在中国讲普世故事。&lt;/p&gt;
       &lt;p&gt;相较看来，虽然追光动画的《新神榜：哪吒重生》里的哪吒是个没成长的、反对一切的愣头青，剧本完全没有找到成长主题与原作精神的契合点，哪怕影片破除题材和时代限制玩起了蒸汽朋克、赛博朋克和荒野机车，哪怕影片在美术视觉上无限地“反叛”与现代，这个哪吒本质上都比《哪吒之魔童降世》更中国——此时，去批判这几部动画电影的主角塑造其实还是立足于美式个人英雄主义都显得苛求了，毕竟同样是塑造英雄，中国故事与世界故事的差异在哪里还需要进一步探索，但无论如何，都比直接把哪吒“父慈子孝”更中国一些。&lt;/p&gt;
       &lt;img alt="" src="https://pic2.zhimg.com/v2-113c09309f7686c2ef4e5052d954bbb9_720w.jpg?source=8673f162"&gt;&lt;/img&gt;《新神榜：哪吒重生》中的“民国蒸汽朋克”街景。图片：《新神榜：哪吒重生》官方微博       &lt;p&gt;必然会有反对的声音说，这些国产动画电影的票房数字可观，对它们的受众群体大小、剧本和制作水平以及意识形态内容的反思都不成立，毕竟人民群众用电影票说话了——从票房数字的美梦中醒来吧！《白蛇 2：青蛇劫起》救市成功了吗？在《哪吒之魔童降世》成功后被寄予了过高票房期望的国产动画电影，这两年间有哪一部真正达到口碑和票房的预期了呢？&lt;/p&gt;
       &lt;p&gt;六年来观众用爱发电，每次都以拯救中国动画产业的牺牲心态购票入场，面对这些六年来没有什么长进，还在选题和创意上越发枯竭和套路化的作品，用如此的宽容所塑造的票房美梦还能坚持多久呢？距离破灭的日子已经不远了，也许在我们看不到的暗影中，在各大动画制片方还在紧锣密鼓地推出各种片单计划的背后，无论是观众还是投资方，都在默默寻找下一个淘金新风口——“国潮”“古风”依然坚挺，谁都还要吃这碗饭，但谁也没有说一定要在国产动画电影这个被定了型的缝合怪上吊死：其他的选择必然是有的。&lt;/p&gt;
       &lt;p&gt;写作这篇反思录时，我与一名在国产动画电影行业里摸爬滚打多年的老同学做了交流，我询问我的部分想法是不是过分激烈、偏颇了一些，结果她说，“你这么温和是转性了吗？我们内部开会时说得比这狠多了”。她的这句话，可能是我对国产动画电影还抱有最后期望的原因；至少这些显而易见的问题，业界并不是熟视无睹的，之所以长久以来没有被解决，当然不会全是创作者的责任。那么，就一起把这些问题告诉资本方吧：六年来国产动画电影的崛起与“盛世”之下，可能需要一些看向未来的危言。&lt;/p&gt;
       &lt;p&gt;注：文中引用大陆电影市场票房数据来自“猫眼专业版”app；海外电影票房数据来自美国专业网站 Box Office Mojo。&lt;/p&gt;
       &lt;img alt="" src="https://pic1.zhimg.com/v2-e460fa339f4bc667a9fba12d8fb7b7b3_720w.jpg?source=8673f162"&gt;&lt;/img&gt;在日本等海外市场取得一定成功的《罗小黑战记》。图片：豆瓣电影
&lt;/div&gt;
&lt;/div&gt;


     &lt;div&gt;      &lt;a href="https://www.zhihu.com/question/21831384"&gt;查看知乎讨论&lt;/a&gt;&lt;/div&gt;

&lt;/div&gt;


&lt;/div&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 />
      <guid isPermaLink="true">https://itindex.net/detail/61738-%E4%B8%AD%E5%9B%BD%E5%8A%A8%E7%94%BB-%E5%8F%91%E5%B1%95</guid>
      <pubDate>Thu, 26 Aug 2021 08:00:00 CST</pubDate>
    </item>
    <item>
      <title>Apollo配置中心如何实现配置热发布</title>
      <link>https://itindex.net/detail/61398-apollo-%E4%B8%AD%E5%BF%83</link>
      <description>&lt;div&gt;  &lt;h1&gt;引言&lt;/h1&gt;
  &lt;p&gt;配置中心在微服务架构体系中是非常重要的基础设施服务，承担着分布式配置集中管理、配置热发布以及审计等重要的职责。本文主要探讨Apollo配置中心的配置热发布特性如何实现。&lt;/p&gt;
  &lt;h1&gt;配置热发布如何实现&lt;/h1&gt;
  &lt;p&gt;   &lt;strong&gt;1、配置发布主流程&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="&amp;#25130;&amp;#23631;2021-05-07 &amp;#19979;&amp;#21320;9.23.18.png" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fde32c52592443bfad48c9312532a652~tplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;如上图所示，配置发布的主流程如下：&lt;/p&gt;
  &lt;p&gt;（1）用户通过   &lt;code&gt;Portal&lt;/code&gt;向   &lt;code&gt;AdminService&lt;/code&gt;发布配置信息；&lt;/p&gt;
  &lt;p&gt;（2）   &lt;code&gt;AdminService&lt;/code&gt;在配置发布后会往   &lt;code&gt;ReleaseMessage&lt;/code&gt;表插入一条消息记录；&lt;/p&gt;
  &lt;p&gt;（3）   &lt;code&gt;ConfigService&lt;/code&gt;中包含了一个定时线程，该定时线程每秒扫描一次   &lt;code&gt;ReleaseMessage&lt;/code&gt;表，检查表中是否有新的消息记录；&lt;/p&gt;
  &lt;p&gt;（4）如果存在配置更新，   &lt;code&gt;ConfigService&lt;/code&gt;就会通知所有的消息监听器；&lt;/p&gt;
  &lt;p&gt;（5）通知   &lt;code&gt;Controller&lt;/code&gt;会根据发布的配置信息通知对应的客户端；&lt;/p&gt;
  &lt;p&gt;客户端与配置中心的大致交互如下所示：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="676975-20190120180959367-885516894.png" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/78a38441566b43fb9ab403c7d105b8ef~tplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;这里的配置更新推送其实并不是真正进行信息推送，而是通过长轮询来实现配置的更新。实际上并不是配置的更新推送，而是配置更新通知的推送，客户端拿到通知后需要进一步获取具体的变化的配置信息。&lt;/p&gt;
  &lt;p&gt;   &lt;strong&gt;2、长轮询&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;（1）如果使用Push方式推送数据会有什么问题？&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="&amp;#25130;&amp;#23631;2021-05-07 &amp;#19979;&amp;#21320;9.28.17.png" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ec5d32bd1aca4fd6aa1f02a332e16b3a~tplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;服务端需要与客户端建立长连接，服务端有数据更新的时候可以进行数据推送，数据更新比较及时。但是服务端无法感知客户端的处理能力，可能会造成数据积压。另外集群情况下部分节点不在线会通知失败，等客户端又在线后需要进行补偿推送，节点还有可能存在扩容等各种情况。对于配置中心这种业务场景来说，通过Push方式实现数据推动显得复杂了。&lt;/p&gt;
  &lt;p&gt;（2）如果使用Pull方式拉取数据会有什么问题？&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="&amp;#25130;&amp;#23631;2021-05-07 &amp;#19979;&amp;#21320;9.29.17.png" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5541803db5bc47c6a34cb98a1e546081~tplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;
   &lt;code&gt;Pull&lt;/code&gt;模式主要是通过客户端主动向配置中心进行数据请求，拉取对应的配置信息。由于是客户端主动拉取，因此不会出现数据堆积的问题。但是数据如何去拉，什么时间去拉，拉的频率如何控制，这些都是问题。如果频率过高，而配置并未更新，那么就会对服务端造成不必要的连接压力。如果频率过低，那么配置更新就会存在延时的问题。因此同样不适合配置中心的业务场景。&lt;/p&gt;
  &lt;p&gt;（3）长轮询&lt;/p&gt;
  &lt;p&gt;客户端向配置中心进行请求，配置中心不会立即返回响应，而是会   &lt;code&gt;hold&lt;/code&gt;住这个请求直到指定时间超时后进行返回。如果没有配置变更，则返回   &lt;code&gt;Http&lt;/code&gt;状态码   &lt;code&gt;304&lt;/code&gt;给客户端。超时返回后，客户端将再次发起请求。&lt;/p&gt;
  &lt;p&gt;如果存在配置变更，将返回对应的   &lt;code&gt;namespace&lt;/code&gt;信息，客户端根据   &lt;code&gt;namespace&lt;/code&gt;信息获取对应的配置信息。
另外为了保证配置的有效性，客户端也会定时请求配置信息，防止配置更新可能出现的异常情况，是一种数据保证的兜底   &lt;code&gt;fallback&lt;/code&gt;机制。另外当获取到配置后，会同步到本地配置文件中 。这样即便客户端与配置中心无法通信，客户端也可以从本地配置文件中获取配置信息。&lt;/p&gt;
  &lt;p&gt;那么问题来了，为什么不直接在长轮询的响应中直接回复配置信息呢？主要是由于本身已经存在了定时拉取配置的步骤，那么为了保证单一原则以及代码上的简洁以及复用。所以通过这种获取配置更新后再进行数据拉取的方式。&lt;/p&gt;
  &lt;p&gt;   &lt;strong&gt;3、客户端获取配置信息&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;我们一起看下客户端如何工作流程，如下图：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="&amp;#26410;&amp;#21629;&amp;#21517;&amp;#25991;&amp;#20214;.png" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7bb6aa13d9a942a38d021d9882079c48~tplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;（1）C   &lt;code&gt;onfigServiceLocator&lt;/code&gt;：主要负责向   &lt;code&gt;Eruka&lt;/code&gt;注册中心获取   &lt;code&gt;ConfigService&lt;/code&gt;地址列表信息；&lt;/p&gt;
  &lt;p&gt;（2）   &lt;code&gt;RemoteConfigLongPollService&lt;/code&gt;：从   &lt;code&gt;ConfigServiceLocator&lt;/code&gt;获取到地址列表信息后，通过长轮询的方式获取配置变更信息；&lt;/p&gt;
  &lt;p&gt;（3）   &lt;code&gt;RemoteConfigReposity&lt;/code&gt;：从   &lt;code&gt;ConfigService&lt;/code&gt;获取变更的配置数据；&lt;/p&gt;
  &lt;p&gt;（4）   &lt;code&gt;LocalFileConfigReposity&lt;/code&gt;：把配置数据固化到本地，同时作为本地配置数据的来源；&lt;/p&gt;
  &lt;p&gt;（5）   &lt;code&gt;DefaultConfig&lt;/code&gt;：主要和业务方进行交互，提供配置获取方法，同时可以注册配置变更事件。&lt;/p&gt;
  &lt;h1&gt;总结&lt;/h1&gt;
  &lt;p&gt;本文主要探讨了   &lt;code&gt;Apollo&lt;/code&gt;配置中心配置热发布的相关内容，分析了为什么长轮询是比较适合配置中心的数据交互方式。在今后的架构设计中我们也可以以此来作为参考。另外客户端的设计中，也体现了了分层以及职责单一的代码风格，我们自己在实际项目开发中也比较有借鉴的意义。&lt;/p&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 />
      <guid isPermaLink="true">https://itindex.net/detail/61398-apollo-%E4%B8%AD%E5%BF%83</guid>
      <pubDate>Fri, 07 May 2021 13:39:50 CST</pubDate>
    </item>
    <item>
      <title>2020我的Podcasts收听总结，Top10及新发现</title>
      <link>https://itindex.net/detail/61132-podcasts-top10-%E6%96%B0%E5%8F%91%E7%8E%B0</link>
      <description>&lt;div&gt;    &lt;div&gt;      &lt;p&gt;第一次在iTunes上发现podcasts板块还是2012年，中文播客完全没有形成气候，走在路上听点英文财经播客。虽然直到现在，与整个文化消费的受众相比，播客还是非常小众的媒介。但感谢近两年的“播客爆发”，中文播客的内容也足够丰富了，这一年依然要感谢播客的陪伴。&lt;/p&gt;&lt;/div&gt;    &lt;h2&gt;客户端&lt;/h2&gt;    &lt;p&gt;想先从听播客的客户端聊起，我目前主要使用Apple Podcasts和Pocket Casts两个客户端，小宇宙偶尔打开刷刷首页推荐，感兴趣的就转去泛用端上订阅一下。播客是无限的、层出不穷的，而时间精力有限，两个App大致分割了“大概率会点开听”和“先订阅一下看看”两类播客。&lt;/p&gt;    &lt;h3&gt;为什么不用小宇宙&lt;/h3&gt;    &lt;ul&gt;      &lt;li&gt;小宇宙可能是内地市场上最接近泛用型的客户端，但出于众所周知的原因，一些中文节目的个别单集会无声无息地消失，一些英文节目即使添加RSS成为私有节目也并不能保证看到全部的单集。这当然不能全怪小宇宙，但对有许多英文订阅的用户而言，非常影响体验。&lt;/li&gt;      &lt;li&gt;查看shownotes不算方便，在更新feed上需要在5个按钮中选中shownotes，播放界面的shownotes需要通过左下角的小按钮呼出，单手握持手机时很不方便。&lt;/li&gt;      &lt;li&gt;有谜之卡顿。&lt;/li&gt;      &lt;li&gt;缺乏网页端/桌面端。&lt;/li&gt;&lt;/ul&gt;    &lt;h3&gt;Apple Podcasts（美区）&lt;/h3&gt;    &lt;p&gt;优点：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;真·泛用端无需担心内容审查&lt;/li&gt;      &lt;li&gt;查看Shownotes非常方便顺滑，更新feed点details，并没有想象中容易误触，播放界面上滑即可&lt;/li&gt;      &lt;li&gt;推荐区和分类区做得非常棒，单集推荐和节目似乎是依据订阅比较多的类别推荐的，很容易看到喜欢的；新播客和大热播客一目了然，Curated Collection质量很高&lt;/li&gt;      &lt;li&gt;喜欢界面&lt;/li&gt;      &lt;li&gt;与系统深度整合，尤其是通过imessage分享非常好看&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;缺点：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;倍速划分过于粗糙，iOS端只有0.5x、1.0x、1.5x、2.0x四档，Mac端加了1.25x&lt;/li&gt;      &lt;li&gt;播放列表不好用，点开列表外的播客，就要重新做列表了&lt;/li&gt;      &lt;li&gt;Shownotes至今无法显示图片&lt;/li&gt;      &lt;li&gt;不支持OPML导入和导出&lt;/li&gt;      &lt;li&gt;MacOS端App巨卡无比，可能是用脚写的&lt;/li&gt;&lt;/ul&gt;    &lt;h3&gt;Pocket Casts&lt;/h3&gt;    &lt;p&gt;优点：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;真·泛用端无需担心内容审查&lt;/li&gt;      &lt;li&gt;全平台同步（web/桌面端需要Pocket Casts Plus，一年$9.99）&lt;/li&gt;      &lt;li&gt;美好的播放列表、标⭐️️、过滤器体验（但永远听不完容易越攒越多&lt;/li&gt;      &lt;li&gt;精确到0.1x的可调倍速&lt;/li&gt;      &lt;li&gt;较为方便的Shownotes查看体验：更新feed端点开上滑，因为封面和字体比Apple Podcasts大，浏览完shownotes的时间多一点点；播放界面直接左滑&lt;/li&gt;      &lt;li&gt;支持OPML导入和导出&lt;/li&gt;      &lt;li&gt;多种主题和图标可选，外观可以换换口味&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;缺点：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;iOS端暂时只有英文界面，安卓端我没用过暂不清楚，网页/桌面端语言可选中文&lt;/li&gt;      &lt;li&gt;搜索栏只支持搜索节目名和RSS，不支持按关键字搜索某个主题相关播客&lt;/li&gt;      &lt;li&gt;因对老旧格式的RSS支持不佳，部分蜻蜓提供的RSS无法播放（受灾播客包括但不限于西夏酒馆、GQ Talk、宇宙乘客）。&lt;/li&gt;&lt;/ul&gt;    &lt;div&gt;      &lt;hr&gt;&lt;/hr&gt;&lt;/div&gt;    &lt;h2&gt;2020年个人Top 10&lt;/h2&gt;    &lt;p&gt;主要提一下今年开始听得比较多的播客，一直听了两三年的就不算在内了，也尽量避开听众人数太多的大热台，私心想给相对小众的节目增加一点曝光机会。&lt;/p&gt;    &lt;h3&gt;时差In-Betweenness&lt;/h3&gt;    &lt;p&gt;&lt;/p&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823223.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;年度最爱播客，主播都在学术圈里，Shownotes可能是中文播客中最硬核的，有格式整齐的各种论文和专著。内容依托主播的背景，信息密度很大，也非常硬，时常觉得需要重听和做笔记。目前更新了8期，主要是身份政治和国际关系主题，经过几个时事热点，这类话题今年在中文播客界讨论度已经相当高了，“时差”的可贵在于系统性、严谨性和深度，以及一手的研究经历（比如上海交大副教授沈洋讲述自身的田野经历），提供了扎实而新鲜的信息。&lt;/p&gt;    &lt;p&gt;没什么想对主播说的，只求赶紧开打赏通道或者会员计划，钱已经准备好了。      &lt;a href="https://www.douban.com/people/sirius_cc/" rel="nofollow"&gt;@dustette&lt;/a&gt;      &lt;a href="https://www.douban.com/people/vulabula/" rel="nofollow"&gt;@乌拉&lt;/a&gt;&lt;/p&gt;    &lt;h3&gt;Arts &amp;amp; Ideas&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823244.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;BBC Radio 3出品，综合人文节目，聊哲学时很硬核（毕竟我什么都不懂），比如“后真相与德里达”“黑格尔的权利论”，虽然形式是圆桌访谈，但英文+完全不熟的哲学话题令人几乎不能分心，走在街上看路牌都会错过几个词；此外也有一些文学、社会学、政治学议题，是比较难得、严肃、有一定深度的文化类对谈节目。&lt;/p&gt;    &lt;p&gt;冬至“winter light”那一集请了当红物理学家Brian Cox、考古学家Susan Greaney、作家/学者Alexandra Harris、哲学家Sophie Grace Chappell一起聊冬天的阳光和星星，洋溢着四个领域交汇的浪漫。&lt;/p&gt;    &lt;h3&gt;跳岛FM&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823257.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;中信大方出品的文学播客，也是热门播客了，尤其是在豆瓣上，但是考虑到跳岛是周更的节目里唯一一档我每期都会听完的，还是有必要把它列出来。出版方聊文学实在是自然不过的事情，跳岛也算是走在前面，主持、嘉宾、选题均上乘，质量比较稳定，非常知道应该请什么人聊什么话题，聊出火花时就既有氛围也有内涵。很多期都印象深刻，比如第一期作家中的性别研究，过劳时代，上海郊区牧歌，台湾文学内向世代，幽默，即兴，阿特伍德的女权观，何伟在中国的经历，路易丝·格丽克的作品解读。      &lt;a href="https://www.douban.com/people/70796084/" rel="nofollow"&gt;@猫弟 maud&lt;/a&gt;      &lt;a href="https://www.douban.com/people/146169906/" rel="nofollow"&gt;@中信大方&lt;/a&gt;&lt;/p&gt;    &lt;h3&gt;The Documentary Podcast&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823275.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;真正具有宽广的国际视野的纪录播客，只有世界各地有据点的大媒体有资源和能力做这样的事。在这里能听到全世界的故事：地中海偷渡难民的沉船、波兰的LGBT运动、非洲大片未经测绘的土地，当然也有英美一地鸡毛的政治闹剧。The Documentary最有价值的部分在于能接触到一些平时极少关注到、完全陌生的地点发生的故事，但它们绝不是不值得被看到的。&lt;/p&gt;    &lt;h3&gt;Backlisted&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823305.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;聊书的谈话类播客，顾名思义不聊新书，而且一部分书是讨论度不算很高的经典，比如威廉·詹姆斯的《宗教经验种种》、左拉的《泰雷兹·拉甘》，我很喜欢主播和嘉宾聊书时轻松、幽默、真诚的氛围，有时他们会读一些选段，像在读书会现场一样舒适。既能发现闻所未闻的书，也能从主播和嘉宾看待文本的视角中获得很多教益。&lt;/p&gt;    &lt;h3&gt;Naive咖啡馆&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823365.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;理想国旗下的播客，主要聊理想国出版的书和人文向话题，相比跳岛FM的文学气质，Naive咖啡馆更偏向社科，选题颇具野心，信息密度也很大，Papi酱生子时那期讨论女权主义脉络的单集在众多同质化的女权话题播客中鹤立鸡群，其他印象很深的单集还有陈嘉映与周濂的对谈、戴锦华和汪晖聊陈映真、英国工业革命、富勒的生平和主张。      &lt;a href="https://www.douban.com/people/imaginister/" rel="nofollow"&gt;@理想国&lt;/a&gt;&lt;/p&gt;    &lt;h3&gt;GQ Talk&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823323.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;虽然年初爆更一波后来就沉默，直到前不久才更新了两集，我依然觉得GQ Talk是中文播客中做得最棒的访谈播客之一。时尚媒体加非虚构的基因，能请到从娱乐圈到文化行业的各种名人做访谈，主持人也很会提问，能聊出不太一样的点，停更是有点可惜。&lt;/p&gt;    &lt;h3&gt;Vibration 歪波音室&lt;/h3&gt;    &lt;p&gt;&lt;/p&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823324.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;我在音乐上一向没什么品味和追求，在夏天听到citypop时瞬间凭着本能的喜爱入坑，在大脑很累不想接受信息输入的时候，总是会打开Vibration听歌，可以一边听一边神游，也非常适合做写作时的BGM ，Vibrarion就此成为我收听率最高的播客之一。拾壹的推荐总是很温柔又疗愈，请嘉宾做的访谈也又轻又走心。&lt;/p&gt;    &lt;h3&gt;晚风说&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823328.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;也是访谈播客，主持人Jade是月光一样的女性，她的采访非常具有个人特色，仔细倾听，无比包容，从不judge，提出顺理成章的问题。晚风说的嘉宾很少有如雷贯耳的名字，基本都是主播的朋友或者非常感兴趣的人，每个人有各自独特而精彩的个性，有不同的经历和对世界的看法，这些使得这档播客丰富、真诚又温柔。&lt;/p&gt;    &lt;h3&gt;鼓腹而游&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823329.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;鼓腹而游是介于“知识输出”与“闲聊”之间的节目，非常喜欢三位主播聊天时的化学反应，比起圆桌访谈更像朋友之间的聊天，随手把话题与自己的经历、读过的书勾连起来。决定这档播客“知识型”属性的是几位文化记者的职业特性和广泛阅读的习惯，既能做到旁征博引，又能保证拆解问题的视角有一定深度，不至于浮皮潦草。鼓腹而游一度是我运动时最爱听的播客，可以不用集中全副注意力，又能保证信息量而不至于单纯吹水，同时聊天气氛又非常棒。程主播谈兴上来会打断其他主播讲话，但大家是朋友好像对此也习惯了，新的一年唯愿三位谈兴更浓点，多更几期。      &lt;a href="https://www.douban.com/people/nellylin/" rel="nofollow"&gt;@Nelly.L&lt;/a&gt;      &lt;a href="https://www.douban.com/people/grenadier/" rel="nofollow"&gt;@Grenadier&lt;/a&gt;&lt;/p&gt;    &lt;h2&gt;Shownotes典范&lt;/h2&gt;    &lt;p&gt;作为听播客必看shownotes的听众，是一定要评几个Shownotes可以拿来做范文的节目的。&lt;/p&gt;    &lt;p&gt;除去带跳转或不带跳转的时间轴，Shownotes还有很大发挥的余地。&lt;/p&gt;    &lt;h3&gt;迟早更新&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823468.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;迟早更新最难以替代的部分除了任宁的声音，就是看似不相关信息之间的跳跃的联结，因此任宁和枪枪给这些联结准备了非常详细的🔗️放在shownotes里，这些🔗️经过主播筛选，通常提供了极好的入门介绍。&lt;/p&gt;    &lt;h3&gt;Casticle&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823477.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;糊糊的每期节目准备量也是非常惊人，英文播客的世界实在太大，糊糊总能让我看到新世界的大门，与“迟早更新”一样，Casticle的Shownotes也值得阅读。&lt;/p&gt;    &lt;h3&gt;不可理论 &amp;amp; Byte.Coffee&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823485.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;&lt;/p&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823489.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;加上Casticle，可能是我最喜欢的三档中文单口播客，shownotes有相当多的好书和值得阅读的文章，内容非常翔实，共同点是更新极其缓慢（发出催更的声音。Update：发完就发现时隔半年多，不可理论更新了，我要多写点播客日记。&lt;/p&gt;    &lt;h2&gt;2020新发现&lt;/h2&gt;    &lt;p&gt;这里是几档我听下来觉得质量不错，但要么比较新，要么还不大熟的节目，暂时辟个“新发现”推荐吧。&lt;/p&gt;    &lt;h3&gt;Lolita Podcast&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823499.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;非常难得的围绕纳博科夫的《洛丽塔》原著聊的播客，聊文本、电影、演员、时尚审美、伦理争议，极少有一部文学作品能在作者去世后的几十年还带给世界这么大的影响，这档播客把这些余音收集起来十分有趣，几相对照，无论是喜爱文学、文化还是纳博科夫，都能从中找到需要的东西。&lt;/p&gt;    &lt;h3&gt;You&amp;apos;re Wrong about&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823506.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;不算新播客，在Apple Podcasts美区年度播客里发现的，每期聊一个被大众误解的知识，两位主播声音非常好听，尤其喜欢女主播的口音，听上去慵懒随意但不会影响清晰度，还没听几期，但是很喜欢这种节目。&lt;/p&gt;    &lt;h3&gt;半影fm&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823517.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;半影是“一个关注、连接、赋能中国女性创造者的平台”，半影fm是女性主义节目，也是聚焦艺术、创意、创作的节目。主播和嘉宾专业的艺术知识、细致的感受力，艺术/创作中展现出的女性力量是这档播客最为迷人的部分，在不少女性主义播客中令人耳目一新。&lt;/p&gt;    &lt;h3&gt;惊奇电台&lt;/h3&gt;    &lt;div&gt;      &lt;div&gt;        &lt;img height="auto" src="https://img9.doubanio.com/view/note/l/public/p78823523.webp"&gt;&lt;/img&gt;&lt;/div&gt;&lt;/div&gt;    &lt;p&gt;读客做的主打科幻作家和作品的播客，质量相当不错（与其书籍封面设计简直天差地别），第二集就请了戴锦华聊厄休拉·勒古恩，再之后聊阿瑟·克拉克、阿西莫夫、道格拉斯·亚当斯、小林泰三、沙丘的几期都很棒，请的嘉宾对作家和作品都很了解，没有浮于表面，而是探讨作品的世界观设定、结构、语言、灵感来源、衍生文化（比如电影改编）。&lt;/p&gt;    &lt;p&gt;&lt;/p&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 />
      <guid isPermaLink="true">https://itindex.net/detail/61132-podcasts-top10-%E6%96%B0%E5%8F%91%E7%8E%B0</guid>
      <pubDate>Sat, 02 Jan 2021 09:44:54 CST</pubDate>
    </item>
    <item>
      <title>基于 gRPC 的注册发现与负载均衡的原理和实战</title>
      <link>https://itindex.net/detail/61062-grpc-%E5%8F%91%E7%8E%B0-%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1</link>
      <description>&lt;p&gt;  &lt;a href="https://github.com/grpc/grpc-go" rel="nofollow"&gt;gRPC&lt;/a&gt;是一个现代的、高性能、开源的和语言无关的通用 RPC 框架，基于 HTTP2 协议设计，序列化使用 PB(Protocol Buffer)，PB 是一种语言无关的高性能序列化框架，基于 HTTP2+PB 保证了的高性能。  &lt;a href="https://github.com/tal-tech/go-zero" rel="nofollow"&gt;go-zero&lt;/a&gt;是一个开源的微服务框架，支持 http 和 rpc 协议，其中 rpc 底层依赖 gRPC，本文会结合 gRPC 和 go-zero 源码从实战的角度和大家一起分析下服务注册与发现和负载均衡的实现原理&lt;/p&gt;
 &lt;h3&gt;基本原理&lt;/h3&gt;
 &lt;p&gt;原理流程图如下：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="yuanli" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3c158fd5402e4117b7350a80e9d61a32%7Etplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;从图中可以看出 go-zero 实现了 gRPC 的 resolver 和 balancer 接口，然后通过 gprc.Register 方法注册到 gRPC 中，resolver 模块提供了服务注册的功能，balancer 模块提供了负载均衡的功能。当 client 发起服务调用的时候会根据 resolver 注册进来的服务列表，使用注册进来的 balancer 选择一个服务发起请求，如果没有进行注册 gRPC 会使用默认的 resolver 和 balancer 。服务地址的变更会同步到 etcd 中，go-zero 监听 etcd 的变化通过 resolver 更新服务列表&lt;/p&gt;
 &lt;h3&gt;Resolver 模块&lt;/h3&gt;
 &lt;p&gt;通过 resolver.Register 方法可以注册自定义的 Resolver，Register 方法定义如下，其中 Builder 为 interface 类型，因此自定义 resolver 需要实现该接口，Builder 定义如下&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;// Register 注册自定义 resolver
func Register(b Builder) {
	m[b.Scheme()] = b
}

// Builder 定义 resolver builder
type Builder interface {
	Build(target Target, cc ClientConn, opts BuildOptions) (Resolver, error)
	Scheme() string
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;Build 方法的第一个参数 target 的类型为  &lt;a href="https://github.com/grpc/grpc/blob/master/doc/naming.md" rel="nofollow"&gt;Target&lt;/a&gt;定义如下，创建 ClientConn 调用 grpc.DialContext 的第二个参数 target 经过解析后需要符合这个结构定义，target 定义格式为：   &lt;em&gt;scheme://authority/endpoint_name&lt;/em&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;type Target struct {
	Scheme    string // 表示要使用的名称系统
	Authority string // 表示一些特定于方案的引导信息
	Endpoint  string // 指出一个具体的名字
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;Build 方法返回的 Resolver 也是一个接口类型。定义如下&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;type Resolver interface {
	ResolveNow(ResolveNowOptions)
	Close()
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;流程图下图&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="resolver" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/77bc1d5079c24668a2e70603a335489f%7Etplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;因此可以看出自定义 Resolver 需要实现如下步骤：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;定义 target&lt;/li&gt;
  &lt;li&gt;实现 resolver.Builder&lt;/li&gt;
  &lt;li&gt;实现 resolver.Resolver&lt;/li&gt;
  &lt;li&gt;调用 resolver.Register 注册自定义的 Resolver，其中 name 为 target 中的 scheme&lt;/li&gt;
  &lt;li&gt;实现服务发现逻辑(etcd 、consul 、zookeeper)&lt;/li&gt;
  &lt;li&gt;通过 resolver.ClientConn 实现服务地址的更新&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;go-zero 中 target 的定义如下，默认的名字为  &lt;em&gt;discov&lt;/em&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;// BuildDiscovTarget 构建 target
func BuildDiscovTarget(endpoints []string, key string) string {
	return fmt.Sprintf(&amp;quot;%s://%s/%s&amp;quot;, resolver.DiscovScheme,
		strings.Join(endpoints, resolver.EndpointSep), key)
}

// RegisterResolver 注册自定义的 Resolver
func RegisterResolver() {
	resolver.Register(&amp;amp;dirBuilder)
	resolver.Register(&amp;amp;disBuilder)
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;Build 方法的实现如下&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;func (d *discovBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (
	resolver.Resolver, error) {
	hosts := strings.FieldsFunc(target.Authority, func(r rune) bool {
		return r == EndpointSepChar
	})
  // 获取服务列表
	sub, err := discov.NewSubscriber(hosts, target.Endpoint)
	if err != nil {
		return nil, err
	}

	update := func() {
		var addrs []resolver.Address
		for _, val := range subset(sub.Values(), subsetSize) {
			addrs = append(addrs, resolver.Address{
				Addr: val,
			})
		}
    // 调用 UpdateState 方法更新
		cc.UpdateState(resolver.State{
			Addresses: addrs,
		})
	}
  
  // 添加监听，当服务地址发生变化会触发更新
	sub.AddListener(update)
  // 更新服务列表
	update()

	return &amp;amp;nopResolver{cc: cc}, nil
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;那么注册进来的 resolver 在哪里用到的呢？当创建客户端的时候调用 DialContext 方法创建 ClientConn 的时候回进行如下操作&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;拦截器处理&lt;/li&gt;
  &lt;li&gt;各种配置项处理&lt;/li&gt;
  &lt;li&gt;解析 target&lt;/li&gt;
  &lt;li&gt;获取 resolver&lt;/li&gt;
  &lt;li&gt;创建 ccResolverWrapper&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;创建 clientConn 的时候回根据 target 解析出 scheme，然后根据 scheme 去找已注册对应的 resolver，如果没有找到则使用默认的 resolver&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="dialcontext" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f52c325f1461476e8632f1b86307a878%7Etplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;ccResolverWrapper 的流程如下图，在这里 resolver 会和 balancer 会进行关联，balancer 的处理方式和 resolver 类似也是通过 wrapper 进行了一次封装&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="ccresolverwrapper" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fe9472f46b8c4f5ca4db45d3f7aff924%7Etplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;紧着着会根据获取到的地址创建 htt2 的链接&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="http2" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3f24461cc0a544dda9e4d2322dc72b03%7Etplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;到此 ClientConn 创建过程基本结束，我们再一起梳理一下整个过程，首先获取 resolver，其中 ccResolverWrapper 实现了 resovler.ClientConn 接口，通过 Resolver 的 UpdateState 方法触发获取 Balancer，获取 Balancer，其中 ccBalancerWrapper 实现了 balancer.ClientConn 接口，通过 Balnacer 的 UpdateClientConnState 方法触发创建连接(SubConn)，最后创建 HTTP2 Client&lt;/p&gt;
 &lt;h3&gt;Balancer 模块&lt;/h3&gt;
 &lt;p&gt;balancer 模块用来在客户端发起请求时进行负载均衡，如果没有注册自定义的 balancer 的话 gRPC 会采用默认的负载均衡算法，流程图如下&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="balancer" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/15787aacc6b443e5afa2e5d4abf9910a%7Etplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在 go-zero 中自定义的 balancer 主要实现了如下步骤：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;实现 PickerBuilder，Build 方法返回 balancer.Picker&lt;/li&gt;
  &lt;li&gt;实现 balancer.Picker，Pick 方法实现负载均衡算法逻辑&lt;/li&gt;
  &lt;li&gt;调用 balancer.Registet 注册自定义 Balancer&lt;/li&gt;
  &lt;li&gt;使用 baseBuilder 注册，框架已提供了 baseBuilder 和 baseBalancer 实现了 Builer 和 Balancer&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;Build 方法的实现如下&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;func (b *p2cPickerBuilder) Build(readySCs map[resolver.Address]balancer.SubConn) balancer.Picker {
	if len(readySCs) == 0 {
		return base.NewErrPicker(balancer.ErrNoSubConnAvailable)
	}

	var conns []*subConn
	for addr, conn := range readySCs {
		conns = append(conns, &amp;amp;subConn{
			addr:    addr,
			conn:    conn,
			success: initSuccess,
		})
	}

	return &amp;amp;p2cPicker{
		conns: conns,
		r:     rand.New(rand.NewSource(time.Now().UnixNano())),
		stamp: syncx.NewAtomicDuration(),
	}
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;go-zero 中默认实现了 p2c 负载均衡算法，该算法的优势是能弹性的处理各个节点的请求，Pick 的实现如下&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;func (p *p2cPicker) Pick(ctx context.Context, info balancer.PickInfo) (
	conn balancer.SubConn, done func(balancer.DoneInfo), err error) {
	p.lock.Lock()
	defer p.lock.Unlock()

	var chosen *subConn
	switch len(p.conns) {
	case 0:
		return nil, nil, balancer.ErrNoSubConnAvailable // 没有可用链接
	case 1:
		chosen = p.choose(p.conns[0], nil) // 只有一个链接
	case 2:
		chosen = p.choose(p.conns[0], p.conns[1])
	default: // 选择一个健康的节点
		var node1, node2 *subConn
		for i := 0; i &amp;lt; pickTimes; i++ {
			a := p.r.Intn(len(p.conns))
			b := p.r.Intn(len(p.conns) - 1)
			if b &amp;gt;= a {
				b++
			}
			node1 = p.conns[a]
			node2 = p.conns[b]
			if node1.healthy() &amp;amp;&amp;amp; node2.healthy() {
				break
			}
		}

		chosen = p.choose(node1, node2)
	}

	atomic.AddInt64(&amp;amp;chosen.inflight, 1)
	atomic.AddInt64(&amp;amp;chosen.requests, 1)
	return chosen.conn, p.buildDoneFunc(chosen), nil
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;客户端发起调用的流程如下，会调用 pick 方法获取一个 transport 进行处理&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="client_call" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0061523f1a904b83999733d825e749be%7Etplv-k3u1fbpfcp-watermark.image"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;总结&lt;/h3&gt;
 &lt;p&gt;本文主要分析了 gRPC 的 resolver 模块和 balancer 模块，详细介绍了如何自定义 resolver 和 balancer，以及通过分析 go-zero 中对 resolver 和 balancer 的实现了解了自定义 resolver 和 balancer 的过程，同时还分析可客户端创建的流程和调用的流程。希望本文能给大家带来一些帮助&lt;/p&gt;
 &lt;h3&gt;项目地址&lt;/h3&gt;
 &lt;p&gt;  &lt;a href="https://github.com/tal-tech/go-zero" rel="nofollow"&gt;https://github.com/tal-tech/go-zero&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;如果觉得文章不错，欢迎   &lt;strong&gt;   &lt;a href="https://github.com/tal-tech/go-zero" rel="nofollow"&gt;github&lt;/a&gt;&lt;/strong&gt; 点个   &lt;strong&gt;star&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 />
      <guid isPermaLink="true">https://itindex.net/detail/61062-grpc-%E5%8F%91%E7%8E%B0-%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1</guid>
      <pubDate>Mon, 07 Dec 2020 22:52:52 CST</pubDate>
    </item>
    <item>
      <title>科研人员发现隐私泄露无孔不入，扫地机器人已成新型“窃听器”？</title>
      <link>https://itindex.net/detail/61038-%E7%A7%91%E7%A0%94-%E5%8F%91%E7%8E%B0-%E9%9A%90%E7%A7%81</link>
      <description>&lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#26469;&amp;#28304;@&amp;#35270;&amp;#35273;&amp;#20013;&amp;#22269;" src="https://images.tmtpost.com/uploads/images/2020/11/e0c84ae9c7c7592af80e91ae2891d8c0_1606561303.jpeg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;图片来源@视觉中国&lt;/p&gt; &lt;blockquote&gt;  &lt;p&gt;文丨学术头条&lt;/p&gt;&lt;/blockquote&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;近日，由新加坡国立大学（NUS）、美国马里兰大学学院市分校（UMD）研究人员组成的科研团队，成功远程入侵了一台家用扫地机器人，使其充当窃听器来“窃听”屋内的私人信息。这项研究表明，即使没有安装传统的“窃听器”，不法分子也可以操纵家居设备来窃取他人信息。&lt;/p&gt; &lt;p&gt;相关论文也以“Spying with Your Robot Vacuum Cleaner: Eavesdropping via Lidar Sensors”为题在线发表。&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;p&gt;而在这项研究中，论文作者之一、马里兰大学计算机科学系助理教授 Nirupam Roy 及其合作者则提出了另一种猜想：&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;扫地机器人中的激光雷达系统，是否有可能成为不法分子在个人家中或企业中的窃听设备，并带来潜在的安全风险呢？&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;于是，他们创造了一种名为“LidarPhone”的监听系统，并通过攻击一款小米 Roborock 扫地机器人进行了测试。  &lt;strong&gt;此次攻击的核心思想是：“黑”进扫地机器人后远程访问云平台，获取激光雷达数据并分析收集到的原始信号。研究人员表示，这将使攻击者可以窃听私人对话，从而泄露信用卡信息或可能用于威胁勒索的信息。&lt;/strong&gt;&lt;/p&gt; &lt;div&gt;  &lt;p&gt;   &lt;img height="810" src="https://images.tmtpost.com/uploads/images/2020/11/9396fc175d6fda6fa4bc0f496e57a4ee_1606561304.jpeg" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;图 | 通过扫地机器人捕捉家中物品（比如垃圾桶）反射的声音信号进行窃听（来源：Sriram Sami）&lt;/p&gt;&lt;/div&gt; &lt;p&gt;那么，问题来了，吸尘器中并没有声音传感器，LidarPhone 是如何“听”到声音的？&lt;/p&gt; &lt;p&gt;我们知道，声波会导致物体振动，而这些振动又会导致从物体反射回来的激光束发生变化。  &lt;strong&gt;因此，攻击者就有可能由吸尘器接收到的激光信号及其变化，分析出导致这种变化的声波信号，进行成功窃听。&lt;/strong&gt;&lt;/p&gt; &lt;div&gt;  &lt;p&gt;   &lt;img height="810" src="https://images.tmtpost.com/uploads/images/2020/11/c9397097557f0ffd69630bfc78f7cb56_1606561304.jpeg" width="1080"&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img alt="" src="http://images.tmtpost.com/uploads/images/2016/12/2rt43q5whyt3.jpg"&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;图 | 深度学习算法可以解释由扫地机器人捕捉到的分散声波，进而识别数字和音乐序列（来源：Sriram Sami）&lt;/p&gt;&lt;/div&gt; &lt;p&gt;自 20 世纪 40 年代以来就一直用于间谍活动的激光麦克风就是一个典型的例子。但是，激光麦克风依赖于在非常光滑的表面（例如玻璃窗）上反射的目标激光束，也就是说，一旦激光束接触到的物体表面不够光滑，最终就难以转换成声波。&lt;/p&gt; &lt;p&gt;在此次实验中，研究人员在小米 Roborock 扫地机器人上使用 LidarPhone 系统进行了概念验证（PoC）。首先，他们对扫地机器人的基于 ARM Cortex-M 的固件进行了反向工程；然后，利用 Dustcloud 软件堆栈（该设备是吸尘器的代理服务器或终结点服务器）中的问题，获得了对系统的 root 访问权限。&lt;/p&gt; &lt;p&gt;研究人员表示：“这类扫地机器人通常与小米云平台连接，以实现其标准操作和数据交换。我们使用设备上的 Valetudo 软件堆栈覆盖此接口，并通过本地网络控制机器人。”&lt;/p&gt; &lt;p&gt;然后，研究人员收集了两个语音序列——计算机扬声器和电视音箱播放的音乐，在记录的 19 个小时内总计发出了 30000 多个语音序列。  &lt;strong&gt;实验结果显示，LidarPhone 的数字和声音分类的平均准确度分别达到了约 91％ 和 90%。&lt;/strong&gt;   &lt;br /&gt;  &lt;img alt="&amp;#22270; | LidarPhone &amp;#23545;&amp;#25968;&amp;#23383;&amp;#22768;&amp;#28304;&amp;#12289;&amp;#24615;&amp;#21035;&amp;#12289;&amp;#35828;&amp;#35805;&amp;#20154;&amp;#30340;&amp;#36776;&amp;#21035;&amp;#20934;&amp;#30830;&amp;#24230;" src="https://images.tmtpost.com/uploads/images/2020/11/54891931cbcffe916c578f8beb43b52d_1606561304.jpeg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;图 | LidarPhone 对数字声源、性别、说话人的辨别准确度&lt;/p&gt; &lt;p&gt;利用 LidarPhone，研究人员可以监测到家庭中出现的不同声音——从地毯到垃圾桶，再到电视上流行的新闻频道（如 FOX、CNN 和 PBS）的各种介绍性音乐背景，甚至可以预测说话者的性别。  &lt;strong&gt; &lt;/strong&gt;&lt;/p&gt; &lt;h2&gt;仍需多加提防&lt;/h2&gt; &lt;p&gt;尽管如此，LidarPhone 也并非完美，其在攻击过程中也遇到了各种各样的问题。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;比如，与扫地机器人之间的距离和各种噪音的音量，都会影响整体效果，背景噪声水平和光照条件也会影响整体攻击效果。&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;研究人员表示，可以通过降低激光雷达信号的信噪比（SNR）来“阻止”攻击或降低攻击风险：以低于特定旋转速率的速度传输，没有选择在软件中覆盖此功能。&lt;/p&gt; &lt;p&gt;此外，手机也可能会成为攻击者的作案工具。“虽然我们以吸尘器为例研究激光雷达系统，但我们的发现可能会扩展到许多其他有源光传感器，包括智能手机的飞行时间（ToF）传感器。” ToF 相机使用红外线感应物体并将反射光线返至相机，光线离开并返回设备所需的时间（即飞行时间）使相机能够感应到深度，从而创建出整个空间的 3D 地图。&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;https://www.cs.umd.edu/~nirupam/images/2_publication/papers/LidarPhone_SenSys20_nirupam.pdf&lt;/p&gt; &lt;p&gt;https://techxplore.com/news/2020-11-hacked-robotic-vacuum-cleaner-speech.html&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;更多精彩内容，关注钛媒体微信号（ID：taimeiti），或者下载钛媒体App&lt;/strong&gt;&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>智能家居 隐私 网络安全 投稿</category>
      <guid isPermaLink="true">https://itindex.net/detail/61038-%E7%A7%91%E7%A0%94-%E5%8F%91%E7%8E%B0-%E9%9A%90%E7%A7%81</guid>
      <pubDate>Sat, 28 Nov 2020 19:20:00 CST</pubDate>
    </item>
    <item>
      <title>浅谈 Kubernetes 中的服务发现 | 伪架构师</title>
      <link>https://itindex.net/detail/60996-kubernetes-%E6%9C%8D%E5%8A%A1-%E5%8F%91%E7%8E%B0</link>
      <description>&lt;div&gt;    &lt;p&gt;原文：      &lt;a href="https://nigelpoulton.com/blog/f/demystifying-kubernetes-service-discovery" target="_blank"&gt;Demystifying Kubernetes service discovery&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;作者：      &lt;a href="https://twitter.com/nigel_poulton" target="_blank"&gt;Nigel Poulton&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;Kubernetes 服务发现是一个经常让我产生困惑的主题之一。本文分为两个部分：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;网络方面的背景知识&lt;/li&gt;      &lt;li&gt;深入了解 Kubernetes 服务发现&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;要了解服务发现，首先要了解背后的网络知识。这部分内容相对浅显，如果读者熟知这一部分，完全可以跳过，直接阅读服务发现部分。&lt;/p&gt;    &lt;p&gt;开始之前还有一个需要提醒的事情就是，为了详细描述这一过程，本文略长。&lt;/p&gt;    &lt;h2&gt;Kubernetes 网络基础&lt;/h2&gt;    &lt;p&gt;要开始服务发现的探索之前，需要理解以下内容：&lt;/p&gt;    &lt;ol&gt;      &lt;li&gt;Kubernetes 应用运行在容器之中，容器处于 Pod 之内。&lt;/li&gt;      &lt;li&gt;每个 Pod 都会附着在同一个大的扁平的 IP 网络之中，被称为 Pod 网络（通常是 VXLAN 叠加网络）。&lt;/li&gt;      &lt;li&gt;每个 Pod 都有自己的唯一的 IP 地址，这个 IP 地址在 Pod 网络中是可路由的。&lt;/li&gt;&lt;/ol&gt;    &lt;p&gt;      &lt;img alt="Pod Network" src="https://blog.fleeto.us/post/demystifying-kubernetes-service-discovery/images/pod-network2.png"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;上述三个因素结合起来，让每个应用（应用的组件和服务）无需通过 NAT 之类的网络过程，就能够直接通信。&lt;/p&gt;    &lt;h3&gt;动态网络&lt;/h3&gt;    &lt;p&gt;在对应用进行横向扩容时，会在 Pod 网络中加入新的 Pod，新 Pod 自然也伴随着新的 IP 地址；如果对应用进行缩容，旧的 Pod 及其 IP 会被删除。这个过程看起来很是混乱。&lt;/p&gt;    &lt;p&gt;应用的滚动更新和撤回也存在同样的情形——加入新版本的新 Pod，或者移除旧版本的旧 Pod。新 Pod 会加入新 IP 到 Pod 网络中，被终结的旧 Pod 会删除其现存 IP。&lt;/p&gt;    &lt;p&gt;如果没有其它因素，每个应用服务都需要对网络进行监控，并管理一个健康 Pod 的列表。这个过程会非常痛苦，另外在每个应用中编写这个逻辑也是很低效的。幸运的是，Kubernetes 用一个对象完成了这个过程——Service。&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;把这个对象叫做 Service 是个坏主意，我们已经用这个单词来形容应用的进程或组件了。&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;还有一个值得注意的事情：Kubernetes 执行 IP 地址管理（IPAM）职责，对 Pod 网络上已使用和可用的 IP 地址进行跟踪。&lt;/p&gt;    &lt;h3&gt;Service 带来稳定性&lt;/h3&gt;    &lt;p&gt;Kubernetes Service 对象在一组提供服务的 Pod 之前创建一个稳定的网络端点，并为这些 Pod 进行负载分配。&lt;/p&gt;    &lt;p&gt;一般会在一组完成同样工作的 Pod 之前放置一个 Service 对象。例如可以在你的 Web 前端 Pod 前方提供一个 Service，在认证服务 Pod 之前提供另一个。行使不同职责的 Pod 之前就不应该用单一的 Service 了。&lt;/p&gt;    &lt;p&gt;客户端和 Service 通信，Service 负责把流量负载均衡给 Pod。&lt;/p&gt;    &lt;p&gt;      &lt;img alt="Service 101" src="https://blog.fleeto.us/post/demystifying-kubernetes-service-discovery/images/service-101.png"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;在上图中，底部的 Pod 会因为伸缩、更新、故障等情况发生变化，而 Service 会对这些变化进行跟踪。同时 Service 的名字、IP 和端口都不会发生变化。&lt;/p&gt;    &lt;h3&gt;Kubernetes Service 解析&lt;/h3&gt;    &lt;p&gt;可以把 Kubernetes Service 理解为前端和后端两部分：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;前端：名称、IP 和端口等不变的部分。&lt;/li&gt;      &lt;li&gt;后端：符合特定标签选择条件的 Pod 集合。&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;前端是稳定可靠的，它的名称、IP 和端口在 Service 的整个生命周期中都不会改变。前端的稳定性意味着无需担心客户端 DNS 缓存超时等问题。&lt;/p&gt;    &lt;p&gt;后端是高度动态的，其中包括一组符合标签选择条件的 Pod，会通过负载均衡的方式进行访问。&lt;/p&gt;    &lt;p&gt;      &lt;img alt="Service Anatomy" src="https://blog.fleeto.us/post/demystifying-kubernetes-service-discovery/images/service-anatomy3.png"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;这里的负载均衡是一个简单的 4 层轮询。它工作在连接层面，所以同一个连接里发起的所有请求都会进入同一个 Pod。因为在 4 层工作，所以对于 7 层的 HTTP 头或者 Cookie 之类的东西是无法感知的。&lt;/p&gt;    &lt;h3&gt;小结&lt;/h3&gt;    &lt;p&gt;应用在容器中运行，在 Kubernetes 中体现为 Pod 的形式。Kubernetes 集群中的所有 Pod 都处于同一个平面的 Pod 网络，有自己的 IP 地址。这意味着所有的 Pod 之间都能直接连接。然而 Pod 是不稳定的，可能因为各种因素创建和销毁。Kubernetes 提供了稳定的网络端点，称为 Service，这个对象处于一组相似的 Pod 前方，提供了稳定的名称、IP 和端口。客户端连接到 Service，Service 把流量负载均衡给 Pod。&lt;/p&gt;    &lt;p&gt;接下来聊聊服务发现。&lt;/p&gt;    &lt;h2&gt;深入了解 Kubernetes 服务发现&lt;/h2&gt;    &lt;p&gt;服务发现实际上包含两个功能点：&lt;/p&gt;    &lt;ol&gt;      &lt;li&gt;服务注册&lt;/li&gt;      &lt;li&gt;服务发现&lt;/li&gt;&lt;/ol&gt;    &lt;h3&gt;服务注册&lt;/h3&gt;    &lt;p&gt;服务注册过程指的是在服务注册表中登记一个服务，以便让其它服务发现。&lt;/p&gt;    &lt;p&gt;      &lt;img alt="service-registration.png" src="https://blog.fleeto.us/post/demystifying-kubernetes-service-discovery/images/service-registration.png"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;Kubernetes 使用 DNS 作为服务注册表。&lt;/p&gt;    &lt;p&gt;为了满足这一需要，每个 Kubernetes 集群都会在      &lt;code&gt;kube-system&lt;/code&gt;命名空间中用 Pod 的形式运行一个 DNS 服务，通常称之为集群 DNS。&lt;/p&gt;    &lt;p&gt;每个 Kubernetes 服务都会自动注册到集群 DNS 之中。&lt;/p&gt;    &lt;p&gt;注册过程大致如下：&lt;/p&gt;    &lt;ol&gt;      &lt;li&gt;向 API Server 用 POST 方式提交一个新的 Service 定义；&lt;/li&gt;      &lt;li&gt;这个请求需要经过认证、鉴权以及其它的准入策略检查过程之后才会放行；&lt;/li&gt;      &lt;li&gt;Service 得到一个        &lt;code&gt;ClusterIP&lt;/code&gt;（虚拟 IP 地址），并保存到集群数据仓库；&lt;/li&gt;      &lt;li&gt;在集群范围内传播 Service 配置；&lt;/li&gt;      &lt;li&gt;集群 DNS 服务得知该 Service 的创建，据此创建必要的 DNS A 记录。&lt;/li&gt;&lt;/ol&gt;    &lt;p&gt;上面过程中，第 5 个步骤是关键环节。集群 DNS 使用的是 CoreDNS，以 Kubernetes 原生应用的形式运行。CoreDNS 实现了一个控制器，会对 API Server 进行监听，一旦发现有新建的 Service 对象，就创建一个从 Service 名称映射到 ClusterIP 的域名记录。这样 Service 就不必自行向 DNS 进行注册，CoreDNS 控制器会关注新创建的 Service 对象，并实现后续的 DNS 过程。&lt;/p&gt;    &lt;p&gt;DNS 中注册的名称就是      &lt;code&gt;metadata.name&lt;/code&gt;，而 ClusterIP 则由 Kubernetes 自行分配。&lt;/p&gt;    &lt;p&gt;      &lt;img alt="svc-yaml2" src="https://blog.fleeto.us/post/demystifying-kubernetes-service-discovery/images/svc-yaml2.png"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;Service 对象注册到集群 DNS 之中后，就能够被运行在集群中的其它 Pod 发现了。&lt;/p&gt;    &lt;h4&gt;Endpoint 对象&lt;/h4&gt;    &lt;p&gt;Service 的前端创建成功并注册到服务注册表（DNS）之后，剩下的就是后端的工作了。后端包含一个 Pod 列表，Service 对象会把流量分发给这些 Pod。&lt;/p&gt;    &lt;p&gt;毫无疑问，这个 Pod 列表需要是最新的。&lt;/p&gt;    &lt;p&gt;Service 对象有一个 Label Selector 字段，这个字段是一个标签列表，符合列表条件的 Pod 就会被服务纳入到服务的负载均衡范围之中。参见下图：&lt;/p&gt;    &lt;p&gt;      &lt;img alt="backend2" src="https://blog.fleeto.us/post/demystifying-kubernetes-service-discovery/images/backend2.png"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;Kubernetes 自动为每个 Service 创建 Endpoints 对象。Endpoints 对象的职责就是保存一个符合 Service 标签选择器标准的 Pod 列表，这些 Pod 将接收来自 Service 的流量。&lt;/p&gt;    &lt;p&gt;下面的图中，Service 会选择两个 Pod，并且还展示了 Service 的 Endpoints 对象，这个对象里包含了两个符合 Service 选择标准的 Pod 的 IP。&lt;/p&gt;    &lt;p&gt;在后面我们将解释网络如何把 ClusterIP 流量转发给 Pod IP 的过程，还会引用到 Endpoints 对象。&lt;/p&gt;    &lt;h3&gt;服务发现&lt;/h3&gt;    &lt;p&gt;假设我们在一个 Kubernetes 集群中有两个应用，      &lt;code&gt;my-app&lt;/code&gt;和      &lt;code&gt;your-app&lt;/code&gt;，      &lt;code&gt;my-app&lt;/code&gt;的 Pod 的前端是一个 名为      &lt;code&gt;my-app-svc&lt;/code&gt;的 Service 对象；      &lt;code&gt;your-app&lt;/code&gt;Pod 之前的 Service 就是      &lt;code&gt;your-app-svc&lt;/code&gt;。&lt;/p&gt;    &lt;p&gt;这两个 Service 对象对应的 DNS 记录是：&lt;/p&gt;    &lt;ul&gt;      &lt;li&gt;        &lt;code&gt;my-app-svc&lt;/code&gt;：10.0.0.10&lt;/li&gt;      &lt;li&gt;        &lt;code&gt;your-app-svc&lt;/code&gt;：10.0.0.20&lt;/li&gt;&lt;/ul&gt;    &lt;p&gt;      &lt;img alt="dns-reg" src="https://blog.fleeto.us/post/demystifying-kubernetes-service-discovery/images/dns-reg.png"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;要使用服务发现功能，每个 Pod 都需要知道集群 DNS 的位置才能使用它。因此每个 Pod 中的每个容器的      &lt;code&gt;/etc/resolv.conf&lt;/code&gt;文件都被配置为使用集群 DNS 进行解析。&lt;/p&gt;    &lt;p&gt;如果      &lt;code&gt;my-app&lt;/code&gt;中的 Pod 想要连接到      &lt;code&gt;your-app&lt;/code&gt;中的 Pod，就得向 DNS 服务器发起对域名      &lt;code&gt;your-app-svc&lt;/code&gt;的查询。假设它们本地的 DNS 解析缓存中没有这个记录，则需要把查询提交到集群 DNS 服务器。会得到      &lt;code&gt;you-app-svc&lt;/code&gt;的 ClusterIP（VIP）。&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;这里有个前提就是        &lt;code&gt;my-app&lt;/code&gt;需要知道目标服务的名称。&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;至此，      &lt;code&gt;my-app&lt;/code&gt;中的 Pod 得到了一个目标 IP 地址，然而这只是个虚拟 IP，在转入目标 Pod 之前，还有些网络工作要做。&lt;/p&gt;    &lt;h4&gt;网络&lt;/h4&gt;    &lt;p&gt;一个 Pod 得到了 Service 的 ClusterIP 之后，就尝试向这个 IP 发送流量。然而 ClusterIP 所在的网络被称为      &lt;code&gt;Service Network&lt;/code&gt;，这个网络有点特别——没有路由指向它。&lt;/p&gt;    &lt;p&gt;因为没有路由，所有容器把发现这种地址的流量都发送到了缺省网关（名为      &lt;code&gt;CBR0&lt;/code&gt;的网桥）。这些流量会被转发给 Pod 所在节点的网卡上。节点的网络栈也同样没有路由能到达 Service Network，所以只能发送到自己的缺省网关。路由到节点缺省网关的数据包会通过 Node 内核——这里有了变化。&lt;/p&gt;    &lt;p&gt;回顾一下前面的内容。首先 Service 对象的配置是全集群范围有效的，另外还会再次说到 Endpoints 对象。我们要在回顾中发现他们各自在这一过程中的职责。&lt;/p&gt;    &lt;p&gt;每个 Kubernetes 节点上都会运行一个叫做      &lt;code&gt;kube-proxy&lt;/code&gt;的系统服务。这是一个基于 Pod 运行的 Kubernetes 原生应用，它所实现的控制器会监控 API Server 上 Service 的变化，并据此创建      &lt;code&gt;iptables&lt;/code&gt;或者      &lt;code&gt;IPVS&lt;/code&gt;规则，这些规则告知节点，捕获目标为 Service 网络的报文，并转发给 Pod IP。&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;有趣的是，kube-proxy 并不是一个普遍意义上的代理。它的工作不过是创建和管理 iptables/IPVS 规则。这个命名的原因是它过去使用 unserspace 模式的代理。&lt;/p&gt;&lt;/blockquote&gt;    &lt;p&gt;每个新 Service 对象的配置，其中包含它的 ClusterIP 以及 Endpoints 对象（其中包含健康 Pod 的列表），都会被发送给 每个节点上的 kube-proxy 进程。kube-proxy 会创建 iptables 或者 IPVS 规则，告知节点捕获目标为 Service ClusterIP 的流量，并根据 Endpoints 对象的内容转发给对应的 Pod。&lt;/p&gt;    &lt;p&gt;也就是说每次节点内核处理到目标为 Service 网络的数据包时，都会对数据包的 Header 进行改写，把目标 IP 改为 Service Endpoints 对象中的健康 Pod 的 IP。&lt;/p&gt;    &lt;blockquote&gt;      &lt;p&gt;原本使用的 iptables 正在被 IPVS 取代（Kubernetes 1.11 进入稳定期）。长话短说，iptables 是一个包过滤器，并非为负载均衡设计的。IPVS 是一个 4 层的负载均衡器，其性能和实现方式都比 iptables 更适合这种使用场景。&lt;/p&gt;&lt;/blockquote&gt;    &lt;h2&gt;总结&lt;/h2&gt;    &lt;p&gt;需要消化的内容很多，简单回顾一下。&lt;/p&gt;    &lt;p&gt;创建新的 Service 对象时，会得到一个虚拟 IP，被称为 ClusterIP。服务名及其 ClusterIP 被自动注册到集群 DNS 中，并且会创建相关的 Endpoints 对象用于保存符合标签条件的健康 Pod 的列表，Service 对象会向列表中的 Pod 转发流量。&lt;/p&gt;    &lt;p&gt;与此同时集群中所有节点都会配置相应的 iptables/IPVS 规则，监听目标为 ClusterIP 的流量并转发给真实的 Pod IP。这个过程如下图所示：&lt;/p&gt;    &lt;p&gt;      &lt;img alt="service register" src="https://blog.fleeto.us/post/demystifying-kubernetes-service-discovery/images/registeration-flow.png"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;一个 Pod 需要用 Service 连接其它 Pod。首先向集群 DNS 发出查询，把 Service 名称解析为 ClusterIP，然后把流量发送给位于 Service 网络的 ClusterIP 上。然而没有到 Service 网络的路由，所以 Pod 把流量发送给它的缺省网关。这一行为导致流量被转发给 Pod 所在节点的网卡，然后是节点的缺省网关。这个操作中，节点的内核修改了数据包 Header 中的目标 IP，使其转向健康的 Pod。&lt;/p&gt;    &lt;p&gt;      &lt;img alt="discovery" src="https://blog.fleeto.us/post/demystifying-kubernetes-service-discovery/images/discovery-flow.png"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;最终所有 Pod 都是在同一个可路由的扁平的叠加网络上，剩下的内容就很简单了。&lt;/p&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 />
      <guid isPermaLink="true">https://itindex.net/detail/60996-kubernetes-%E6%9C%8D%E5%8A%A1-%E5%8F%91%E7%8E%B0</guid>
      <pubDate>Mon, 09 Nov 2020 18:56:19 CST</pubDate>
    </item>
    <item>
      <title>spring-cloud-kubernetes的服务发现和轮询实战(含熔断)_程序员欣宸的博客-CSDN博客</title>
      <link>https://itindex.net/detail/60981-spring-cloud-kubernetes</link>
      <description>&lt;div&gt;    &lt;p&gt;本文是《spring-cloud-kubernetes实战系列》的第四篇，主要内容是在kubernetes上部署两个应用：Web-Service和Account-Service，通过spring-cloud-kubernetes提供的注册发现能力，实现Web-Service调用Account-Service提供的http服务；&lt;/p&gt;    &lt;h3&gt;      &lt;a&gt;&lt;/a&gt;系列文章列表&lt;/h3&gt;    &lt;ol&gt;      &lt;li&gt;        &lt;a href="https://blog.csdn.net/boling_cavalry/article/details/91346780"&gt;《spring-cloud-kubernetes官方demo运行实战》&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://blog.csdn.net/boling_cavalry/article/details/91351411"&gt;《你好spring-cloud-kubernetes》&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://blog.csdn.net/boling_cavalry/article/details/92069486"&gt;《spring-cloud-kubernetes背后的三个关键知识点》&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://xinchen.blog.csdn.net/article/details/92394559"&gt;《spring-cloud-kubernetes的服务发现和轮询实战(含熔断)》&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://xinchen.blog.csdn.net/article/details/95001691"&gt;《spring-cloud-kubernetes与SpringCloud Gateway》&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;        &lt;a href="https://xinchen.blog.csdn.net/article/details/95804909"&gt;《spring-cloud-kubernetes与k8s的configmap》&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;    &lt;h3&gt;      &lt;a&gt;&lt;/a&gt;全文概览&lt;/h3&gt;    &lt;p&gt;本文由以下段落组成：&lt;/p&gt;    &lt;ol&gt;      &lt;li&gt;环境信息&lt;/li&gt;      &lt;li&gt;常见的SpringCloud注册发现服务一览&lt;/li&gt;      &lt;li&gt;分析kubernetes上如何实现服务注册发现&lt;/li&gt;      &lt;li&gt;本章实战源码下载链接&lt;/li&gt;      &lt;li&gt;实战开发Account-Service服务(服务提供方)&lt;/li&gt;      &lt;li&gt;实战开发Web-Service服务(服务消费方)&lt;/li&gt;      &lt;li&gt;扩容验证ribbon轮询能力&lt;/li&gt;      &lt;li&gt;验证熔断能力&lt;/li&gt;&lt;/ol&gt;    &lt;h3&gt;      &lt;a&gt;&lt;/a&gt;环境信息&lt;/h3&gt;    &lt;p&gt;本次实战的环境和版本信息如下：&lt;/p&gt;    &lt;ol&gt;      &lt;li&gt;操作系统：CentOS Linux release 7.6.1810&lt;/li&gt;      &lt;li&gt;minikube：1.1.1&lt;/li&gt;      &lt;li&gt;Java：1.8.0_191&lt;/li&gt;      &lt;li&gt;Maven：3.6.0&lt;/li&gt;      &lt;li&gt;fabric8-maven-plugin插件：3.5.37&lt;/li&gt;      &lt;li&gt;spring-cloud-kubernetes：1.0.1.RELEASE&lt;/li&gt;&lt;/ol&gt;    &lt;p&gt;上面的linux、minikube、java、maven，请确保已准备好，linux环境下minikube的安装和启动请参考      &lt;a href="https://blog.csdn.net/boling_cavalry/article/details/91304127"&gt;《Linux安装minikube指南 》&lt;/a&gt;。&lt;/p&gt;    &lt;h3&gt;      &lt;a&gt;&lt;/a&gt;常见的SpringCloud注册发现服务一览&lt;/h3&gt;    &lt;p&gt;SpringCloud环境最重要的功能是注册发现服务，因此将SpringCloud应用迁移到kubernetes环境时，开发者最关心的问题是在kubernetes上如何将自身服务暴露出去，以及如何调用其他微服务。&lt;/p&gt;    &lt;p&gt;先看看普通SpringCloud环境下的注册发现，下图来自spring官方博客，地址是：      &lt;a href="https://spring.io/blog/2015/07/14/microservices-with-spring%EF%BC%8C"&gt;https://spring.io/blog/2015/07/14/microservices-with-spring，&lt;/a&gt;      &lt;br /&gt;      &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://img-blog.csdnimg.cn/20190616142339871.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly94aW5jaGVuLmJsb2cuY3Nkbi5uZXQ=,size_16,color_FFFFFF,t_70"&gt;&lt;/img&gt;&lt;/p&gt;    &lt;p&gt;由上图可见，应用Account-Service将自己注册到Eureka，这样Web-Service用&amp;quot;account-service&amp;quot;就能在Eureka找到Account-Service服务的地址，然后顺利发送RestFul请求到Account-Service，用上其提供的服务。&lt;/p&gt;    &lt;h3&gt;      &lt;a&gt;&lt;/a&gt;分析kubernetes上如何实现服务注册发现&lt;/h3&gt;    &lt;p&gt;如果将上面的Web-Service和Account-Service两个应用迁移到kubernetes上之后，注册发现机制变成了啥样呢？      &lt;br /&gt;第一种：沿用上图的方式，将Eureka也部署在kubernetes上，这样的架构和不用kubernetes时没有啥区别；      &lt;br /&gt;第二种，就是今天要实战的内容，使用spring-cloud-kubernetes框架，该框架可以调用kubernetes的原生能力来为现有SpringCloud应用提供服务，架构如下图所示：      &lt;br /&gt;      &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://img-blog.csdnimg.cn/20190616165108300.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly94aW5jaGVuLmJsb2cuY3Nkbi5uZXQ=,size_16,color_FFFFFF,t_70"&gt;&lt;/img&gt;      &lt;br /&gt;上图表明，Web-Service应用在调用Account-Service应用的服务时，会用okhttp向API Server请求服务列表，API Server收到请求后会去etcd取数据返回给Web-Service应用，这样Web-Service就有了Account-Service的信息，可以向Account-Service的多个Pod轮询发起请求；&lt;/p&gt;    &lt;p&gt;上图有个细节请注意：WebService应用并不是直接将请求发送给Account-Service在kubernetes创建的service，而是直接发送到具体的Pod上了，之所以具有这个能力，是因为spring-cloud-kubernetes框架通过service拿到了Account-Service对应的所有Pod信息（endpoint），此逻辑可以参考源码KubernetesServerList.java，如下所示：&lt;/p&gt;    &lt;pre&gt;      &lt;code&gt;publicList&amp;lt;Server&amp;gt;getUpdatedListOfServers(){//用namespace和serviceId做条件，得到该服务对应的所有节点(endpoints)信息Endpoints endpoints=this.namespace!=null?this.client.endpoints().inNamespace(this.namespace).withName(this.serviceId).get():this.client.endpoints().withName(this.serviceId).get();List&amp;lt;Server&amp;gt;result=newArrayList&amp;lt;Server&amp;gt;();if(endpoints!=null){if(LOG.isDebugEnabled()){LOG.debug(&amp;quot;Found [&amp;quot;+endpoints.getSubsets().size()+&amp;quot;] endpoints in namespace [&amp;quot;+this.namespace+&amp;quot;] for name [&amp;quot;+this.serviceId+&amp;quot;] and portName [&amp;quot;+this.portName+&amp;quot;]&amp;quot;);}//遍历所有的endpoint，取出IP地址和端口，构建成Server实例，放入result集合中for(EndpointSubset subset:endpoints.getSubsets()){if(subset.getPorts().size()==1){EndpointPort port=subset.getPorts().get(FIRST);for(EndpointAddress address:subset.getAddresses()){result.add(newServer(address.getIp(),port.getPort()));}}else{for(EndpointPort port:subset.getPorts()){if(Utils.isNullOrEmpty(this.portName)||this.portName.endsWith(port.getName())){for(EndpointAddress address:subset.getAddresses()){result.add(newServer(address.getIp(),port.getPort()));}}}}}}else{LOG.warn(&amp;quot;Did not find any endpoints in ribbon in namespace [&amp;quot;+this.namespace+&amp;quot;] for name [&amp;quot;+this.serviceId+&amp;quot;] and portName [&amp;quot;+this.portName+&amp;quot;]&amp;quot;);}returnresult;}&lt;/code&gt;&lt;/pre&gt;    &lt;p&gt;理论分析已经完成，接下来就开始实战吧&lt;/p&gt;    &lt;h3&gt;      &lt;a&gt;&lt;/a&gt;源码下载&lt;/h3&gt;    &lt;p&gt;如果您不打算写代码，也可以从GitHub上下载本次实战的源码，地址和链接信息如下表所示：&lt;/p&gt;    &lt;table&gt;      &lt;tr&gt;        &lt;th align="left"&gt;名称&lt;/th&gt;        &lt;th align="left"&gt;链接&lt;/th&gt;        &lt;th align="left"&gt;备注&lt;/th&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td align="left"&gt;项目主页&lt;/td&gt;        &lt;td align="left"&gt;          &lt;a href="https://github.com/zq2599/blog_demos"&gt;https://github.com/zq2599/blog_demos&lt;/a&gt;&lt;/td&gt;        &lt;td align="left"&gt;该项目在GitHub上的主页&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td align="left"&gt;git仓库地址(https)&lt;/td&gt;        &lt;td align="left"&gt;          &lt;a href="https://github.com/zq2599/blog_demos.git"&gt;https://github.com/zq2599/blog_demos.git&lt;/a&gt;&lt;/td&gt;        &lt;td align="left"&gt;该项目源码的仓库地址，https协议&lt;/td&gt;&lt;/tr&gt;      &lt;tr&gt;        &lt;td align="left"&gt;git仓库地址(ssh)&lt;/td&gt;        &lt;td align="left"&gt;git@github.com:zq2599/blog_demos.git&lt;/td&gt;        &lt;td align="left"&gt;该项目源码的仓库地址，ssh协议&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;    &lt;p&gt;这个git项目中有多个文件夹，本章的Account-Service源码在spring-cloud-k8s-account-service文件夹下，Web-Service源码在spring-cloud-k8s-web-service文件夹下，如下图红框所示：      &lt;br /&gt;      &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://img-blog.csdnimg.cn/20190616221001730.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly94aW5jaGVuLmJsb2cuY3Nkbi5uZXQ=,size_16,color_FFFFFF,t_70"&gt;&lt;/img&gt;      &lt;br /&gt;下面是详细的编码过程；&lt;/p&gt;    &lt;h3&gt;      &lt;a&gt;&lt;/a&gt;开发和部署Account-Service服务&lt;/h3&gt;    &lt;p&gt;Account-Service服务是个很普通的springboot应用，和spring-cloud-kubernetes没有任何关系：&lt;/p&gt;    &lt;ol&gt;      &lt;li&gt;通过maven创建一个springboot应用，artifactId是account-service，pom.xml内容如下：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&amp;lt;projectxmlns=&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;xsi:schemaLocation=&amp;quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;quot;&amp;gt;&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&amp;lt;parent&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;2.1.1.RELEASE&amp;lt;/version&amp;gt;&amp;lt;relativePath/&amp;gt;&amp;lt;!-- lookup parent from repository --&amp;gt;&amp;lt;/parent&amp;gt;&amp;lt;groupId&amp;gt;com.bolingcavalry&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;account-service&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;&amp;lt;name&amp;gt;account-service&amp;lt;/name&amp;gt;&amp;lt;description&amp;gt;Demo project for Spring Cloud service provider run in kubernetes&amp;lt;/description&amp;gt;&amp;lt;properties&amp;gt;&amp;lt;java.version&amp;gt;1.8&amp;lt;/java.version&amp;gt;&amp;lt;spring-boot.version&amp;gt;2.1.1.RELEASE&amp;lt;/spring-boot.version&amp;gt;&amp;lt;maven-checkstyle-plugin.failsOnError&amp;gt;false&amp;lt;/maven-checkstyle-plugin.failsOnError&amp;gt;&amp;lt;maven-checkstyle-plugin.failsOnViolation&amp;gt;false&amp;lt;/maven-checkstyle-plugin.failsOnViolation&amp;gt;&amp;lt;maven-checkstyle-plugin.includeTestSourceDirectory&amp;gt;false&amp;lt;/maven-checkstyle-plugin.includeTestSourceDirectory&amp;gt;&amp;lt;maven-compiler-plugin.version&amp;gt;3.5&amp;lt;/maven-compiler-plugin.version&amp;gt;&amp;lt;maven-deploy-plugin.version&amp;gt;2.8.2&amp;lt;/maven-deploy-plugin.version&amp;gt;&amp;lt;maven-failsafe-plugin.version&amp;gt;2.18.1&amp;lt;/maven-failsafe-plugin.version&amp;gt;&amp;lt;maven-surefire-plugin.version&amp;gt;2.21.0&amp;lt;/maven-surefire-plugin.version&amp;gt;&amp;lt;fabric8.maven.plugin.version&amp;gt;3.5.37&amp;lt;/fabric8.maven.plugin.version&amp;gt;&amp;lt;springcloud.version&amp;gt;2.1.1.RELEASE&amp;lt;/springcloud.version&amp;gt;&amp;lt;/properties&amp;gt;&amp;lt;dependencyManagement&amp;gt;&amp;lt;dependencies&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-boot-dependencies&amp;lt;/artifactId&amp;gt;&amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;&amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;&amp;lt;version&amp;gt;${spring-boot.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;/dependencies&amp;gt;&amp;lt;/dependencyManagement&amp;gt;&amp;lt;dependencies&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-boot-starter&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${springcloud.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${springcloud.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;/dependencies&amp;gt;&amp;lt;build&amp;gt;&amp;lt;plugins&amp;gt;&amp;lt;plugin&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${spring-boot.version}&amp;lt;/version&amp;gt;&amp;lt;executions&amp;gt;&amp;lt;execution&amp;gt;&amp;lt;goals&amp;gt;&amp;lt;goal&amp;gt;repackage&amp;lt;/goal&amp;gt;&amp;lt;/goals&amp;gt;&amp;lt;/execution&amp;gt;&amp;lt;/executions&amp;gt;&amp;lt;/plugin&amp;gt;&amp;lt;plugin&amp;gt;&amp;lt;!--skip deploy --&amp;gt;&amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;maven-deploy-plugin&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${maven-deploy-plugin.version}&amp;lt;/version&amp;gt;&amp;lt;configuration&amp;gt;&amp;lt;skip&amp;gt;true&amp;lt;/skip&amp;gt;&amp;lt;/configuration&amp;gt;&amp;lt;/plugin&amp;gt;&amp;lt;plugin&amp;gt;&amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;maven-surefire-plugin&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${maven-surefire-plugin.version}&amp;lt;/version&amp;gt;&amp;lt;configuration&amp;gt;&amp;lt;skipTests&amp;gt;true&amp;lt;/skipTests&amp;gt;&amp;lt;!-- Workaround for https://issues.apache.org/jira/browse/SUREFIRE-1588 --&amp;gt;&amp;lt;useSystemClassLoader&amp;gt;false&amp;lt;/useSystemClassLoader&amp;gt;&amp;lt;/configuration&amp;gt;&amp;lt;/plugin&amp;gt;&amp;lt;plugin&amp;gt;&amp;lt;groupId&amp;gt;io.fabric8&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;fabric8-maven-plugin&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${fabric8.maven.plugin.version}&amp;lt;/version&amp;gt;&amp;lt;executions&amp;gt;&amp;lt;execution&amp;gt;&amp;lt;id&amp;gt;fmp&amp;lt;/id&amp;gt;&amp;lt;goals&amp;gt;&amp;lt;goal&amp;gt;resource&amp;lt;/goal&amp;gt;&amp;lt;/goals&amp;gt;&amp;lt;/execution&amp;gt;&amp;lt;/executions&amp;gt;&amp;lt;/plugin&amp;gt;&amp;lt;/plugins&amp;gt;&amp;lt;/build&amp;gt;&amp;lt;profiles&amp;gt;&amp;lt;profile&amp;gt;&amp;lt;id&amp;gt;kubernetes&amp;lt;/id&amp;gt;&amp;lt;build&amp;gt;&amp;lt;plugins&amp;gt;&amp;lt;plugin&amp;gt;&amp;lt;groupId&amp;gt;io.fabric8&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;fabric8-maven-plugin&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${fabric8.maven.plugin.version}&amp;lt;/version&amp;gt;&amp;lt;executions&amp;gt;&amp;lt;execution&amp;gt;&amp;lt;id&amp;gt;fmp&amp;lt;/id&amp;gt;&amp;lt;goals&amp;gt;&amp;lt;goal&amp;gt;resource&amp;lt;/goal&amp;gt;&amp;lt;goal&amp;gt;build&amp;lt;/goal&amp;gt;&amp;lt;/goals&amp;gt;&amp;lt;/execution&amp;gt;&amp;lt;/executions&amp;gt;&amp;lt;configuration&amp;gt;&amp;lt;enricher&amp;gt;&amp;lt;config&amp;gt;&amp;lt;fmp-service&amp;gt;&amp;lt;type&amp;gt;NodePort&amp;lt;/type&amp;gt;&amp;lt;/fmp-service&amp;gt;&amp;lt;/config&amp;gt;&amp;lt;/enricher&amp;gt;&amp;lt;/configuration&amp;gt;&amp;lt;/plugin&amp;gt;&amp;lt;/plugins&amp;gt;&amp;lt;/build&amp;gt;&amp;lt;/profile&amp;gt;&amp;lt;/profiles&amp;gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;    &lt;p&gt;由上面的pom.xml内容可见，account-service应用是个简单的web应用，和SpringCloud、spring-cloud-kubernetes都没有任何关系，和其他springboot唯一的不同就是用到了fabric8-maven-plugin插件，可以方便的将应用部署到kubernetes环境；&lt;/p&gt;    &lt;ol start="2"&gt;      &lt;li&gt;application.yml内容如下，依旧很简单：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;spring:application:name:account-serviceserver:port:8080&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="3"&gt;      &lt;li&gt;对外提供服务的是AccountController ，方法getName返回了当前容器的hostname，方法health用于响应kubernetes的两个探针，方法ribbonPing用于响应使用了ribbon服务的调用方，它们会调用这个接口来确定当前服务是否正常：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;@RestControllerpublicclassAccountController{privatestaticfinalLogger LOG=LoggerFactory.getLogger(AccountController.class);privatefinalString hostName=System.getenv(&amp;quot;HOSTNAME&amp;quot;);/**
     * 探针检查响应类
     * @return
     */@RequestMapping(&amp;quot;/health&amp;quot;)publicStringhealth(){return&amp;quot;OK&amp;quot;;}@RequestMapping(&amp;quot;/&amp;quot;)publicStringribbonPing(){LOG.info(&amp;quot;ribbonPing of {}&amp;quot;,hostName);returnhostName;}/**
     * 返回hostname
     * @return 当前应用所在容器的hostname.
     */@RequestMapping(&amp;quot;/name&amp;quot;)publicStringgetName(){returnthis.hostName+&amp;quot;, &amp;quot;+newSimpleDateFormat(&amp;quot;yyyy-MM-dd HH:mm:ss&amp;quot;).format(newDate());}}&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="4"&gt;      &lt;li&gt;将上述工程的源码放在minikube机器上，确保maven设置正常，然后在pom.xml文件所在目录执行以下命令，即可编译构建工程并部署到kubernetes上：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;mvn cleaninstallfabric8:deploy -Dfabric8.generator.from=fabric8/java-jboss-openjdk8-jdk -Pkubernetes&lt;/code&gt;&lt;/pre&gt;    &lt;p&gt;执行成功后控制台输出如下：&lt;/p&gt;    &lt;pre&gt;      &lt;code&gt;...[INFO]Installing /usr/local/work/k8s/ribbon/spring-cloud-k8s-account-service/target/classes/META-INF/fabric8/kubernetes.json to /root/.m2/repository/com/bolingcavalry/account-service/0.0.1-SNAPSHOT/account-service-0.0.1-SNAPSHOT-kubernetes.json[INFO][INFO]&amp;lt;&amp;lt;&amp;lt;fabric8-maven-plugin:3.5.37:deploy(default-cli)&amp;lt;install@ account-service&amp;lt;&amp;lt;&amp;lt;[INFO][INFO][INFO]--- fabric8-maven-plugin:3.5.37:deploy(default-cli)@ account-service ---[INFO]F8: Using Kubernetes at https://192.168.121.133:8443/innamespace default with manifest /usr/local/work/k8s/ribbon/spring-cloud-k8s-account-service/target/classes/META-INF/fabric8/kubernetes.yml[INFO]Using namespace: default[INFO]Updating a Service from kubernetes.yml[INFO]Updated Service: target/fabric8/applyJson/default/service-account-service.json[INFO]Using namespace: default[INFO]Updating Deployment from kubernetes.yml[INFO]Updated Deployment: target/fabric8/applyJson/default/deployment-account-service.json[INFO]F8: HINT: Use thecommand`kubectl get pods -w`towatchyour pods start up[INFO]------------------------------------------------------------------------[INFO]BUILD SUCCESS[INFO]------------------------------------------------------------------------[INFO]Total time:  11.941 s[INFO]Finished at: 2019-06-16T19:00:51+08:00[INFO]------------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="5"&gt;      &lt;li&gt;检查kubernetes上的部署和服务是否正常：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;[root@minikube spring-cloud-k8s-account-service]# kubectl get deploymentsNAME              READY   UP-TO-DATE   AVAILABLE   AGE
account-service   1/1     1            1           69m[root@minikube spring-cloud-k8s-account-service]# kubectl get servicesNAME              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)AGE
account-service   NodePort    10.105.157.201&amp;lt;none&amp;gt;8080:32596/TCP   69m
kubernetes        ClusterIP   10.96.0.1&amp;lt;none&amp;gt;443/TCP          8d&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="6"&gt;      &lt;li&gt;minikube的service命令可以得到指定服务的访问地址：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;[root@minikube spring-cloud-k8s-account-service]# minikube service account-service --urlhttp://192.168.121.133:32596&lt;/code&gt;&lt;/pre&gt;    &lt;p&gt;可见account-service的服务可以通过这个url访问：      &lt;a href="http://192.168.121.133:32596"&gt;http://192.168.121.133:32596&lt;/a&gt;&lt;/p&gt;    &lt;ol start="7"&gt;      &lt;li&gt;用浏览器访问地址：        &lt;a href="http://192.168.121.133:32596/name"&gt;http://192.168.121.133:32596/name&lt;/a&gt;，如下图所示，可以正常访问account-service提供的服务：        &lt;br /&gt;        &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://img-blog.csdnimg.cn/20190616190934770.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly94aW5jaGVuLmJsb2cuY3Nkbi5uZXQ=,size_16,color_FFFFFF,t_70"&gt;&lt;/img&gt;        &lt;br /&gt;现在account-service服务已经就绪，接下来是开发和部署web-service应用。&lt;/li&gt;&lt;/ol&gt;    &lt;h3&gt;      &lt;a&gt;&lt;/a&gt;开发和部署Web-Service服务&lt;/h3&gt;    &lt;p&gt;Web-Service服务是个springboot应用，用到了spring-cloud-kubernetes提供的注册发现能力，以轮询的方式访问指定服务的全部pod：&lt;/p&gt;    &lt;ol&gt;      &lt;li&gt;通过maven创建一个springboot应用，artifactId是web-service，pom.xml内容如下，要重点关注的是spring-cloud-starter-kubernetes-ribbon的依赖：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&amp;lt;projectxmlns=&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;xsi:schemaLocation=&amp;quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;quot;&amp;gt;&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&amp;lt;parent&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;2.1.1.RELEASE&amp;lt;/version&amp;gt;&amp;lt;relativePath/&amp;gt;&amp;lt;!-- lookup parent from repository --&amp;gt;&amp;lt;/parent&amp;gt;&amp;lt;groupId&amp;gt;com.bolingcavalry&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;web-service&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;&amp;lt;name&amp;gt;web-service&amp;lt;/name&amp;gt;&amp;lt;description&amp;gt;Demo project for Spring Cloud service consumer run in kubernetes&amp;lt;/description&amp;gt;&amp;lt;properties&amp;gt;&amp;lt;java.version&amp;gt;1.8&amp;lt;/java.version&amp;gt;&amp;lt;spring-boot.version&amp;gt;2.1.1.RELEASE&amp;lt;/spring-boot.version&amp;gt;&amp;lt;maven-checkstyle-plugin.failsOnError&amp;gt;false&amp;lt;/maven-checkstyle-plugin.failsOnError&amp;gt;&amp;lt;maven-checkstyle-plugin.failsOnViolation&amp;gt;false&amp;lt;/maven-checkstyle-plugin.failsOnViolation&amp;gt;&amp;lt;maven-checkstyle-plugin.includeTestSourceDirectory&amp;gt;false&amp;lt;/maven-checkstyle-plugin.includeTestSourceDirectory&amp;gt;&amp;lt;maven-compiler-plugin.version&amp;gt;3.5&amp;lt;/maven-compiler-plugin.version&amp;gt;&amp;lt;maven-deploy-plugin.version&amp;gt;2.8.2&amp;lt;/maven-deploy-plugin.version&amp;gt;&amp;lt;maven-failsafe-plugin.version&amp;gt;2.18.1&amp;lt;/maven-failsafe-plugin.version&amp;gt;&amp;lt;maven-surefire-plugin.version&amp;gt;2.21.0&amp;lt;/maven-surefire-plugin.version&amp;gt;&amp;lt;fabric8.maven.plugin.version&amp;gt;3.5.37&amp;lt;/fabric8.maven.plugin.version&amp;gt;&amp;lt;springcloud.kubernetes.version&amp;gt;1.0.1.RELEASE&amp;lt;/springcloud.kubernetes.version&amp;gt;&amp;lt;springcloud.version&amp;gt;2.1.1.RELEASE&amp;lt;/springcloud.version&amp;gt;&amp;lt;/properties&amp;gt;&amp;lt;dependencyManagement&amp;gt;&amp;lt;dependencies&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-boot-dependencies&amp;lt;/artifactId&amp;gt;&amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;&amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;&amp;lt;version&amp;gt;${spring-boot.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;/dependencies&amp;gt;&amp;lt;/dependencyManagement&amp;gt;&amp;lt;dependencies&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-cloud-kubernetes-core&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${springcloud.kubernetes.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-cloud-kubernetes-discovery&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${springcloud.kubernetes.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-cloud-starter-kubernetes-ribbon&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${springcloud.kubernetes.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-cloud-commons&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${springcloud.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-boot-starter&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${springcloud.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${springcloud.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-cloud-starter-netflix-ribbon&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${springcloud.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;dependency&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-cloud-starter-netflix-hystrix&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${springcloud.version}&amp;lt;/version&amp;gt;&amp;lt;/dependency&amp;gt;&amp;lt;/dependencies&amp;gt;&amp;lt;build&amp;gt;&amp;lt;plugins&amp;gt;&amp;lt;plugin&amp;gt;&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${spring-boot.version}&amp;lt;/version&amp;gt;&amp;lt;executions&amp;gt;&amp;lt;execution&amp;gt;&amp;lt;goals&amp;gt;&amp;lt;goal&amp;gt;repackage&amp;lt;/goal&amp;gt;&amp;lt;/goals&amp;gt;&amp;lt;/execution&amp;gt;&amp;lt;/executions&amp;gt;&amp;lt;/plugin&amp;gt;&amp;lt;plugin&amp;gt;&amp;lt;!--skip deploy --&amp;gt;&amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;maven-deploy-plugin&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${maven-deploy-plugin.version}&amp;lt;/version&amp;gt;&amp;lt;configuration&amp;gt;&amp;lt;skip&amp;gt;true&amp;lt;/skip&amp;gt;&amp;lt;/configuration&amp;gt;&amp;lt;/plugin&amp;gt;&amp;lt;plugin&amp;gt;&amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;maven-surefire-plugin&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${maven-surefire-plugin.version}&amp;lt;/version&amp;gt;&amp;lt;configuration&amp;gt;&amp;lt;skipTests&amp;gt;true&amp;lt;/skipTests&amp;gt;&amp;lt;!-- Workaround for https://issues.apache.org/jira/browse/SUREFIRE-1588 --&amp;gt;&amp;lt;useSystemClassLoader&amp;gt;false&amp;lt;/useSystemClassLoader&amp;gt;&amp;lt;/configuration&amp;gt;&amp;lt;/plugin&amp;gt;&amp;lt;plugin&amp;gt;&amp;lt;groupId&amp;gt;io.fabric8&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;fabric8-maven-plugin&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${fabric8.maven.plugin.version}&amp;lt;/version&amp;gt;&amp;lt;executions&amp;gt;&amp;lt;execution&amp;gt;&amp;lt;id&amp;gt;fmp&amp;lt;/id&amp;gt;&amp;lt;goals&amp;gt;&amp;lt;goal&amp;gt;resource&amp;lt;/goal&amp;gt;&amp;lt;/goals&amp;gt;&amp;lt;/execution&amp;gt;&amp;lt;/executions&amp;gt;&amp;lt;/plugin&amp;gt;&amp;lt;/plugins&amp;gt;&amp;lt;/build&amp;gt;&amp;lt;profiles&amp;gt;&amp;lt;profile&amp;gt;&amp;lt;id&amp;gt;kubernetes&amp;lt;/id&amp;gt;&amp;lt;build&amp;gt;&amp;lt;plugins&amp;gt;&amp;lt;plugin&amp;gt;&amp;lt;groupId&amp;gt;io.fabric8&amp;lt;/groupId&amp;gt;&amp;lt;artifactId&amp;gt;fabric8-maven-plugin&amp;lt;/artifactId&amp;gt;&amp;lt;version&amp;gt;${fabric8.maven.plugin.version}&amp;lt;/version&amp;gt;&amp;lt;executions&amp;gt;&amp;lt;execution&amp;gt;&amp;lt;id&amp;gt;fmp&amp;lt;/id&amp;gt;&amp;lt;goals&amp;gt;&amp;lt;goal&amp;gt;resource&amp;lt;/goal&amp;gt;&amp;lt;goal&amp;gt;build&amp;lt;/goal&amp;gt;&amp;lt;/goals&amp;gt;&amp;lt;/execution&amp;gt;&amp;lt;/executions&amp;gt;&amp;lt;configuration&amp;gt;&amp;lt;enricher&amp;gt;&amp;lt;config&amp;gt;&amp;lt;fmp-service&amp;gt;&amp;lt;type&amp;gt;NodePort&amp;lt;/type&amp;gt;&amp;lt;/fmp-service&amp;gt;&amp;lt;/config&amp;gt;&amp;lt;/enricher&amp;gt;&amp;lt;/configuration&amp;gt;&amp;lt;/plugin&amp;gt;&amp;lt;/plugins&amp;gt;&amp;lt;/build&amp;gt;&amp;lt;/profile&amp;gt;&amp;lt;/profiles&amp;gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="2"&gt;      &lt;li&gt;application.yml的内容如下，增加了熔断的配置：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;spring:application:name:web-serviceserver:port:8080backend:ribbon:eureka:enabled:falseclient:enabled:trueServerListRefreshInterval:5000hystrix.command.BackendCall.execution.isolation.thread.timeoutInMilliseconds:5000hystrix.threadpool.BackendCallThread.coreSize:5&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="3"&gt;      &lt;li&gt;创建一个ribbon的配置类RibbonConfiguration：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;packagecom.bolingcavalry.webservice;importcom.netflix.client.config.IClientConfig;importcom.netflix.loadbalancer.AvailabilityFilteringRule;importcom.netflix.loadbalancer.IPing;importcom.netflix.loadbalancer.IRule;importcom.netflix.loadbalancer.PingUrl;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;/**
 * @Description: ribbon配置类
 * @author: willzhao E-mail: zq2599@gmail.com
 * @date: 2019/6/16 11:52
 */publicclassRibbonConfiguration{@AutowiredIClientConfig ribbonClientConfig;/**
     * 检查服务是否可用的实例，
     * 此地址返回的响应的返回码如果是200表示服务可用
     * @param config
     * @return
     */@BeanpublicIPingribbonPing(IClientConfig config){returnnewPingUrl();}/**
     * 轮询规则
     * @param config
     * @return
     */@BeanpublicIRuleribbonRule(IClientConfig config){returnnewAvailabilityFilteringRule();}}&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="4"&gt;      &lt;li&gt;应用启动类如下，注意增加了服务发现、熔断、ribbon的配置，还定义了restTemplte实例，注意@LoadBalanced注解：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;packagecom.bolingcavalry.webservice;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;importorg.springframework.cloud.client.discovery.EnableDiscoveryClient;importorg.springframework.cloud.client.loadbalancer.LoadBalanced;importorg.springframework.cloud.netflix.ribbon.RibbonClient;importorg.springframework.context.annotation.Bean;importorg.springframework.web.client.RestTemplate;@SpringBootApplication@EnableDiscoveryClient@EnableCircuitBreaker@RibbonClient(name=&amp;quot;account-service&amp;quot;,configuration=RibbonConfiguration.class)publicclassWebServiceApplication{publicstaticvoidmain(String[]args){SpringApplication.run(WebServiceApplication.class,args);}@LoadBalanced@BeanRestTemplaterestTemplate(){returnnewRestTemplate();}}&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="5"&gt;      &lt;li&gt;远程调用account-service的http接口的逻辑被放进服务类AccountService中，注意URL中用的是服务名account-service：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;packagecom.bolingcavalry.webservice;importcom.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;importcom.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.web.client.RestTemplate;importjava.text.SimpleDateFormat;importjava.util.Date;/**
 * @Description: 这里面封装了远程调用account-service提供服务的逻辑
 * @author: willzhao E-mail: zq2599@gmail.com
 * @date: 2019/6/16 12:21
 */@ServicepublicclassAccountService{@AutowiredprivateRestTemplate restTemplate;@HystrixCommand(fallbackMethod=&amp;quot;getFallbackName&amp;quot;,commandProperties={@HystrixProperty(name=&amp;quot;execution.isolation.thread.timeoutInMilliseconds&amp;quot;,value=&amp;quot;1000&amp;quot;)})publicStringgetDataFromSpringCloudK8SProvider(){returnthis.restTemplate.getForObject(&amp;quot;http://account-service/name&amp;quot;,String.class);}/**
     * 熔断时调用的方法
     * @return
     */privateStringgetFallbackName(){return&amp;quot;Fallback&amp;quot;+&amp;quot;, &amp;quot;+newSimpleDateFormat(&amp;quot;yyyy-MM-dd HH:mm:ss&amp;quot;).format(newDate());}}&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="6"&gt;      &lt;li&gt;最后是响应web请求的WebServiceController类，这里面调用了AccountService的服务，这样我们从web发起请求后，web-service就会远程调用account-service的服务：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;packagecom.bolingcavalry.webservice;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;/**
 * @Description: 测试用的controller，会远程调用account-service的服务
 * @author: willzhao E-mail: zq2599@gmail.com
 * @date: 2019/6/16 11:46
 */@RestControllerpublicclassWebServiceController{@AutowiredprivateAccountService accountService;/**
     * 探针检查响应类
     * @return
     */@RequestMapping(&amp;quot;/health&amp;quot;)publicStringhealth(){return&amp;quot;OK&amp;quot;;}/**
     * 远程调用account-service提供的服务
     * @return 多次远程调返回的所有结果.
     */@RequestMapping(&amp;quot;/account&amp;quot;)publicStringaccount(){StringBuilder sbud=newStringBuilder();for(inti=0;i&amp;lt;10;i++){sbud.append(accountService.getDataFromSpringCloudK8SProvider()).append(&amp;quot;&amp;lt;br&amp;gt;&amp;quot;);}returnsbud.toString();}}&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="7"&gt;      &lt;li&gt;将上述工程的源码放在minikube机器上，确保maven设置正常，然后在pom.xml文件所在目录执行以下命令，即可编译构建工程并部署到kubernetes上：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;mvn cleaninstallfabric8:deploy -Dfabric8.generator.from=fabric8/java-jboss-openjdk8-jdk -Pkubernetes&lt;/code&gt;&lt;/pre&gt;    &lt;p&gt;执行成功后控制台输出如下：&lt;/p&gt;    &lt;pre&gt;      &lt;code&gt;...[INFO]Installing /usr/local/work/k8s/ribbon/spring-cloud-k8s-web-service/target/classes/META-INF/fabric8/kubernetes.json to /root/.m2/repository/com/bolingcavalry/web-service/0.0.1-SNAPSHOT/web-service-0.0.1-SNAPSHOT-kubernetes.json[INFO][INFO]&amp;lt;&amp;lt;&amp;lt;fabric8-maven-plugin:3.5.37:deploy(default-cli)&amp;lt;install@ web-service&amp;lt;&amp;lt;&amp;lt;[INFO][INFO][INFO]--- fabric8-maven-plugin:3.5.37:deploy(default-cli)@ web-service ---[INFO]F8: Using Kubernetes at https://192.168.121.133:8443/innamespace default with manifest /usr/local/work/k8s/ribbon/spring-cloud-k8s-web-service/target/classes/META-INF/fabric8/kubernetes.yml[INFO]Using namespace: default[INFO]Creating a Service from kubernetes.yml namespace default name web-service[INFO]Created Service: target/fabric8/applyJson/default/service-web-service.json[INFO]Using namespace: default[INFO]Creating a Deployment from kubernetes.yml namespace default name web-service[INFO]Created Deployment: target/fabric8/applyJson/default/deployment-web-service.json[INFO]F8: HINT: Use thecommand`kubectl get pods -w`towatchyour pods start up[INFO]------------------------------------------------------------------------[INFO]BUILD SUCCESS[INFO]------------------------------------------------------------------------[INFO]Total time:  12.792 s[INFO]Finished at: 2019-06-16T19:24:21+08:00[INFO]------------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="8"&gt;      &lt;li&gt;检查kubernetes上的部署和服务是否正常：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;[root@minikube spring-cloud-k8s-web-service]# kubectl get deploymentsNAME              READY   UP-TO-DATE   AVAILABLE   AGE
account-service   1/1     1            1           109m
web-service       1/1     1            1           18m[root@minikube spring-cloud-k8s-web-service]# kubectl get svcNAME              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)AGE
account-service   NodePort    10.105.157.201&amp;lt;none&amp;gt;8080:32596/TCP   109m
kubernetes        ClusterIP   10.96.0.1&amp;lt;none&amp;gt;443/TCP          8d
web-service       NodePort    10.99.211.179&amp;lt;none&amp;gt;8080:30519/TCP   18m&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="9"&gt;      &lt;li&gt;minikube的service命令可以得到指定服务的访问地址：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;[root@minikube spring-cloud-k8s-web-service]# minikube service web-service --urlhttp://192.168.121.133:30519&lt;/code&gt;&lt;/pre&gt;    &lt;p&gt;可见web-service的服务可以通过这个url访问：      &lt;a href="http://192.168.121.133:30519"&gt;http://192.168.121.133:30519&lt;/a&gt;&lt;/p&gt;    &lt;ol start="10"&gt;      &lt;li&gt;用浏览器访问地址：        &lt;a href="http://192.168.121.133:30519/account"&gt;http://192.168.121.133:30519/account&lt;/a&gt;，如下图所示，页面上展示的内容都是web-service调用了account-service的接口返回的，证明kubernetes上的注册发现能力正常：        &lt;br /&gt;        &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://img-blog.csdnimg.cn/20190616194557751.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly94aW5jaGVuLmJsb2cuY3Nkbi5uZXQ=,size_16,color_FFFFFF,t_70"&gt;&lt;/img&gt;&lt;/li&gt;&lt;/ol&gt;    &lt;h3&gt;      &lt;a&gt;&lt;/a&gt;扩容验证ribbon轮询能力&lt;/h3&gt;    &lt;p&gt;虽然web-service可以正常调用account-service的服务，但始终访问的是一个pod，接下来我们就对account-service的pod进行扩容，将数量调整为2个，看看web-service是否可以轮询调用每个account-service的pod：&lt;/p&gt;    &lt;ol&gt;      &lt;li&gt;执行以下命令即可将pod数量调整为2个：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;kubectl scale --replicas=2 deployment account-service&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="2"&gt;      &lt;li&gt;检查account-service的pod，发现已经有两个了(account-service-5554576647-m29xr和account-service-5554576647-zwwml)：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;[root@minikube spring-cloud-k8s-web-service]# kubectl get podsNAME                               READY   STATUS    RESTARTS   AGE
account-service-5554576647-m29xr   1/1     Running   0          53m
account-service-5554576647-zwwml   1/1     Running   0          20s
web-service-6d775855c7-7lkvr       1/1     Running   0          29m&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="3"&gt;      &lt;li&gt;用浏览器访问地址：        &lt;a href="http://192.168.121.133:30519/account"&gt;http://192.168.121.133:30519/account&lt;/a&gt;，如下图所示，account-sercice返回的hostname已经变成了两种，和前面查到的pod的name一致，可见web-service的确是通过ribbon轮询访问了多个account-service的pod：        &lt;br /&gt;        &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://img-blog.csdnimg.cn/2019061619564254.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly94aW5jaGVuLmJsb2cuY3Nkbi5uZXQ=,size_16,color_FFFFFF,t_70"&gt;&lt;/img&gt;&lt;/li&gt;&lt;/ol&gt;    &lt;h3&gt;      &lt;a&gt;&lt;/a&gt;验证熔断能力&lt;/h3&gt;    &lt;p&gt;接下来验证web-service配置的熔断服务是否可以生效：&lt;/p&gt;    &lt;ol&gt;      &lt;li&gt;执行以下命令将account-service的deployment删除：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;kubectl delete deployment account-service&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="2"&gt;      &lt;li&gt;再浏览器访问地址：        &lt;a href="http://192.168.121.133:30519/account"&gt;http://192.168.121.133:30519/account&lt;/a&gt;，如下图所示，页面上的&amp;quot;Fallback&amp;quot;是配置的熔断方法返回的内容，可见熔断配置已经生效：        &lt;br /&gt;        &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://img-blog.csdnimg.cn/20190616200622598.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly94aW5jaGVuLmJsb2cuY3Nkbi5uZXQ=,size_16,color_FFFFFF,t_70"&gt;&lt;/img&gt;&lt;/li&gt;      &lt;li&gt;再回到web-service的pom.xml所在位置执行以下命令，这样会重新构建部署一次web-service服务：&lt;/li&gt;&lt;/ol&gt;    &lt;pre&gt;      &lt;code&gt;mvn cleaninstallfabric8:deploy -Dfabric8.generator.from=fabric8/java-jboss-openjdk8-jdk -Pkubernetes&lt;/code&gt;&lt;/pre&gt;    &lt;ol start="4"&gt;      &lt;li&gt;再浏览器访问地址：        &lt;a href="http://192.168.121.133:30519/account"&gt;http://192.168.121.133:30519/account&lt;/a&gt;，如下图所示，服务成功恢复：        &lt;br /&gt;        &lt;img alt="&amp;#22312;&amp;#36825;&amp;#37324;&amp;#25554;&amp;#20837;&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://img-blog.csdnimg.cn/20190616215427372.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly94aW5jaGVuLmJsb2cuY3Nkbi5uZXQ=,size_16,color_FFFFFF,t_70"&gt;&lt;/img&gt;&lt;/li&gt;&lt;/ol&gt;    &lt;p&gt;至此，spring-cloud-kubernetes的服务发现和轮询实战(含熔断)就全部完成了，利用API Server提供的信息，spring-cloud-kubernetes将原生的kubernetes服务带给了SpringCloud应用，帮助传统微服务更好的融合在kubernetes环境中，如果您也在考虑将应用迁移到kubernetes上，希望本文能给您一些参考。&lt;/p&gt;    &lt;h3&gt;   &lt;br /&gt;&lt;/h3&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 />
      <guid isPermaLink="true">https://itindex.net/detail/60981-spring-cloud-kubernetes</guid>
      <pubDate>Sun, 01 Nov 2020 08:38:35 CST</pubDate>
    </item>
    <item>
      <title>AIOps在美团的探索与实践——故障发现篇</title>
      <link>https://itindex.net/detail/60941-aiops-%E7%BE%8E%E5%9B%A2-%E5%AE%9E%E8%B7%B5</link>
      <description>&lt;br /&gt;【编者的话】AIOps，最初的定义是Algorithm IT Operations，是利用运维算法来实现运维的自动化，最终走向无人化运维。随着技术成熟，逐步确定为Artificial Intelligence for IT Operations——智能运维，将人工智能应用于运维领域，基于已有的运维数据（日志、监控信息、应用信息等），通过机器学习的方式来进一步解决自动化运维无法解决的问题。本文系AIOps在美团的探索与实践的第一部分，如何自动发现故障问题，其中重点介绍了美团时序数据异常检测系统Horae的架构与设计。 &lt;br /&gt;
 &lt;h3&gt;背景&lt;/h3&gt;早期的运维工作大部分是由运维人员手工完成的，手工运维在互联网业务快速扩张、人力成本高企的时代，难以维系。于是，自动化运维应运而生，它主要通过可被自动触发、预定义规则的脚本，来执行常见、重复性的运维工作，从而减少人力成本，提高运维的效率。总的来说，自动化运维可以认为是一种基于行业领域知识和运维场景领域知识的专家系统。随着整个互联网业务急剧膨胀，以及服务类型的复杂多样，“基于人为指定规则”的专家系统逐渐变得力不从心，自动化运维的不足，日益凸显，当前美团在业务监控和运维层面也面临着同样的困境。 &lt;br /&gt;
 &lt;br /&gt;DevOps的出现，部分解决了上述问题，它强调从价值交付的全局视角，但DevOps更强调横向融合及打通，AIOps则是DevOps在运维（技术运营）侧的高阶实现，两者并不冲突。AIOps不依赖于人为指定规则，主张由机器学习算法自动地从海量运维数据（包括事件本身以及运维人员的人工处理日志）中不断地学习，不断提炼并总结规则。AIOps在自动化运维的基础上，增加了一个基于机器学习的大脑，指挥监测系统采集大脑决策所需的数据，做出分析、决策，并指挥自动化脚本去执行大脑的决策，从而达到运维系统的整体目标。综上看，自动化运维水平是AIOps的重要基石，而AIOps将基于自动化运维，将AI和运维很好地结合起来，这个过程需要三方面的知识： &lt;br /&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;br /&gt;
 &lt;br /&gt;美团技术团队在行业、业务领域知识和运维领域的知识等方面有着长期的积累，已经沉淀出不少工具和产品，实现了自动化运维，同时在AIOps方面也有一些初步的成果。我们希望通过在AIOps上持续投入、迭代和钻研，将之前积累的行业、业务和运维领域的知识应用到AIOps中，从而能让AIOps为业务研发、产品和运营团队赋能，提高整个公司的生产效率。 &lt;br /&gt;
 &lt;h3&gt;技术路线规划&lt;/h3&gt; &lt;h4&gt;AIOps能力建设&lt;/h4&gt;AIOps的建设可以先由无到局部单点探索，在单点探索上得到初步的成果，再对单点能力进行完善，形成解决某个局部问题的运维AI学件，再由多个具有AI能力的单运维能力点组合成一个智能运维流程。行业通用的演进路线如下： &lt;br /&gt;
 &lt;ul&gt;  &lt;li&gt;开始尝试应用AI能力，还无较为成熟的单点应用。&lt;/li&gt;  &lt;li&gt;具备单场景的AI运维能力，可以初步形成供内部使用的学件。&lt;/li&gt;  &lt;li&gt;有由多个单场景AI运维模块串联起来的流程化AI运维能力，可以对外提供可靠的运维AI学件。&lt;/li&gt;  &lt;li&gt;主要运维场景均已实现流程化免干预AI运维能力，可以对外提供供可靠的AIOps服务。&lt;/li&gt;  &lt;li&gt;有核心中枢AI，可以在成本、质量、效率间从容调整，达到业务不同生命周期对三个方面不同的指标要求，可实现多目标下的最优或按需最优。&lt;/li&gt;&lt;/ul&gt; &lt;br /&gt;
 &lt;br /&gt;所谓学件，亦称AI运维组件[1]（南京大学周志华老师提出），类似程序中的API或公共库，但API及公共库不含具体业务数据，只是某种算法，而AI运维组件（或称学件），则是在类似API的基础上，兼具对某个运维场景智能化解决的“记忆”能力，将处理这个场景的智能规则保存在了这个组件中，学件（Learnware）= 模型（Model）+规约（Specification）。AIOps具体的能力框架如下图1所示： &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/f8cb6a27ed965f8bd85297c47a44f69a.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="1.png" src="http://dockone.io/uploads/article/20201016/f8cb6a27ed965f8bd85297c47a44f69a.png" title="1.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图1 AIOps能力框架图&lt;/em&gt; &lt;br /&gt;
 &lt;h4&gt;关联团队建设&lt;/h4&gt;AIOps团队内部人员根据职能可分为三类团队，分别为SRE团队、开发工程师（稳定性保障方向）团队和算法工程师团队，他们在AIOps相关工作中分别扮演不同的角色，三者缺一不可。SRE能从业务的技术运营中，提炼出智能化的需求点，在开发实施前能够考虑好需求方案，产品上线后能对产品数据进行持续的运营。开发工程师负责进行平台相关功能和模块的开发，以降低用户的使用门槛，提升用户的使用效率，根据企业AIOps程度和能力的不同，运维自动化平台开发和运维数据平台开发的权重不同，在工程落地上能够考虑好健壮性、鲁棒性、扩展性等，合理拆分任务，保障成果落地。算法工程师则针对来自于SRE的需求进行理解和梳理，对业界方案、相关论文、算法进行调研和尝试，完成最终算法落地方案的输出工作，并不断迭代优化。各团队之间的关系图如下图2所示： &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/b0764dfddb0d388d7dd9fe8574f3244c.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="2.png" src="http://dockone.io/uploads/article/20201016/b0764dfddb0d388d7dd9fe8574f3244c.png" title="2.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图2 AIOps关联团队关系图&lt;/em&gt; &lt;br /&gt;
 &lt;h4&gt;演进路线&lt;/h4&gt;当前，我们在质量保障方面的诉求最迫切，服务运维部先从故障管理领域探索AIOps实践。在故障管理体系中，从故障开始到结束主要有四大核心能力，即故障发现、告警触达、故障定位、故障恢复。故障发现包含了指标预测、异常检测和故障预测等方面，主要目标是能及时、准确地发现故障；告警触达包含了告警事件的收敛、聚合和抑制，主要目标是降噪聚合，减少干扰；故障定位包含了数据收集、根因分析、关联分析、智能分析等，主要目标是能及时、精准地定位故障根因；故障恢复部分包含了流量切换、预案、降级等，主要目标是及时恢复故障，减少业务损失，具体关系如下图3所示： &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/85a3615664b9cf84fac91ecd179f1c64.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="3.png" src="http://dockone.io/uploads/article/20201016/85a3615664b9cf84fac91ecd179f1c64.png" title="3.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图3 故障管理体系核心能力关系图&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt;其中在故障管理智能化的过程中，故障发现作为故障管理中最开始的一环，在当前海量指标场景下，自动发现故障和自动异常检测的需求甚为迫切，能极大地简化研发策略配置成本，提高告警的准确率，减少告警风暴和误告，从而提高研发的效率。 &lt;br /&gt;
 &lt;br /&gt;除此之外，时序数据异常检测其实是基础能力，在后续告警触达、故障定位和故障恢复环节中，存在大量指标需要进行异常检测。所以将故障发现作为当前重点探索目标，解决当前海量数据场景下人工配置和运营告警策略、告警风暴和准确率不高的核心痛点。整个AIOps体系的探索和演进路线如下图4所示。每个环节均有独立的产品演进，故障发现-Horae（美团服务运维部与交易系统平台部共建项目）、告警触达-告警中心、故障定位-雷达、故障恢复-雷达预案。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/2b0c5dbba1c84259e2d9bc5b39c74081.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="4.png" src="http://dockone.io/uploads/article/20201016/2b0c5dbba1c84259e2d9bc5b39c74081.png" title="4.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图4 AIOps在故障管理方面的演进路线&lt;/em&gt; &lt;br /&gt;
 &lt;h3&gt;AIOps之故障发现&lt;/h3&gt; &lt;h4&gt;故障发现&lt;/h4&gt;从美团现有的监控体系可以发现，绝大多数监控数据均为时序数据（Time Series），时序数据的监控在公司故障发现过程中扮演着不可忽视的角色。无论是基础监控CAT[2]、MT-Falcon[3]、Metrics（App端监控），还是业务监控Digger（外卖业务监控）、Radar（故障发现与定位平台）等，均基于时序数据进行异常监控，来判断当前业务是否在正常运行。 &lt;br /&gt;
 &lt;br /&gt;然而从海量的时序数据指标中可以发现，指标种类繁多、关系复杂（如下图5所示）。在指标本身的特点上，有周期性、规律突刺、整体抬升和下降、低峰期等特点，在影响因素上，有节假日、临时活动、天气、疫情等因素。原有监控系统的固定阈值类监控策略想要覆盖上述种种场景，变得越来越困难，并且指标数量众多，在策略配置和优化运营上，人力成本将成倍增长。 &lt;br /&gt;
 &lt;br /&gt;若在海量指标监控上，能根据指标自动适配合适的策略，不需要人为参与，将极大的减少SRE和研发同学在策略配置和运营上的时间成本，也可让SRE和研发人员把更多精力用在业务研发上，从而产生更多的业务价值，更好地服务于业务和用户。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/6dc5c7ecfc8a1b2fa1951b1eee4c5d6d.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="5.png" src="http://dockone.io/uploads/article/20201016/6dc5c7ecfc8a1b2fa1951b1eee4c5d6d.png" title="5.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图5 时序数据种类多样性&lt;/em&gt; &lt;br /&gt;
 &lt;h4&gt;时序数据自动分类&lt;/h4&gt;在时序数据异常检测中，对于不同类型的时序数据，通常需要设置不同的告警规则。比如对于CPU Load曲线，往往波动剧烈，如果设置固定阈值，瞬时的高涨会经常产生误告，SRE和研发人员需要不断调整阈值和检测窗口来减少误告，当前，通过Radar（美团内部系统）监控系统提供的动态阈值策略，然后参考历史数据可以在一定程度上避免这一情况。如果系统能够提前预判该时序数据类型，给出合理的策略配置建议，就可以提升告警配置体验，甚至做到自动化配置。而且在异常检测中，时序数据分类通常也是智能化的第一步，只有实现智能化分类，才能自动适配相应的策略。 &lt;br /&gt;
 &lt;br /&gt;目前，时间序列分类主要有两种方法，无监督的聚类和基于监督学习的分类。Yading[4]是一种大规模的时序聚类方法，它采用PAA降维和基于密度聚类的方法实现快速聚类，有别于K-Means和K-Shape[5]采用互相关统计方法，它基于互相关的特性提出了一个新颖的计算簇心的方法，且在计算距离时尽量保留了时间序列的形状。对KPI进行聚类，也分为两种方法，一种是必须提前指定类别数目（如K-Means、K-Shape等）的方法，另一种是无需指定类别数目（如DBSCAN等），无需指定类别数目的聚类方法，类别划分的结果受模型参数和样本影响。至于监督学习的分类方法，经典的算法主要包括Logistics、SVM等。 &lt;br /&gt;
 &lt;br /&gt; &lt;strong&gt;分类器选择&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;根据当前监控系统中时序数据特点，以及业内的实践，我们将所有指标抽象成三种类别：周期型、平稳型和无规律波动型[6]。我们主要经历了三个阶段的探索，单分类器分类、多弱分类器集成决策分类和卷积神经网络分类。 &lt;br /&gt;
 &lt;ul&gt;  &lt;li&gt;单分类器分类：本文训练了SVM、DBSCAN、One-Class-SVM（S3VM）三种分类器，平均分类准确率达到80%左右，但无规律波动型指标的分类准确率只有50%左右，不满足使用要求。&lt;/li&gt;  &lt;li&gt;多弱分类器集成决策分类：参考集成学习相关原理，通过对SVM、DBSCAN、S3VM三种分类器集成投票，提高分类准确率，最终分类准确率提高7个百分点，达到87%。&lt;/li&gt;  &lt;li&gt;卷积神经网络分类：参考对Human Activity Recognition（HAR）进行分类的实践[7]，我们用CNN（卷积神经网络）实现了一个分类器，该分类器在时序数据分类上表现优秀，准确率能达到95%以上。CNN在训练中会逐层学习时序数据的特征，不需要成本昂贵的特征工程，大大减少了特征设计的工作量。&lt;/li&gt;&lt;/ul&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;strong&gt;分类流程&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;我们选择CNN分类器进行时序数据分类，分类过程如下图6所示，主要步骤如下： &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/36027636d979673b63f4e505e1fe9797.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="6.png" src="http://dockone.io/uploads/article/20201016/36027636d979673b63f4e505e1fe9797.png" title="6.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图6 时序数据分类处理流程&lt;/em&gt; &lt;br /&gt;
 &lt;ul&gt;  &lt;li&gt;缺失值填充：时序数据存在少量数据丢失或者部分时段无数据等现象，因此在分类前先对数据先进行缺失值填充。&lt;/li&gt;  &lt;li&gt;标准化：本文采用方差标准化对时序数据进行处理。&lt;/li&gt;  &lt;li&gt;降维处理：按分钟粒度的话，一天有1440个点，为了减少计算量，我们进行降维处理到144个点。PCA、PAA、SAX等一系列方法是常用的降维方法，此类方法在降低数据维度的同时还能最大程度地保持数据的特征。通过比较，PAA在降到同样的维度（144维）时，还能保留更多的时序数据细节，具体对比如下图7所示。&lt;/li&gt;  &lt;li&gt;模型训练：使用标注的样本数据，在CNN分类器中进行训练，最终输出分类模型。&lt;/li&gt;&lt;/ul&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/66603327272bafcd147b96173817fbae.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="7.png" src="http://dockone.io/uploads/article/20201016/66603327272bafcd147b96173817fbae.png" title="7.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图7 PAA、SAX降维方法对比&lt;/em&gt; &lt;br /&gt;
 &lt;h4&gt;周期型指标异常检测&lt;/h4&gt; &lt;strong&gt;异常检测方法&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;基于上述时序数据分类工作，本文能够相对准确地将时序数据分为周期型、平稳型和无规律波动型三类。在这三种类型中，周期型最为常见，占比30%以上，并且包含了大多数业务指标，业务请求量、订单数等核心指标均为周期型，所以本文优先选择周期型指标进行自动异常检测的探索。对于大量的时序数据，通过规则进行判断已经不能满足，需要通用的解决方案，能对所有周期型指标进行异常检测，而非一个指标一套完全独立的策略，机器学习方法是首选。 &lt;br /&gt;
 &lt;br /&gt;论文Opprentice[8]和腾讯开源的Metis[9]采用监督学习的方式进行异常检测，其做法如下：首先，进行样本标注得到样本数据集，然后进行特征提取得到特征数据集，使用特征数据集在指定的学习系统上进行训练，得到异常分类模型，最后把模型用于实时检测。监督学习整体思路[10]如下图8所示，其中(x1,y1),(x2,y2),…,(xn,yn)是训练数据集，学习系统由训练数据学习一个分类器P(Y∣X)或Y=f(X)，分类系统通过学习到的分类器对新的输入实例xn+1进行分类，预测其输出的类别yn+1。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/49f0d5ba8a0d60f1d5477b2066fff197.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="8.png" src="http://dockone.io/uploads/article/20201016/49f0d5ba8a0d60f1d5477b2066fff197.png" title="8.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图8 监督学习在分类问题中的应用&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;strong&gt;异常注入&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;一般而言，在样本数据集中，正负样本比例如果极度不均衡（比如1:5，或者更悬殊），那么分类器分类时就会倾向于高比例的那一类样本（假如负样本占较大比例，则会表现为负样本Recall过高，正样本Recall低，而整体的Accuracy依然会有比较好的表现），在一个极度不均衡的样本集中，由于机器学习会对每个数据进行学习，那么多数数据样本带有的信息量就比少数样本信息量大，会对分类器学习过程中造成干扰，导致分类不准确。 &lt;br /&gt;
 &lt;br /&gt;在实际生产环境中，时序数据异常点是非常少见的，99%以上的数据都是正常的。如果使用真实生产环境的数据进行样本标注，将会导致正负样本比例严重失衡，导致精召率无法满足要求。为了解决基于监督学习的异常检测异常点过少的问题，本文设计一种针对周期型指标的自动异常注入算法，保证异常注入足够随机且包含各种异常场景。 &lt;br /&gt;
 &lt;br /&gt;时序数据的异常分为两种基本类型，异常上涨和异常下跌，如下图9（图中数据使用Curve[11]标注），通常异常会持续一段时间，然后逐步恢复，恢复过程或快或慢，影响异常两侧的值，称之为涟漪效应（Ripple Effect），类似石头落入水中，波纹扩散的情形。受到该场景的启发，异常注入思路及步骤如下： &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/62ccd90bb399185bc2436a88ca249f4d.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="9.png" src="http://dockone.io/uploads/article/20201016/62ccd90bb399185bc2436a88ca249f4d.png" title="9.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图9 异常case中异常数据分布&lt;/em&gt; &lt;br /&gt;
 &lt;ol&gt;  &lt;li&gt;给定一段时序值S，确定注入的异常个数N，将时序数据划分为N块。&lt;/li&gt;  &lt;li&gt;在其中的一个区域X中，随机选定一个点Xi作为异常种子点。&lt;/li&gt;  &lt;li&gt;设定异常点数目范围，基于此范围产生随机出异常点数n，异常点随机分布在异常种子两侧，左侧和右侧的数目随机产生。&lt;/li&gt;  &lt;li&gt;对于具体的异常点，根据其所在位置，选择该点邻域范围数据作为参考数据集m，需要邻域在设定的范围内随机产生。&lt;/li&gt;  &lt;li&gt;产生一个随机数，若为奇数，则为上涨，否则下跌。基于参考数据集m，根据3Sigma原理，生成超出±3σ的数据作为异常值。&lt;/li&gt;  &lt;li&gt;设定一个影响范围，在设定范围内随机产生影响的范围大小，左右两侧的影响范围也随机分配，同时随机产生异常衰减的方式，包括简单移动平均、加权移动平均、指数加权移动平均三种方式。&lt;/li&gt;  &lt;li&gt;上述过程只涉及突增突降场景，而对于同时存在升降的场景，通过分别生成上涨和下跌的上述两个异常，然后叠加在一起即可。&lt;/li&gt;&lt;/ol&gt; &lt;br /&gt;
 &lt;br /&gt;通过上面的异常注入步骤，能比较好地模拟出周期型指标在生产环境中的各种异常场景，上述过程中各个步骤的数据都是随机产生，所以产生的异常案例各不相同，从而能为我们生产出足够多的异常样本。为了保证样本集的高准确性，我们对于注入异常后的指标数据还会进行标注，以去除部分注入的非异常数据。具体异常数据生成效果如图10所示，其中蓝色线为原始数据，红色线为注入的异常，可以看出注入异常与线上环境发生故障时相似，注入的异常随机性较大。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/04259ed0e96fde0d66069bfe7a793ba8.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="10.png" src="http://dockone.io/uploads/article/20201016/04259ed0e96fde0d66069bfe7a793ba8.png" title="10.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图10 异常注入效果图&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;strong&gt;特征工程&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;针对周期型指标，经标注产生样本数据集后，需要设计特征提取器进行特征提取，Opprentice中设计的几种特征提取器如图11所示： &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/25af5e965abfb4c72faf123c1513643a.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="11.png" src="http://dockone.io/uploads/article/20201016/25af5e965abfb4c72faf123c1513643a.png" title="11.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图11 论文Opprentice特征提取器&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt;上述特征主要是一些简单的检测器，包括如固定阈值、差分、移动平均、SVD分解等。Metis将其分为三种特征，一是统计特征，包括方差、均值、偏度等统计学特征；二是拟合特征，包括如移动平均、指数加权移动平均等特征；三是分类特征，包含一些自相关性、互相关性等特征。参考上述提及的特征提取方法，本文设计了一套特征工程，区别于上述特征提取方法，本文对提取的结果用孤立森林进行了一层特征抽象，使得模型的泛化能力更强，所选择的特征及说明如下图12所示： &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/c7be6585df58d1bc54e71c93e3e38629.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="12.png" src="http://dockone.io/uploads/article/20201016/c7be6585df58d1bc54e71c93e3e38629.png" title="12.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图12 特征选择及说明&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;strong&gt;模型训练及实时检测&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;参考监督学习在分类问题中的应用思路，对周期型指标自动异常检测方案具体设计如图下13所示，主要分为离线模型训练和实时检测两大部分，模型训练主要根据样本数据集训练生成分类模型，实时检测利用分类模型进行实时异常检测。具体过程说明如下： &lt;br /&gt;
 &lt;ol&gt;  &lt;li&gt;离线模型训练：基于标注的样本数据集，使用设计的特征提取器进行特征提取，生成特征数据集，通过Xgboost进行训练，得到分类模型，并存储。&lt;/li&gt;  &lt;li&gt;实时检测：线上实时检测时，时序数据先经过预检测（降低进入特征提取环节概率，减少计算压力），然后根据设计的特征工程进行特征提取，再加载离线训练好的模型，进行异常分类。&lt;/li&gt;  &lt;li&gt;数据反馈：如果判定为异常，将发出告警。进一步地，用户可根据实际情况对告警进行反馈，反馈结果将加入样本数据集中，用于定时更新检测模型。&lt;/li&gt;&lt;/ol&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/e1df76fddee8ea1e6198119a872651ed.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="13.png" src="http://dockone.io/uploads/article/20201016/e1df76fddee8ea1e6198119a872651ed.png" title="13.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图13 模型检测和实时检测流说明&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;strong&gt;特殊场景优化&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;通过上述实践，本文得到一套可完整运行的周期型指标异常检测系统，在该系统应用到生产环境的过程中，也遇到不少问题，比如低峰期（小数值）波动幅度较大，节假日和周末趋势和工作日趋势完全不同，数据存在整体大幅抬升或下降，部分规律波动时间轴上存在偏移，这些情况都有可能产生误告。本文也针对这些场景，分别提出对应的优化策略，从而减少周期型指标在这些场景下的误告，提高异常检测的精召率。 &lt;br /&gt;
 &lt;br /&gt;1）低峰期场景：低峰期主要表现是小数值高波动，低峰期的波动比较普遍，但是常规检测时，只获取当前点前后7min的邻域内的数据，可能无法获取到本身已经出现过多次的较大波动，导致误判为异常。所以对于低峰期，需要扩大比较窗口，容纳到更多的正常的较大波动场景，从而减少被误判。如下图14所示，红色是当日数据，灰色是上周同日数据，如果判断窗口为w1，w1内蓝色点有可能被认为是异常点，而时间窗口范围扩大到w2后，大幅波动的蓝色点和绿色点都会被捕获到，出现类似大幅波动时不再被判定为异常，至于低峰期范围可以通过历史数据计算进行识别。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/4b03fab08ef8b660ae6f39741f71f5f0.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="14.png" src="http://dockone.io/uploads/article/20201016/4b03fab08ef8b660ae6f39741f71f5f0.png" title="14.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图14 低峰期时不同时段的相似大幅波动&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt;2）节假日场景：节假日前一天以及节假日之后一周的数据，和正常周期的趋势都会有较大差别，可能会出现误告。本文通过提前配置需要进行节假日检测的日期，在设置的日期范围内，除了进行正常的检测流程，对于已经检测出异常的数据点，会再进入到节假日检测流程，都异常才会触发告警。节假日检测会取最近1h的数据，分别计算其波动比、周同比、日环比等数据，当前时间的这些指标通过“孤立森林”判断都为异常，才会认为数据是真正异常。除此之外，对于节假日，模型的敏感度会适当调低以适应节假日场景。 &lt;br /&gt;
 &lt;br /&gt;3）整体抬升/下降场景：场景特点如下图15所示，在该场景下，会设置一个抬升/下跌率，比如80%，如果今天最近1h数据80%相对昨日和上周都上涨，则认为是整体抬升，都下跌则认为是整体下降。如果出现整体抬升情况，会降低模型敏感度，并且要求当前日环比、周同比在1h数据中均为异常点，才会判定当前的数据异常。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/be8ac5a5b5e16b4ddbd3bc530b56d837.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="15.png" src="http://dockone.io/uploads/article/20201016/be8ac5a5b5e16b4ddbd3bc530b56d837.png" title="15.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图15 整体抬升下降场景&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt;4）规律波动偏移场景：部分指标存在周期性波动，但是时间上会有所偏移，如图16所示案例中时序数据由于波动时间偏移导致误告。本文设计一种相似序列识别算法，在历史数据中找出波动相似的序列，如果存在足够多的相似波动序列，则认为该波动为正常波动。相似序列提取过程如下：最近n分钟的时序作为基础序列x，获取检测时刻历史14天邻域内的数据（如前后30min），在邻域数据中指定滑动窗口（如3min）滑动，把邻域数据分为多个长度为n的序列集Y，计算基础序列x与Y中每个序列的DTW距离，通过“孤立森林”对距离序列进行异常判断，对于被判定为异常值的DTW距离，它所对应的序列将被视为相似序列。如果相似序列个数超出设定阈值，则认为当前波动为规律偏移波动，属于正常现象。根据上述方法，提取到对应的相似序列如图16右边所示，其中红实线为基础序列。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/1d00578af40d62294e3ae90501bbcd0e.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="16.png" src="http://dockone.io/uploads/article/20201016/1d00578af40d62294e3ae90501bbcd0e.png" title="16.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图16 规律波动偏移相似序列提取&lt;/em&gt; &lt;br /&gt;
 &lt;h4&gt;异常检测能力平台化&lt;/h4&gt;为了把上述时序数据异常检测探索的结果进行落地，服务运维部与交易系统平台部设计和开发了时序数据异常检测系统Horae。Horae致力于时间序列异常检测流程的编排与调优，处理对象是时序数据，输出是检测流程和检测结果，核心算法是异常检测算法、时间序列预测算法以及针对时间序列的特征提取算法。除此之外，Horae还会针对特殊的场景开发异常检测算法。Horae核心能力是可根据提供的算法，编排不同的检测流程，对指标进行自动分类，并针对指标所属类型自动选择合适的检测流程，进行流程调优得到该指标下的最优参数，从而确保能适配指标并得到更高的精召率，为各个对时序数据异常检测有需求的团队提供高准确率的异常检测服务。 &lt;br /&gt;
 &lt;br /&gt; &lt;strong&gt;Horae系统架构设计&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;Horae系统由四个模块组成：数据接入、实时检测、实验模块和算法模块。用户通过数据接入模块注册需要监听时序数据的消息队列，Horae系统将监听注册的Topic采集时序数据，并根据粒度（例如分钟、小时或天）更新每个时间序列，每个时序点都存储到时序数据库中，实时检测模块对每个时序点执行异常检测，当检测到异常时，通过消息队列将异常信息传输给用户。下图17详细展示了Horae系统的整体架构图。 &lt;br /&gt;
 &lt;ul&gt;  &lt;li&gt;数据接入：用户可以通过创建数据源用于数据上报，数据源可以包含一个或多个指标，指标更新频率最小为一分钟。不同数据源中指标的时序数据相互隔离，时序数据更新到使用Elasticsearch改造后的时序数据库中。&lt;/li&gt;  &lt;li&gt;实时检测：采集到实时的时序数据后，会根据指标绑定的执行流程立即进行异常检测，如果没有训练调优，会先执行训练调优以保证更佳的精召率。实时检测的结果会通过消息队列通知到用户，用户根据异常检测的结果进行进一步处理判断是否需要发出告警。&lt;/li&gt;  &lt;li&gt;实验模块：该模块主要功能是样本管理、算法注册、流程编排、模型训练和评估、模型发布。该模块提供样本管理功能，可对样本进行标注和存储；对于已经实现的算法，可以注册到系统中，供流程编排使用；通过算法编排得到的流程，可以用在模型训练或者异常检测中；训练流程会使用到标注好的样本数据调用算法离线服务进行离线训练并存储模型；对于已经编排好的检测流程，可以对指标进行模拟观察检测异常检测效果，或者离线回归判断检测流程在该指标上的具体精召率数据。&lt;/li&gt;  &lt;li&gt;算法模块：算法模块提供了所有在实验模块注册的异常检测算法的具体实现，算法模块既可以执行单个算法，也可以接受多个算法编排的流程进行执行。当前支持的算法大类主要有预处理算法（异常值去除、空值填充、降维、归一化等），时序特征算法（统计类特征、拟合特征、分类特征等），机器学习类算法（RF、SVM、XGBoost、GRU、LSTM、CNN、聚类算法等），检测类算法（孤立森林、LOF、SVM、3Sigma、四分位、IQR等），预测类算法（Ewma、Linear Weighted MA、Holt-Winters、STL、SAIMAX、Prophet等），自定义算法（形变分析、同环比、波动比等）。&lt;/li&gt;&lt;/ul&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/2bdcdcabfa834a42150b0bb9ae2a05a9.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="17.png" src="http://dockone.io/uploads/article/20201016/2bdcdcabfa834a42150b0bb9ae2a05a9.png" title="17.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图17 Horae时序数据异常检测系统架构图&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;strong&gt;算法注册和模型编排&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;算法模型是对算法的抽象，通过唯一字符串标识算法模型，注册算法时需要指定算法的类型、接口、参数、返回值和处理单个时序点所需要加载的时序数据配置。成功注册的算法模型根据算法类型的不同，会生成用于模型编排的算法组件或对异常检测模型进行训练的组件。用于模型编排的算法组件主要包括：预处理算法、时序特征算法、评估算法、预测算法、分类算法、异常检测算法等，用于模型训练的算法分为两大类：参数调优和机器学习模型训练。 &lt;br /&gt;
 &lt;br /&gt;注册后的算法模型通常不会直接用于异常检测，会对算法模型进行编排后得到一个流程模型，流程模型可以用于执行异常检测或者执行训练。实验模块支持两种类型的流程模型：执行流程和训练流程。执行流程是一个异常检测流程，指定指标和检测时间段，得到检测时间段每个时序点的异常分值；训练流程是一个执行训练的流程模型，主要包括参数调优训练流程和机器学习模型训练流程。使用算法进行流程编排如下图18所示，左侧菜单为算法组件，中间区域可对算法执行流程进行编排调整，右侧区域是具体算法的参数设置。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/ec348fe2f011bcbcbfe44c61a3b222aa.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="18.png" src="http://dockone.io/uploads/article/20201016/ec348fe2f011bcbcbfe44c61a3b222aa.png" title="18.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图18 流程编排示意图&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;strong&gt;离线训练和实时检测&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;在模型编排阶段，可编排执行流程和训练流程，执行流程主要用在指标实时异常检测过程，而训练流程主要用在离线模型训练和参数调优。执行流程由流程配置和异常分值配置构成，由实验模块的流程调度引擎负责执行调度，下图19展示了执行流程的详细构成。流程调度引擎在对执行流程调度执行之前，会从流程的最深叶子节点的算法组件开始递归计算需要加载的时序数据集，根据流程中算法组件的参数配置，加载前置训练流程的训练结果，最后对流程中的算法组件依次调度执行，得到检测时间段每个时序点的异常分值。最终实现后的执行流程编排如图18所示。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/37c421c4917a8897401db9841508fc48.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="19.png" src="http://dockone.io/uploads/article/20201016/37c421c4917a8897401db9841508fc48.png" title="19.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图19 执行流程组成和处理过程&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt;训练流程由流程配置、训练算法、样本加载配置和训练频次等信息构成，由实验模块的流程调度引擎负责调度执行，下图20展示了训练流程的详细构成。训练流程主要分为两大类，参数调优训练和机器学习模型训练。参数调优训练是指为需要调优的参数设置参数值迭代范围或者枚举值，通过贝叶斯调优算法对参数进行调优，得到最优参数组合；机器学习模型训练则通过设计好特征工程，设置分类器和超参数范围后调优得到机器学习模型文件。训练流程执行训练的样本集来源于人工标注的样本或者基于自动样本构造功能生成的样本。训练流程编排具体过程和执行流程类似，不同的是训练流程可设置定时任务执行，训练的结果会存储供后续使用。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/41c8e57009449ce1fafb42cdd56db4e9.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="20.png" src="http://dockone.io/uploads/article/20201016/41c8e57009449ce1fafb42cdd56db4e9.png" title="20.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图20 训练流程组成和处理过程&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt;异常检测模型中会包含很多凭借经验设定的超参数，不同的指标可能需要设置不同的参数值，保证更高的精召率。而指标数据会随着时间发生变化，设置参数需要定期的训练和更新，在实验模块中可以为训练流程设置定时任务，实验模块会定时调度训练流程生成离线训练任务，训练任务执行完成可以看到训练结果和效果。下图21示例展示了一个参数调优训练流程的示例。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/718a837aa1552400e9ef577bf24a84d8.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="21.png" src="http://dockone.io/uploads/article/20201016/718a837aa1552400e9ef577bf24a84d8.png" title="21.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图21 参数调优训练结果示例&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt; &lt;strong&gt;模型案例和结果评估&lt;/strong&gt; &lt;br /&gt;
 &lt;br /&gt;根据在周期型指标上探索的结果，在Horae上编排分类模型训练流程，训练和测试所使用的样本数是28000个，其中用于训练的比例是75%，用于验证的比例是25%，具体分类模型训练结果如下图22所示，在测试集上的准确率94%，召回率89%。同时编排了与之对应的执行流程，它的检测流程除了异常分类，还主要包含了空值填充、预检测、特征提取、分类判断、低峰期判断、偏移波动判断等逻辑，该执行流程适用范围是周期型和稳定型指标。除此之外，还提供了流程调优能力，检测流程中的每个算法可以暴露其超参数，对于具体的指标，通过该指标的样本数据可以训练得到该流程下的一组较优超参数，从而提高该指标的异常检测的精召率。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/4c5b6a184b5b500f205bfe15a0379c84.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="22.png" src="http://dockone.io/uploads/article/20201016/4c5b6a184b5b500f205bfe15a0379c84.png" title="22.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图22 异常分类模型训练结果&lt;/em&gt; &lt;br /&gt;
 &lt;br /&gt;该异常检测流程应用到生产环境的指标后，具体检测效果相关案例如下图23所示，对于周期型指标，能及时准确地发现异常，对异常点进行反馈，准确率达到90%以上。除此之外，还对比了形变分析异常检测，对于生产环境中遇到的三个形变分析无法发现的4个案例，周期型指标异常检测流程能发现其中3个，表现优于形变分析。 &lt;br /&gt;
 &lt;div&gt;
  &lt;a href="http://dockone.io/uploads/article/20201016/b5b916181764a0a55afcd83497ed9b4e.png" rel="lightbox" target="_blank"&gt;   &lt;img alt="23.png" src="http://dockone.io/uploads/article/20201016/b5b916181764a0a55afcd83497ed9b4e.png" title="23.png"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;
 &lt;br /&gt;
 &lt;em&gt;图23 周期型指标异常检测模型生产环境检测结果&lt;/em&gt; &lt;br /&gt;
 &lt;h3&gt;总结与展望&lt;/h3&gt;时序数据异常检测作为AIOps中故障发现环节的核心，当前经过探索和实践，已经在周期型指标异常检测上取得了一定的成绩，并落地到Horae时序异常检测系统中。在时序数据异常检测部分，后续会陆续实现平稳型、无规律波动型指标自动异常检测，增加指标数据预测相关能力，提高检测性能，从而实现所有类型的海量指标自动异常检测的目的。 &lt;br /&gt;
 &lt;br /&gt;除此之外，在告警触达方面，我们当前在进行告警收敛、降噪和抑制相关的规则和算法的探索，致力于提供精简有效的信息，减少告警风暴及干扰；在故障定位方面，我们已经基于规则在定位上取得比较不错的效果，后续还会进行更全面的定位场景覆盖和关联性分析、根因分析、知识图谱相关的探索，通过算法和规则提升故障定位的精召率。因篇幅所限，告警触达（告警中心）和故障定位（雷达）两部分内容将会在后续的文章中详细进行分享，敬请期待。 &lt;br /&gt;
 &lt;h3&gt;参考资料&lt;/h3&gt;[1] 周志华. 机器学习: 发展与未来[R]. 报告地: 深圳, 2016. &lt;br /&gt;
[2] 美团实时监控系统CAT[EB/OL].  &lt;a href="https://tech.meituan.com/CAT_in_Depth_Java_Application_Monitoring.html" rel="nofollow" target="_blank"&gt;https://tech.meituan.com/CAT_i ... .html&lt;/a&gt;, 2018-11-01. &lt;br /&gt;
[3] 美团系统指标监控Mt-Falcon[EB/OL].  &lt;a href="https://tech.meituan.com/Mt-Falcon_Monitoring_System.html" rel="nofollow" target="_blank"&gt;https://tech.meituan.com/Mt-Fa ... .html&lt;/a&gt;, 2017-02-24. &lt;br /&gt;
[4] Ding R, Wang Q, Dang Y, et al. Yading: fast clustering of large-scale time series data[J]. Proceedings of the VLDB Endowment, 2015, 8(5): 473-484. &lt;br /&gt;
[5] Paparrizos J, Gravano L. k-shape: Efficient and accurate clustering of time series[C]. Proceedings of the 2015 ACM SIGMOD International Conference on Management of Data. ACM, 2015: 1855-1870. &lt;br /&gt;
[6]  H. Ren, Q. Zhang, B. Xu, Y. Wang, C. Yi, C. Huang, X. Kou, T. Xing, M. Yang, and J. Tong, “Time-series anomaly detection serviceat microsoft,” in Proceedings of the ACM SIGKDD International Conference on Knowledge Discovery and Data Mining, pp. 3009–3017, ACM, Jun. 2019. &lt;br /&gt;
[7] Tom Brander. Time series classification with Tensorflow[EB/OL].  &lt;a href="https://burakhimmetoglu.com/2017/08/22/time-series-classification-with-tensorflow" rel="nofollow" target="_blank"&gt;https://burakhimmetoglu.com/20 ... rflow&lt;/a&gt;, 2017-08-22. &lt;br /&gt;
[8] Liu D, Zhao Y, Xu H, et al. Opprentice: Towards practical and automatic anomaly detection through machine learning[C]//Proceedings of the 2015 Internet Measurement Conference. ACM, 2015: 211-224. &lt;br /&gt;
[9] Metis is a learnware platform in the field of AIOps[EB/OL].  &lt;a href="https://github.com/Tencent/Metis" rel="nofollow" target="_blank"&gt;https://github.com/Tencent/Metis&lt;/a&gt;, 2018-10-12. &lt;br /&gt;
[10] 李航. 统计学习方法 [M]. 第2版. 北京: 清华大学出版社, 2019.28-29. &lt;br /&gt;
[11] An tool to help label anomalies on time-series data[EB/OL].  &lt;a href="https://github.com/baidu/Curve" rel="nofollow" target="_blank"&gt;https://github.com/baidu/Curve&lt;/a&gt;, 2018-08-07. &lt;br /&gt;
六、作者简介 &lt;br /&gt;
 &lt;br /&gt;胡原、锦冬、俊峰，来自基础技术部-服务运维部；长伟、永强，来自到家事业群-交易系统平台部。 &lt;br /&gt;
 &lt;br /&gt;原文链接： &lt;a href="https://mp.weixin.qq.com/s/AjE7uP7ApVPyL_HdQDkk5g" rel="nofollow" target="_blank"&gt;https://mp.weixin.qq.com/s/AjE7uP7ApVPyL_HdQDkk5g&lt;/a&gt;
                                                                 &lt;div&gt;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                &lt;/div&gt;
                                
                                                                 &lt;ul&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 />
      <guid isPermaLink="true">https://itindex.net/detail/60941-aiops-%E7%BE%8E%E5%9B%A2-%E5%AE%9E%E8%B7%B5</guid>
      <pubDate>Fri, 16 Oct 2020 17:37:53 CST</pubDate>
    </item>
    <item>
      <title>想要搭建个论坛？Guide哥调研了100来个 Java 开源论坛系统，发现这 5 个最好用！</title>
      <link>https://itindex.net/detail/60889-%E8%AE%BA%E5%9D%9B-guide-java</link>
      <description>&lt;div&gt;  &lt;p&gt;   &lt;a href="https://www.yuque.com/docs/share/71251673-1fef-416e-93d7-489a25a9eda5?#%20%E3%80%8A%E8%B5%B0%E8%BF%91JavaGuide%E3%80%8B" rel="nofollow noopener noreferrer" target="_blank"&gt;大家好！我是 Guide 哥，Java 后端开发。一个会一点前端，喜欢烹饪的自由少年。&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;最近有点小忙。但是，由于前几天答应了一位读者自己会推荐一些开源的论坛系统，所以，昨晚就简单地熬了个夜，对比了很多个开源论坛系统之后，总结成了这篇文章。&lt;/p&gt;
  &lt;p&gt;这篇文章我一共推荐了 5 个论坛类开源项目，除了有 1 个是基于 PHP 开发之外，其他都是基于 Java ,并且大部分都是基于 Spring Boot 这个主流框架来做的。&lt;/p&gt;
  &lt;p&gt;欢迎小伙伴们在评论区补充啊！ღ( ´･ᴗ･` )比心&lt;/p&gt;
  &lt;h2&gt;1. NiterForum&lt;/h2&gt;
  &lt;ul&gt;
   &lt;li&gt;Github 地址：    &lt;a href="https://github.com/yourkevin/NiterForum" rel="nofollow noopener noreferrer" target="_blank" title="https://github.com/yourkevin/NiterForum"&gt;github.com/yourkevin/N…&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;官网地址：    &lt;a href="https://niter.cn/forum" rel="nofollow noopener noreferrer" target="_blank"&gt;niter.cn/forum&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;Star : 0.5k&lt;/li&gt;
   &lt;li&gt;简介：尼特社区-NiterForum-一个论坛程序，几乎具有一个论坛/社区所应该有的全部功能-后端 Springboot/MyBatis/Maven/MySQL-前端 Thymeleaf/Layui-可供初学者，学习、交流使用。&lt;/li&gt;
   &lt;li&gt;技术栈： 后端 Springboot + MyBatis + Maven + MySQL 前端 Thymeleaf + Layui&lt;/li&gt;
   &lt;li&gt;推荐等级 ：⭐⭐⭐⭐⭐&lt;/li&gt;
   &lt;li&gt;评价：可以说 NiterForum 提供了一个论坛所能提供的所有功能，功能特性覆盖的非常全面。但这并不是这次推荐他的主要原因。作为本次论坛项目中第一个推荐的项目，NiterForum 的 NB 之处就是：他提供 NiterApp，完美适配了 NiterForum，支持 app 端扫码登录！&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bd07024e31a54057949df1c45e8eb0ce~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;2. Symphony&lt;/h2&gt;
  &lt;ul&gt;
   &lt;li&gt;Github 地址：    &lt;a href="https://github.com/88250/symphony" rel="nofollow noopener noreferrer" target="_blank" title="https://github.com/88250/symphony"&gt;github.com/88250/symph…&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;官网地址：    &lt;a href="https://ld246.com/" rel="nofollow noopener noreferrer" target="_blank" title="https://ld246.com/"&gt;ld246.com/&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;Star : 0.7k&lt;/li&gt;
   &lt;li&gt;简介： 一款用 Java 实现的现代化社区（论坛/问答/BBS/社交网络/博客）系统平台。&lt;/li&gt;
   &lt;li&gt;技术栈： Latke （作者自研的以 JSON 为主的 Java Web 框架）+    &lt;a href="https://github.com/jhy/jsoup" rel="nofollow noopener noreferrer" target="_blank" title="jsoup"&gt;jsoup&lt;/a&gt; +     &lt;a href="https://github.com/oblac/jodd" rel="nofollow noopener noreferrer" target="_blank" title="Jodd"&gt;Jodd&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;推荐等级 ：⭐⭐⭐⭐&lt;/li&gt;
   &lt;li&gt;评价：讲真，Symphony 是笔者目前见过的论坛项目中功能最齐全的一款（没有之一），满足多维需求：面向内容、面向知识问答、面向用户分享、交友、游戏等。而且 Symphony 风格时尚，充满创新、好玩的特性。交互体验一级棒。这个项目的缺点也很明显，那就是项目使用的技术栈不是主流，比较小众（    &lt;em&gt;不过，作者自研 Java Web 框架的精神还是非常值得赞赏的！&lt;/em&gt;）。&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img alt="sym" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/64ad51e1ca084d948969a84a031b3933~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;3. 码问社区&lt;/h2&gt;
  &lt;ul&gt;
   &lt;li&gt;Github 地址：    &lt;a href="https://github.com/codedrinker/community" rel="nofollow noopener noreferrer" target="_blank" title="https://github.com/codedrinker/community"&gt;github.com/codedrinker…&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;官网地址：    &lt;a href="http://www.mawen.co/?sort=hot" rel="nofollow noopener noreferrer" target="_blank" title="http://www.mawen.co/?sort=hot"&gt;www.mawen.co/?sort=hot&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;Star : 1.1k&lt;/li&gt;
   &lt;li&gt;简介：开源论坛、问答系统，现有功能提问、回复、通知、最新、最热、消除零回复功能。&lt;/li&gt;
   &lt;li&gt;技术栈：SpringBoot + MyBatis+MySQL/H2+Flyway&lt;/li&gt;
   &lt;li&gt;推荐等级 ：⭐⭐⭐⭐⭐&lt;/li&gt;
   &lt;li&gt;评价：码问社区的作者是阿里巴巴的一位大佬，开源了很多有意思的项目，码问社区就是其中一款，采用 SpringBoot + Vue 等主流技术栈打造，并配有整个开发过程的    &lt;a href="https://www.bilibili.com/video/BV1r4411r7au" rel="nofollow noopener noreferrer" target="_blank" title="&amp;#35270;&amp;#39057;&amp;#35762;&amp;#35299;"&gt;视频讲解&lt;/a&gt;。    &lt;strong&gt;实战项目首推。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7f11173003fe42919352f09b4c86739c~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;4. MDclub&lt;/h2&gt;
  &lt;ul&gt;
   &lt;li&gt;Github 地址：    &lt;a href="https://juejin.im/post/undefined" title="https://github.com/zdhxiong/mdclub"&gt;github.com/zdhxiong/md…&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;官网地址：    &lt;a href="https://community.mdclub.org/" rel="nofollow noopener noreferrer" target="_blank" title="https://community.mdclub.org/"&gt;community.mdclub.org/&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;Star : 0.5k&lt;/li&gt;
   &lt;li&gt;简介：MDClub 漂亮、轻量且好用，它能让在线讨论变得更加轻松愉悦&lt;/li&gt;
   &lt;li&gt;技术栈：PHP+MySQL&lt;/li&gt;
   &lt;li&gt;推荐等级 ：⭐⭐⭐⭐&lt;/li&gt;
   &lt;li&gt;评价 ：MDclub 是一款简约风格的论坛项目。漂亮、轻量且容易上手。代码实现基于 MDUI 框架，分层分明。网站适配多种终端，从手机、ipad 到大屏显示器，均能自动适配，并且提供根据操作系统的主题，自动切换亮色主题和暗色主题。这个特性真的超赞的~&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img alt="mdclub.png" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/52a33f2f35d14764a480449da15a5707~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;5. 朋也社区&lt;/h2&gt;
  &lt;ul&gt;
   &lt;li&gt;Github 地址：    &lt;a href="https://github.com/tomoya92/pybbs" rel="nofollow noopener noreferrer" target="_blank" title="https://github.com/tomoya92/pybbs"&gt;github.com/tomoya92/py…&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;官网地址：    &lt;a href="https://tomoya92.github.io/pybbs/" rel="nofollow noopener noreferrer" target="_blank" title="https://tomoya92.github.io/pybbs/"&gt;tomoya92.github.io/pybbs/&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;Star : 1.1 k&lt;/li&gt;
   &lt;li&gt;简介：更实用的 Java 开发的社区(论坛)&lt;/li&gt;
   &lt;li&gt;技术栈：Spring-Boot + Mybatis-Plus + MySQL&lt;/li&gt;
   &lt;li&gt;推荐等级 ：⭐⭐⭐⭐&lt;/li&gt;
   &lt;li&gt;评价：朋也社区基于 Java 语言，采用主流的 Java Web 开发框架（SpringBoot）进行开发。个人觉得朋也社区最大的亮点是在设计层面上支持高度的可定制化。要实现这点很不容易，需要有很强的设计能力，并且朋也社区在实现过程对于各种集成的服务支持配置化（可随意开启或关闭）。&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/62b553ea15f64e68b44ef2f07a9568c6~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ae5cccd07439443288e1ce536682a885~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="https://www.yuque.com/docs/share/71251673-1fef-416e-93d7-489a25a9eda5?#%20%E3%80%8A%E8%B5%B0%E8%BF%91JavaGuide%E3%80%8B" rel="nofollow noopener noreferrer" target="_blank"&gt;我是 Guide 哥，一 Java 后端开发，会一点前端，自由的少年。我们下期再见！微信搜“    &lt;strong&gt;JavaGuide&lt;/strong&gt;”回复“    &lt;strong&gt;面试突击&lt;/strong&gt;”领取我整理的 4 本原创PDF&lt;/a&gt;&lt;/p&gt;&lt;/div&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 />
      <guid isPermaLink="true">https://itindex.net/detail/60889-%E8%AE%BA%E5%9D%9B-guide-java</guid>
      <pubDate>Wed, 23 Sep 2020 12:38:43 CST</pubDate>
    </item>
    <item>
      <title>Java程序员博客系统推荐！我调研了100来个 Java 开源博客系统，发现这 5 个最好用！</title>
      <link>https://itindex.net/detail/60873-java-%E7%A8%8B%E5%BA%8F%E5%91%98-%E5%8D%9A%E5%AE%A2</link>
      <description>&lt;div&gt;  &lt;p&gt;最近想倒腾一下博客，看了很多现成的比较成熟的开源博客系统，自己也简单从下面几个维度总结对比了一下：&lt;/p&gt;
  &lt;ol&gt;
   &lt;li&gt;star数量&lt;/li&gt;
   &lt;li&gt;技术选型&lt;/li&gt;
   &lt;li&gt;社区生态&lt;/li&gt;
&lt;/ol&gt;
  &lt;p&gt;当然啦！好东西不能独享。下面简单分享一下我所做的笔记。&lt;/p&gt;
  &lt;p&gt;   &lt;em&gt;欢迎小伙伴们评论区补充完善。ღ( ´･ᴗ･` )比心&lt;/em&gt;&lt;/p&gt;
  &lt;h2&gt;halo&lt;/h2&gt;
  &lt;ul&gt;
   &lt;li&gt;Github地址 ：    &lt;a href="https://github.com/halo-dev/halo" rel="nofollow noopener noreferrer" target="_blank"&gt;github.com/halo-dev/ha…&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;Star : 16.2k&lt;/li&gt;
   &lt;li&gt;简介 ：✍ 一个优秀的开源博客发布应用。&lt;/li&gt;
   &lt;li&gt;技术 ：Spring Boot+JPA+Hutool&lt;/li&gt;
   &lt;li&gt;推荐等级 ：⭐⭐⭐⭐⭐&lt;/li&gt;
   &lt;li&gt;评价 ：这款博客生态非常好（可选主题也非常多），使用的人也非常多。并且！！    &lt;strong&gt;还提供了小程序端！&lt;/strong&gt; 另外，搭建步骤也非常简单，基本是傻瓜式的。&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;   &lt;strong&gt;Halo 首页：&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img alt="Halo&amp;#39318;&amp;#39029;-halo.run" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4bbafd5090964a87aff62f9690ace07a~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;strong&gt;Halo 主题仓库 ：&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img alt="&amp;#20027;&amp;#39064;&amp;#20179;&amp;#24211;- Halo-halo.run" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3f2d17368d254c1391655877cfba8241~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;strong&gt;Halo 博客效果：&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img alt=" halo-&amp;#23506;&amp;#23665;&amp;#24535;-baozi.fun" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e197bbf8ed304f7c82a80e30ebd79637~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;OneBlog&lt;/h2&gt;
  &lt;ul&gt;
   &lt;li&gt;Github地址：    &lt;a href="https://gitee.com/yadong.zhang/DBlog" rel="nofollow noopener noreferrer" target="_blank"&gt;gitee.com/yadong.zhan…&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;Star : 2.3k&lt;/li&gt;
   &lt;li&gt;简介 ：一个简洁美观、功能强大并且自适应的Java博客。使用Spring Boot开发，前端使用Bootstrap。支持移动端自适应，配有完备的前台和后台管理功能。&lt;/li&gt;
   &lt;li&gt;技术 : Springboot + Shiro + MySQL + Mybatis + Redis&lt;/li&gt;
   &lt;li&gt;推荐等级 ：⭐⭐⭐⭐&lt;/li&gt;
   &lt;li&gt;评价 ：我个人比较喜欢的一款博客样式类型（    &lt;em&gt;不过，需要花更多时间自定义和完善。没精力折腾的，慎入！&lt;/em&gt;），自带评论系统、SEO等功能。比较适合做知识沉淀类网站。&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img alt="Artificial-Intelligence-Algorithm-Scientist-www.piqiandong.com" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6af69f55cc4049feb62f0d2604850541~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;solo&lt;/h2&gt;
  &lt;ul&gt;
   &lt;li&gt;Github地址：    &lt;a href="https://github.com/88250/solo" rel="nofollow noopener noreferrer" target="_blank"&gt;github.com/88250/solo&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;Star : 0.8k&lt;/li&gt;
   &lt;li&gt;简介 ：    &lt;a href="https://solo.b3log.org/" rel="nofollow noopener noreferrer" target="_blank"&gt;Solo&lt;/a&gt; 是一款小而美的开源博客系统，专为程序员设计。     &lt;a href="https://solo.b3log.org/" rel="nofollow noopener noreferrer" target="_blank"&gt;Solo&lt;/a&gt;是B3log 分布式社区的 Java 博客端节点系统，欢迎加入下一代社区网络。&lt;/li&gt;
   &lt;li&gt;技术 ：Docker+H2+Nginx+    &lt;a href="https://github.com/88250/latke" rel="nofollow noopener noreferrer" target="_blank"&gt;Latke&lt;/a&gt; （作者自研的以 JSON 为主的 Java Web 框架）&lt;/li&gt;
   &lt;li&gt;推荐等级：⭐⭐⭐⭐&lt;/li&gt;
   &lt;li&gt;评价 ：和 halo 一样，都是比较成熟的博客系统了，并且生态特别好。Solo 第一个版本是在 2020 年发布，到现在为止，Solo项目的作者已经维护这个项目快10年了。为你们点赞！感谢你们的付出！另外，需要格外说明一下：    &lt;strong&gt;项目框架不是选用的主流的 Spring Boot 而是作者自己写的一个叫做      &lt;a href="https://github.com/88250/latke" rel="nofollow noopener noreferrer" target="_blank"&gt;Latke&lt;/a&gt; 的web 框架。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;   &lt;strong&gt;solo 博客效果：&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img alt="D&amp;#30340;&amp;#20010;&amp;#20154;&amp;#21338;&amp;#23458;" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/981336d39244469c88ec14279e6b24c2~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;蘑菇博客&lt;/h2&gt;
  &lt;ul&gt;
   &lt;li&gt;Github地址：    &lt;a href="https://gitee.com/moxi159753/mogu_blog_v2" rel="nofollow noopener noreferrer" target="_blank"&gt;gitee.com/moxi159753/…&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;Star: 1.2k&lt;/li&gt;
   &lt;li&gt;简介：蘑菇博客(MoguBlog)，一个基于微服务架构的前后端分离博客系统。&lt;/li&gt;
   &lt;li&gt;技术 ：Spring Boot + Spring Cloud Alibaba +     &lt;a href="https://baomidou.com/" rel="nofollow noopener noreferrer" target="_blank"&gt;MyBatis-Plus&lt;/a&gt; + ElasticSearch&lt;/li&gt;
   &lt;li&gt;推荐等级：⭐⭐⭐⭐&lt;/li&gt;
   &lt;li&gt;评价：第一次看到基于微服务架构的个人博客系统。我觉得作者可能是为了检验自己对于微服务相关框架的掌握，正如作者说的那样：“现在挺多是SSM或者SSH的博客管理系统，想用spring boot + spring cloud + vue 的微服务架构进行尝试项目的构建，里面很多功能可能只是为了满足自己的学习需求而引入的，因此本博客也是一个非常好的SpringBoot、SpringCloud以及Vue技术的入门学习项目。”&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;img alt=" &amp;#34321;&amp;#33735;&amp;#21338;&amp;#23458;-&amp;#19987;&amp;#27880;&amp;#20110;&amp;#25216;&amp;#26415;&amp;#20998;&amp;#20139;&amp;#30340;&amp;#21338;&amp;#23458;&amp;#24179;&amp;#21488;-demoweb.moguit.cn" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b16cd268d43944d0bcd803803a199b67~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&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;img alt="&amp;#34321;&amp;#33735;&amp;#20113;&amp;#21518;&amp;#21488;&amp;#31649;&amp;#29702;&amp;#31995;&amp;#32479;-demoadmin.moguit.cn" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9b0a34887b434a7c8d0ad5232bc001b4~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;plumemo&lt;/h2&gt;
  &lt;ul&gt;
   &lt;li&gt;Github地址 ：     &lt;a href="https://github.com/byteblogs168/plumemo" rel="nofollow noopener noreferrer" target="_blank"&gt;github.com/byteblogs16…&lt;/a&gt;。&lt;/li&gt;
   &lt;li&gt;Star: 0.3k&lt;/li&gt;
   &lt;li&gt;简介：基于    &lt;a href="https://spring.io/projects/spring-boot/" rel="nofollow noopener noreferrer" target="_blank"&gt;SpringBoot&lt;/a&gt;实现零配置让系统的配置更简单，使用了    &lt;a href="https://mp.baomidou.com/" rel="nofollow noopener noreferrer" target="_blank"&gt;Mybatis-Plus&lt;/a&gt;快速开发框架，在不是复杂的查询操作下，无需写sql就可以快速完成接口编写。 后台管理系统使用了vue中流行的    &lt;a href="https://panjiachen.github.io/vue-element-admin-site/#/" rel="nofollow noopener noreferrer" target="_blank"&gt;ant&lt;/a&gt;，另外前后交互使用了    &lt;a href="https://jwt.io/" rel="nofollow noopener noreferrer" target="_blank"&gt;JWT&lt;/a&gt;作为令牌，进行权限、登录校验。。&lt;/li&gt;
   &lt;li&gt;技术 ：Spring boot +      &lt;a href="https://baomidou.com/" rel="nofollow noopener noreferrer" target="_blank"&gt;MyBatis-Plus&lt;/a&gt; + JWT&lt;/li&gt;
   &lt;li&gt;推荐等级：⭐⭐⭐⭐&lt;/li&gt;
   &lt;li&gt;评价 ：界面简单美观，基于 Spring Boot 开发，适合用来学习，同时适合用来作为自己的博客。&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;   &lt;strong&gt;plumemo博客后台效果：&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img alt="plumemo-qfdxz.top" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ae25b5050f7d40199835446c68d1b032~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;以上就是我今天要推荐的所有博客了。花了比较长时间去搜索以及对比，希望能对JavaGuide的小可爱们的有帮助！ღ( ´･ᴗ･` )比心&lt;/p&gt;
  &lt;p&gt;   &lt;strong&gt;如果有帮助的话，不要吝啬你们手中的在看和赞！“怼”起来！&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;  &lt;img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1cec8d78c65e41318396fa084778fab1~tplv-k3u1fbpfcp-zoom-1.image"&gt;&lt;/img&gt;  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;以上  4 本优质   &lt;strong&gt;原创 PDF&lt;/strong&gt; 微信搜“   &lt;strong&gt;JavaGuide&lt;/strong&gt;”后台回复“   &lt;strong&gt;面试突击&lt;/strong&gt;”即可免费领取。&lt;/p&gt;&lt;/div&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 />
      <guid isPermaLink="true">https://itindex.net/detail/60873-java-%E7%A8%8B%E5%BA%8F%E5%91%98-%E5%8D%9A%E5%AE%A2</guid>
      <pubDate>Thu, 17 Sep 2020 10:53:34 CST</pubDate>
    </item>
    <item>
      <title>深圳人到底有多拼？我们研究了40年的数据，发现……</title>
      <link>https://itindex.net/detail/60837-%E6%B7%B1%E5%9C%B3-%E7%A0%94%E7%A9%B6-%E6%95%B0%E6%8D%AE</link>
      <description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;  &lt;img src="https://img.21jingji.com/uploadfile/cover/20200825/1598356884220910.jpg" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;今天，深圳迎来40岁生日。&lt;/p&gt; &lt;p&gt;过去40年，一批又一批建设者用世人瞩目的“深圳速度”“深圳模式”，将一个小渔村变成了一座“充满魅力、活力和创新力的国际化大都市”，创造了一个又一个“深圳奇迹”，成为全球经济特区的成功典范。&lt;/p&gt; &lt;p&gt;这一切都是每一位“深圳人”的辛勤付出、努力拼搏的成果。&lt;/p&gt; &lt;h4&gt;40年深圳人口增长42倍&lt;/h4&gt; &lt;h4&gt;GDP增长近1.4万倍&lt;/h4&gt; &lt;p&gt;改革开放的春风，经济特区的政策优势，让深圳焕发出前所未有的生命力，吸引了五湖四海的人为其发展做贡献。据21数据新闻实验室统计，40年来，深圳常住人口从31.41万人增长至1343.88万人，增长42倍。同期，北上广人口增长均在1-2倍之间。&lt;/p&gt; &lt;p&gt;庞大且增长迅速的人口，对深圳来说意味着强大的生产力和消费力，是经济社会发展的源泉。21数据新闻实验室统计数据发现，40年间，深圳GDP实现惊人增长，从1.96亿上升到2.69万亿，增长近1.4万倍（同期全国增长241倍），年均增长28%；人均GDP从606元增长至20.35万元跃升为全国第一，增长334倍（同期全国增长167倍）。&lt;/p&gt; &lt;p&gt;   &lt;img src="https://img.21jingji.com/uploadfile/cover/20200826/1598428382364617.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;此外，深圳在2018年GDP首次超过香港，成为粤港澳大湾区城市经济总量第一的城市。2020年上半年，在全球新冠疫情背景下，深圳经济总量仍保持正增长，为12634.30亿元，全国排名第三。&lt;/p&gt; &lt;p&gt;那么，“深圳人”作为这些经济增长背后的功臣都有何特点？21数据新闻实验室一一解密。&lt;/p&gt; &lt;h4&gt;超50%“深圳人”来自本省&lt;/h4&gt; &lt;h4&gt;外省人中湖南占比最多&lt;/h4&gt; &lt;p&gt;“来了就是深圳人”，这是让所有外地人最暖心的一句标语。&lt;/p&gt; &lt;p&gt;深圳这座典型的移民城市，包容性极强，外来人口占比极高。据深圳统计局公布数据显示，2019年深圳常住人口有1343.88万人，其中非户籍人口849.1万人，占比超63%，那么，这些外来人口都来源于哪些地方？&lt;/p&gt; &lt;p&gt;据宝安县志等文献记载，1979年深圳建市之前，31.41万的原住民以客家人为主，客家人占深圳原住民的六成以上。改革开放后，深圳设立经济特区，在政策吸引下，广东广府系、潮汕系以及客家系三支人口率先移民深圳，与此同时，也吸引了湖南、广西、江西等邻省以及河南、四川、重庆等中西部地区人口。&lt;/p&gt; &lt;p&gt;   &lt;img src="https://img.21jingji.com/uploadfile/cover/20200826/202008261554465157.jpg" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;21数据新闻实验室根据百度迁徙大数据统计发现：&lt;/p&gt; &lt;ul&gt;  &lt;li&gt;   &lt;p&gt;深圳常住人口超50%来自广东本省，其次是湖南、广西；&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;从具体城市来看，流入地TOP10中，前9名均为广东城市，分别是东莞、惠州、广州、梅州、茂名、揭阳、河源、汕尾、湛江，江西赣州排第10；&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;流入地TOP20中，广东城市占12个，其次是湖南有4个城市上榜；&lt;/p&gt;&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;整体来看，深圳的“虹吸”效应辐射整个秦岭淮河以南地区，外省建设者来源地最多的9个省份占据8个，其中TOP3来源地湖南、广西、江西，均为广东省邻居。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;平均年龄仅33岁&lt;/h4&gt; &lt;h4&gt;超86%深圳人在工作打拼！&lt;/h4&gt; &lt;p&gt;数据显示，2019年深圳户籍人口不足500万人，仅占常住人口的36.82%，人口倒挂现象较为严重；同一时期，北上广的户籍人口占比分别为65.38%、59.73%、62.31%。&lt;/p&gt; &lt;p&gt;从男女比例来看，2018年户籍人口为454.7万人，其中男性有228.6万人，女性有226.1万人。&lt;/p&gt; &lt;p&gt;   &lt;img src="https://img.21jingji.com/uploadfile/cover/20200826/202008261555123437.jpg" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;深圳面积不到2000平方公里的地方住着1343.88万人，人口密度高达6727人/平方公里，是全国“最挤”的城市。近5年来，深圳仍保持每年40万—50万人的新增常住人口，人口还在源源不断地增加。&lt;/p&gt; &lt;p&gt;深圳也是全国“最年轻”“最拼”的城市，常住人口平均年龄只有33岁，就业人员占常住人口比例超86%，其他一线城市均在56%-60%之间。深圳年龄结构总体呈现“两头低、中间高”的特征，人口增长空间仍然较大。&lt;/p&gt; &lt;h4&gt;从人口红利转为人才红利&lt;/h4&gt; &lt;h4&gt;人才占比从1%上升到45%&lt;/h4&gt; &lt;p&gt;过去，深圳享受人口流动带来的人口红利，快速崛起成经济总量领先的超一线城市。但随着人口增长速度下降，劳动力成本提高，各大城市均面临产业升级，人口红利不可持续。&lt;/p&gt; &lt;p&gt;如今，除了北京上海还需疏解人口的超级城市，包括广州、深圳、杭州在内的头部城市都加入如火如荼的“抢人大战”，而这实际上是“人才争夺战”。&lt;/p&gt; &lt;p&gt;数据显示，2019年，杭州人口增量已经超过深圳成为全国人口净流入最多的城市。据悉，2019年5月，杭州推出新的人才引入政策，凡是大专以上学历，35 周岁以下，缴纳一个月社保即可落户。&lt;/p&gt; &lt;p&gt;   &lt;img src="https://img.21jingji.com/uploadfile/cover/20200826/202008261555316918.jpg" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;近些年，深圳也推出一批又一批人才引入政策，放宽入户条件，扩大户籍人口规模，对人才落户不设上限，拿出真金白银补贴百万年薪人才个税，还有住房补贴、创业补贴等，试图改善当前人口结构严重倒挂的问题，优化深圳人才结构。&lt;/p&gt; &lt;p&gt;除此之外，还加大财政投入，新办各类学校和医院，向全球教育和医疗人才抛出橄榄枝，一改过去教育、医疗等民生事业底子薄、基础差、发展起步晚的缺点，提供便捷舒适的生活环境。&lt;/p&gt; &lt;p&gt;   &lt;img src="https://img.21jingji.com/uploadfile/cover/20200826/202008261555512070.jpg" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;在一系列措施吸引下，2017年深圳户籍人口猛增50万人，创历史最高纪录。2018年，深圳接收应届毕业生10.8万人，同比增长7%，连续5年创新高；同年深圳各类人才已达到580万人，占常住人口44.5%。&lt;/p&gt; &lt;p&gt;展望未来发展潜力，40岁的深圳，既是深圳经济特区，又是粤港澳大湾区中心城市，还是社会主义先行示范区。凭借“三区叠加”带来的驱动效应，深圳将迎来新的战略机遇。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;【先行40年 湾区新标杆】系列策划&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;出品：南方财经全媒体集团  21财经客户端&lt;/p&gt; &lt;p&gt;          21数据新闻实验室&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;/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;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 />
      <guid isPermaLink="true">https://itindex.net/detail/60837-%E6%B7%B1%E5%9C%B3-%E7%A0%94%E7%A9%B6-%E6%95%B0%E6%8D%AE</guid>
      <pubDate>Wed, 26 Aug 2020 17:59:29 CST</pubDate>
    </item>
    <item>
      <title>说说Kubernetes是怎么实现服务发现的</title>
      <link>https://itindex.net/detail/60394-kubernetes-%E6%9C%8D%E5%8A%A1-%E5%8F%91%E7%8E%B0</link>
      <description>&lt;p&gt;我们来说说 kubernetes 的服务发现。那么首先这个大前提是同主机通信以及跨主机通信都是 ok 的，即同一 kubernetes 集群中各个 pod 都是互通的。这点是由更底层的方案实现，包括 docker0/CNI 网桥、flannel vxlan/host-gw 模式等，在此篇就不展开讲了。&lt;/p&gt;
 &lt;p&gt;在各 pod 都互通的前提下，我们可以通过访问 podIp 来调用 pod 上的资源，那么离服务发现还有多少距离呢？首先 Pod 的 IP 不是固定的，另一方面我们访问一组 Pod 实例的时候往往会有负载均衡的需求，那么 service 对象就是用来解决此类问题的。&lt;/p&gt;
 &lt;h2&gt;集群内通信&lt;/h2&gt;
 &lt;h3&gt;endPoints&lt;/h3&gt;
 &lt;p&gt;service 首先解决的是集群内通信的需求，首先我们编写一个普通的 deployment:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostnames
spec:
  selector:
    matchLabels:
      app: hostnames
  replicas: 3
  template:
    metadata:
      labels:
        app: hostnames
    spec:
      containers:
        - name: hostnames
          image: mirrorgooglecontainers/serve_hostname
          ports:
            - containerPort: 9376
              protocol: TCP
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这个应用干的事儿就是访问它是返回自己的 hostname，并且每个 pod 都带上了 app 为 hostnames 的标签。&lt;/p&gt;
 &lt;p&gt;那么我们为这些 pod 编写一个普通的 service：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: hostnames
spec:
  selector:
    app: hostnames
  ports:
    - name: default
      protocol: TCP
      port: 80
      targetPort: 9376
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;可以看到 service 通过 selector 选择  了带相应的标签 pod，而这些被选中的 pod，成为 endpoints，我们可以试一下：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt; ~/cloud/k8s kubectl get ep hostnames
NAME        ENDPOINTS
hostnames   172.28.21.66:9376,172.28.29.52:9376,172.28.70.13:9376
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;当某一个 pod 出现问题，不处于 running 状态或者 readinessProbe 未通过时，endpoints 列表会将其摘除。&lt;/p&gt;
 &lt;h3&gt;clusterIp&lt;/h3&gt;
 &lt;p&gt;以上我们有了 service 和 endpoints，而默认创建 service 的类型是 clusterIp 类型，我们查看一下之前创建的 service:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt; ~ kubectl get svc hostnames
NAME        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
hostnames   ClusterIP   10.212.8.127           80/TCP    8m2s
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;我们看到 cluster-ip 是 10.212.8.127，那么我们此时可以在 kubernetes 集群内通过这个地址访问到 endpoints 列表里的任意 pod:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;sh-4.2# curl 10.212.8.127
hostnames-8548b869d7-9qk6b
sh-4.2# curl 10.212.8.127
hostnames-8548b869d7-wzksp
sh-4.2# curl 10.212.8.127
hostnames-8548b869d7-bvlw8
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;访问了三次 clusterIp 地址，返回了三个不同的 hostname，我们意识到 clusterIp 模式的 service 自动对请求做了 round robin 形式的负载均衡。&lt;/p&gt;
 &lt;p&gt;对于此时 clusterIp 模式 serivice 来说，它有一个 A 记录是  &lt;code&gt;service-name.namespace-name.svc.cluster.local&lt;/code&gt;，指向 clusterIp 地址：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;sh-4.2# nslookup hostnames.coops-dev.svc.cluster.local
Server:10.212.0.2
Address:10.212.0.2#53

Name:hostnames.coops-dev.svc.cluster.local
Address: 10.212.8.127
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;理所当然我们通过此 A 记录去访问得到的效果一样：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;sh-4.2# curl hostnames.coops-dev.svc.cluster.local
hostnames-8548b869d7-wzksp
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;那对 pod 来说它的 A 记录是啥呢，我们可以看一下：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;sh-4.2# nslookup 172.28.21.66
66.21.28.172.in-addr.arpaname = 172-28-21-66.hostnames.coops-dev.svc.cluster.local.
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;h3&gt;headless service&lt;/h3&gt;
 &lt;p&gt;service 的 cluserIp 默认是 k8s 自动分配的，当然也可以自己设置，当我们将 clusterIp 设置成 none 的时候，它就变成了 headless service。&lt;/p&gt;
 &lt;p&gt;headless service 一般配合 statefulSet 使用。statefulSet 是一种有状态应用的容器编排方式，其核心思想是给予 pod 指定的编号名称，从而让 pod 有一个不变的唯一网络标识码。那这么说来，使用 cluserIp 负载均衡访问 pod 的方式显然是行不通了，因为我们渴望通过某个标识直接访问到 pod 本身，而不是一个虚拟 vip。&lt;/p&gt;
 &lt;p&gt;这个时候我们其实可以借助 dns，每个 pod 都会有一条 A 记录  &lt;code&gt;pod-name.service-name.namespace-name.svc.cluster.local&lt;/code&gt;指向 podIp，我们可以通过这条 A 记录直接访问到 pod。&lt;/p&gt;
 &lt;p&gt;我们编写相应的 statefulSet 和 service 来看一下：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: hostnames
spec:
  serviceName: &amp;quot;hostnames&amp;quot;
  selector:
    matchLabels:
      app: hostnames
  replicas: 3
  template:
    metadata:
      labels:
        app: hostnames
    spec:
      containers:
        - name: hostnames
          image: mirrorgooglecontainers/serve_hostname
          ports:
            - containerPort: 9376
              protocol: TCP

---
apiVersion: v1
kind: Service
metadata:
  name: hostnames
spec:
  selector:
    app: hostnames
  clusterIP: None
  ports:
    - name: default
      protocol: TCP
      port: 80
      targetPort: 9376

复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;如上，statefulSet 和 deployment 并没有什么不同，多了一个字段  &lt;code&gt;spec.serviceName&lt;/code&gt;，这个字段的作用就是告诉 statefuleSet controller，在逻辑处理时使用  &lt;code&gt;hostnames&lt;/code&gt;这个 service 来保证 pod 的唯一可解析性。&lt;/p&gt;
 &lt;p&gt;当你执行 apply 之后，一会你就可以看到生成了对应的 pod:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt; ~ kubectl get pods -w -l app=hostnames
NAME          READY   STATUS    RESTARTS   AGE
hostnames-0   1/1     Running   0          9m54s
hostnames-1   1/1     Running   0          9m28s
hostnames-2   1/1     Running   0          9m24s
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;如意料之中，这里对 pod 名称进行了递增编号，并不重复，同时这些 pod 的创建过程也是按照编号依次串行进行的。我们知道，使用 deployment 部署的 pod 名称会加上 replicaSet 名称和随机数，重启后是不断变化的。而这边使用 statefulSet 部署的 pod，虽然 podIp 仍然会变化，但名称是一直不会变的，基于此我们得以通过固定的 Dns A 记录来访问到每个 pod。&lt;/p&gt;
 &lt;p&gt;那么此时，我们来看一下 pod 的 A 记录:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;sh-4.2# nslookup hostnames-0.hostnames
Server:10.212.0.2
Address:10.212.0.2#53

Name:hostnames-0.hostnames.coops-dev.svc.cluster.local
Address: 172.28.3.57

sh-4.2# nslookup hostnames-1.hostnames
Server:10.212.0.2
Address:10.212.0.2#53

Name:hostnames-1.hostnames.coops-dev.svc.cluster.local
Address: 172.28.29.31

sh-4.2# nslookup hostnames-2.hostnames
Server:10.212.0.2
Address:10.212.0.2#53

Name:hostnames-2.hostnames.coops-dev.svc.cluster.local
Address: 172.28.23.31
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;和之前的推论一致，我们可以通过  &lt;code&gt;pod-name.service-name.namespace-name.svc.cluster.local&lt;/code&gt;这条 A 记录访问到 podIp，在同一个 namespace 中，我们可以简化为  &lt;code&gt;pod-name.service-name&lt;/code&gt;。&lt;/p&gt;
 &lt;p&gt;而这个时候，service 的 A 记录是什么呢：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;sh-4.2# nslookup hostnames
Server:10.212.0.2
Address:10.212.0.2#53

Name:hostnames.coops-dev.svc.cluster.local
Address: 172.28.29.31
Name:hostnames.coops-dev.svc.cluster.local
Address: 172.28.3.57
Name:hostnames.coops-dev.svc.cluster.local
Address: 172.28.23.31
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;原来是 endpoints 列表里的一组 podIp，也就是说此时你依然可以通过  &lt;code&gt;service-name.namespace-name.svc.cluster.local&lt;/code&gt;这条 A 记录来负载均衡地访问到后端 pod。&lt;/p&gt;
 &lt;h3&gt;iptables&lt;/h3&gt;
 &lt;p&gt;或多或少我们知道 kubernetes 里面的 service 是基于 kube-proxy 和 iptables 工作的。service 创建之后可以被 kube-proxy 感知到，那么它会为此在宿主机上创建对应的 iptables 规则。&lt;/p&gt;
 &lt;p&gt;以 cluserIp 模式的 service 为例，首先它会创建一条  &lt;code&gt;KUBE-SERVICES&lt;/code&gt;规则作为入口:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;-A KUBE-SERVICES -d 10.212.8.127/32 -p tcp -m comment --comment &amp;quot;default/hostnames: cluster IP&amp;quot; -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这条记录的意思是:所有目的地址是 10.212.8.127 这条 cluserIp 的，都将跳转到  &lt;code&gt;KUBE-SVC&lt;/code&gt; iptables 链处理。&lt;/p&gt;
 &lt;p&gt;那么我们来看   &lt;code&gt;KUBE-SVC&lt;/code&gt;链都是什么：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment &amp;quot;default/hostnames:&amp;quot; -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment &amp;quot;default/hostnames:&amp;quot; -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment &amp;quot;default/hostnames:&amp;quot; -j KUBE-SEP-57KPRZ3JQVENLNBR
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这组规则其实是用于负载均衡的，我们看到了--probability 依次是 1/3、1/2、1，由于 iptables 规则是自上而下匹配的，所以设置这些值能保证每条链匹配到的几率一样。处理完负载均衡的逻辑后，又分别将请求转发到了另外三条规则，我们来看一下:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;-A KUBE-SEP-57KPRZ3JQVENLNBR -s 172.28.21.66/32 -m comment --comment &amp;quot;default/hostnames:&amp;quot; -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment &amp;quot;default/hostnames:&amp;quot; -m tcp -j DNAT --to-destination 172.28.21.66:9376

-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 172.28.29.52/32 -m comment --comment &amp;quot;default/hostnames:&amp;quot; -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment &amp;quot;default/hostnames:&amp;quot; -m tcp -j DNAT --to-destination 172.28.29.52:9376

-A KUBE-SEP-X3P2623AGDH6CDF3 -s 172.28.70.13/32 -m comment --comment &amp;quot;default/hostnames:&amp;quot; -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment &amp;quot;default/hostnames:&amp;quot; -m tcp -j DNAT --to-destination 172.28.70.13:9376
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;可以看到   &lt;code&gt;KUBE-SEP&lt;/code&gt;链 就是三条 DNAT 规则，并在 DNAT 之前设置了一个 0x00004000 的标志。DNAT 规则就是在 PREROUTING，即路由作用之前，将请求的目的地址和端口改为--to-destination 指定的 podIp 和端口。这样一来，我们起先访问 10.212.8.127 这个 cluserIp 的请求，就会被负载均衡到各个 pod 上。&lt;/p&gt;
 &lt;p&gt;那么 pod 重启了，podIp 变了怎么办？自然是 kube-proxy 负责监听 pod 变化以及更新维护 iptables 规则了。&lt;/p&gt;
 &lt;p&gt;而对于 headless service 来说，我们直接通过固定的 A 记录访问到了 pod，自然不需要这些 iptables 规则了。&lt;/p&gt;
 &lt;p&gt;iptables 理解起来比较简单，但实际上性能并不好。可以想象，当我们的 pod 非常多时，成千上万的 iptables 规则将被创建出来，并不断刷新，会占用宿主机大量的 cpu 资源。一个行之有效的方案是基于 IPVS 模式的 service，IPVS 不需要为每个 pod 都设置 iptables 规则，而是将这些规则都放到了内核态，极大降低了维护这些规则的成本。&lt;/p&gt;
 &lt;h2&gt;集群间通信&lt;/h2&gt;
 &lt;h3&gt;外界访问 sevice&lt;/h3&gt;
 &lt;p&gt;以上我们讲了请求怎么在 kubernetes 集群内互通，主要基于 kube-dns 生成的 dns 记录以及 kube-proxy 维护的 iptables 规则。而这些信息都是作用在集群内的，那么自然我们从集群外访问不到一个具体的 service 或者 pod 了。&lt;/p&gt;
 &lt;p&gt;service 除了默认的 cluserIp 模式外，还提供了很多其他的模式，比如 nodePort 模式，就是用于解决该问题的。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: hostnames
spec:
  selector:
    app: hostnames
  type: NodePort
  ports:
    - nodePort: 8477
      protocol: TCP
      port: 80
      targetPort: 9376
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;我们编写了一个 nodePort 模式的 service，并且设置 nodePort 为 8477，那么意味着我们可以通过任意一台宿主机的 8477 端口访问到 hostnames 这个 sevice。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;sh-4.2# curl 10.1.6.25:8477
hostnames-8548b869d7-j5lj9
sh-4.2# curl 10.1.6.25:8477
hostnames-8548b869d7-66vnv
sh-4.2# curl 10.1.6.25:8477
hostnames-8548b869d7-szz4f
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;我们随便找了一台 node 地址去访问，得到了相同的返回配方。
那么这个时候它的 iptables 规则是怎么作用的呢：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;-A KUBE-NODEPORTS -p tcp -m comment --comment &amp;quot;default/hostnames: nodePort&amp;quot; -m tcp --dport 8477 -j KUBE-SVC-67RL4FN6JRUPOJYM
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;kube-proxy 在每台宿主机上都生成了如上的 iptables 规则，通过--dport 指定了端口，访问该端口的请求都会跳转到  &lt;code&gt;KUBE-SVC&lt;/code&gt;链上，  &lt;code&gt;KUBE-SVC&lt;/code&gt;链和之前 cluserIp service 的配方一样，接下来就和访问 cluserIp service 没什么区别了。&lt;/p&gt;
 &lt;p&gt;不过还需要注意的是，在请求离开当前宿主机发往其他 node 时会对其做一次 SNAT 操作：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;
-A KUBE-POSTROUTING -m comment --comment &amp;quot;kubernetes service traffic requiring SNAT&amp;quot; -m mark --mark 0x4000/0x4000 -j MASQUERADE
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;可以看到这条 postrouting 规则给即将离开主机的请求进行了一次 SNAT，判断条件为带有 0x4000 标志，这就是之前 DNAT 带的标志，从而判断请求是从 service 转发出来的，而不是普通请求。&lt;/p&gt;
 &lt;p&gt;需要做 SNAT 的原因很简单，首先这是一个外部的未经 k8s 处理的请求，
如果它访问 node1，node1 的负载均衡将其转发给 node2 上的某个 pod，这没什么问题，而这个 pod 处理完后直接返回给外部 client，那么外部 client 就很疑惑，明明自己访问的是 node1，给自己返回的确是 node2，这时往往会报错。&lt;/p&gt;
 &lt;p&gt;SNAT 的作用与 DNAT 相反，就是在请求从 node1 离开发往 node2 时，将源地址改为 node1 的地址，那么当 node2 上的 pod 返回时，会返回给 node1，然后再让 node1 返回给 client。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;              client
                | ^
                | |
                v |
   node 2 &amp;lt;--- node 1
    | ^   SNAT
    | |   ---&amp;gt;
    v |
 endpoints
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;service 还有另外 2 种通过外界访问的方式。适用于公有云的 LoadBalancer 模式的 service，公有云 k8s 会调用 CloudProvider 在公有云上为你创建一个负载均衡服务，并且把被代理的 Pod 的 IP 地址配置给负载均衡服务做后端。另外一种是 ExternalName 模式，可以通过在  &lt;code&gt;spec.externalName&lt;/code&gt;来指定你想要的外部访问域名，例如  &lt;code&gt;hostnames.example.com&lt;/code&gt;，那么你访问该域名和访问  &lt;code&gt;service-name.namespace-name.svc.cluser.local&lt;/code&gt;效果是一样的，这时候你应该知道，其实 kube-dns 为你添加了一条 cname 记录。&lt;/p&gt;
 &lt;h3&gt;ingress&lt;/h3&gt;
 &lt;p&gt;service 有一种类型叫作 loadBalancer，不过如果每个 service 对外都配置一个负载均衡服务，成本很高而且浪费。一般来说我们希望有一个全局的负载均衡器，通过访问不同 url，转发到不同 service 上，而这就是 ingress 的功能，ingress 可以看做是 service 的 service。&lt;/p&gt;
 &lt;p&gt;ingress 其实是对反向代理的一种抽象，相信大家已经感觉到，这玩意儿和 nginx 十分相似，实际上 ingress 是抽象层，而其实现层其中之一就支持 nginx。&lt;/p&gt;
 &lt;p&gt;我们可以部署一个 nginx ingress controller:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;  &lt;a href="https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml" rel="nofollow noopener noreferrer" target="_blank"&gt;mandatory.yaml&lt;/a&gt;是官方维护的 ingress controller，我们看一下：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;
kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      annotations:
        ...
    spec:
      serviceAccountName: nginx-ingress-serviceaccount
      containers:
        - name: nginx-ingress-controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.20.0
          args:
            - /nginx-ingress-controller
            - --configmap=$(POD_NAMESPACE)/nginx-configuration
            - --publish-service=$(POD_NAMESPACE)/ingress-nginx
            - --annotations-prefix=nginx.ingress.kubernetes.io
          securityContext:
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
            # www-data -&amp;gt; 33
            runAsUser: 33
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
            - name: http
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          ports:
            - name: http
              containerPort: 80
            - name: https
              containerPort: 443
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;总的来说，我们定义了一个基于 nginx-ingress-controller 镜像的 pod，
而这个 pod 自身，是一个监听 ingress 对象及其代理后端 service 变化的控制器。&lt;/p&gt;
 &lt;p&gt;当一个 ingress 对象被创建时，nginx-ingress-controller 就会根据 ingress 对象里的内容，生成一份 nginx 配置文件(nginx.conf)，并依此启动一个 nginx 服务。&lt;/p&gt;
 &lt;p&gt;当 ingress 对象被更新时，nginx-ingress-controller 就会更新这个配置文件。nginx-ingress-controller 还通过 nginx lua 方案实现了 nginx upstream 的动态配置。&lt;/p&gt;
 &lt;p&gt;为了让外界可以访问到这个 nginx，我们还得给它创建一个 service 来把 nginx 暴露出去:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这里面的内容描述了一个 nodePort 类型的 service:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  type: NodePort
  ports:
    - name: http
      port: 80
      targetPort: 80
      protocol: TCP
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;可以看到这个 service 仅仅是把 nginx pod 的 80/443 端口暴露出去，完了你就可以通过宿主机 Ip 和 nodePort 端口访问到 nginx 了。&lt;/p&gt;
 &lt;p&gt;接下来我们来看 ingress 对象一般是如何编写的，我们可以参考一个  &lt;a href="https://github.com/nginxinc/kubernetes-ingress/blob/master/examples/complete-example/cafe-ingress.yaml" rel="nofollow noopener noreferrer" target="_blank"&gt;例子&lt;/a&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: cafe-ingress
spec:
  tls:
  - hosts:
    - cafe.example.com
    secretName: cafe-secret
  rules:
  - host: cafe.example.com
    http:
      paths:
      - path: /tea
        backend:
          serviceName: tea-svc
          servicePort: 80
      - path: /coffee
        backend:
          serviceName: coffee-svc
          servicePort: 80
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这个 ingress 表明我们整体的域名是  &lt;code&gt;cafe.example.com&lt;/code&gt;，希望通过  &lt;code&gt;cafe.example.com/tea&lt;/code&gt;访问  &lt;code&gt;tea-svc&lt;/code&gt;这个 service，通过  &lt;code&gt;cafe.example.com/coffee&lt;/code&gt;访问  &lt;code&gt;coffee-svc&lt;/code&gt;这个 service。这里我们通过关键字段  &lt;code&gt;spec.rules&lt;/code&gt;来编写转发规则。&lt;/p&gt;
 &lt;p&gt;我们可以查看到 ingress 对象的详细信息:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;
$ kubectl get ingress
NAME           HOSTS              ADDRESS   PORTS     AGE
cafe-ingress   cafe.example.com             80, 443   2h

$ kubectl describe ingress cafe-ingress
Name:             cafe-ingress
Namespace:        default
Address:
Default backend:  default-http-backend:80 ()
TLS:
  cafe-secret terminates cafe.example.com
Rules:
  Host              Path  Backends
  ----              ----  --------
  cafe.example.com
                    /tea      tea-svc:80 ()
                    /coffee   coffee-svc:80 ()
Annotations:
Events:
  Type    Reason  Age   From                      Message
  ----    ------  ----  ----                      -------
  Normal  CREATE  4m    nginx-ingress-controller  Ingress default/cafe-ingress
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;我们之前讲了我们通过 nodePort 的方式将 nginx-ingress 暴露出去了，而这时候我们 ingress 配置又希望通过  &lt;code&gt;cafe.example.com&lt;/code&gt;来访问到后端 pod，那么首先  &lt;code&gt;cafe.example.com&lt;/code&gt;这个域名得指到  &lt;code&gt;任意一台宿主机Ip:nodePort&lt;/code&gt;上，请求到达 nginx-ingress 之后再转发到各个后端 service 上。当然，暴露 nginx-ingress 的方式有很多种，除了 nodePort 外还包括 loadBalancer、hostNetWork 方式等等。&lt;/p&gt;
 &lt;p&gt;我们最后来试一下请求:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;$ curl cafe.example.com/coffee
Server name: coffee-7dbb5795f6-vglbv
$ curl cafe.example.com/tea
Server name: tea-7d57856c44-lwbnp
复制代码&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;可以看到 nginx ingress controller 已经为我们成功将请求转发到了对应的后端 service。而当请求没有匹配到任何一条 ingress rule 的时候，理所当然我们会得到一个 404。&lt;/p&gt;
 &lt;p&gt;至此，kubernetes 的容器网络是怎么实现服务发现的已经讲完了，而服务发现正是微服务架构中最核心的问题，解决了这个问题，那么使用 kubernetes 来实现微服务架构也就实现了一大半。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://fredal.xin/kubertnetes-discovery" rel="nofollow noopener noreferrer" target="_blank"&gt;fredal.xin/kubertnetes…&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 />
      <guid isPermaLink="true">https://itindex.net/detail/60394-kubernetes-%E6%9C%8D%E5%8A%A1-%E5%8F%91%E7%8E%B0</guid>
      <pubDate>Mon, 24 Feb 2020 03:04:50 CST</pubDate>
    </item>
    <item>
      <title>基于springcloud实现的灰度发布</title>
      <link>https://itindex.net/detail/60368-springcloud-%E7%81%B0%E5%BA%A6</link>
      <description>&lt;h1&gt;其他参考：  &lt;br /&gt;&lt;/h1&gt; &lt;div&gt;  &lt;a href="https://github.com/charlesvhe/spring-cloud-practice"&gt;https://github.com/charlesvhe/spring-cloud-practice&lt;/a&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;  &lt;a href="https://github.com/SpringCloud/spring-cloud-gray"&gt;https://github.com/SpringCloud/spring-cloud-gray&lt;/a&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;  &lt;a href="https://github.com/saleson/fm-cloud"&gt;https://github.com/saleson/fm-cloud&lt;/a&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;  &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray"&gt;https://github.com/JeromeLiuLly/springcloud-gray&lt;/a&gt;  &lt;br /&gt;&lt;/div&gt; &lt;div&gt;  &lt;br /&gt;&lt;/div&gt; &lt;h1&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#springcloud-gray"&gt;&lt;/a&gt;springcloud-gray&lt;/h1&gt;  &lt;p&gt;基于springcloud实现的灰度发布&lt;/p&gt;  &lt;h2&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#26550;&amp;#26500;&amp;#35774;&amp;#35745;&amp;#21644;&amp;#30028;&amp;#38754;"&gt;&lt;/a&gt;架构设计和界面&lt;/h2&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#26550;&amp;#26500;&amp;#27169;&amp;#22411;"&gt;&lt;/a&gt;架构模型&lt;/h3&gt;  &lt;p&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E7%81%B0%E5%BA%A6%E6%9E%B6%E6%9E%84%E5%9B%BE.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#28784;&amp;#24230;&amp;#21457;&amp;#24067;&amp;#26550;&amp;#26500;&amp;#35774;&amp;#35745;&amp;#22270;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E7%81%B0%E5%BA%A6%E6%9E%B6%E6%9E%84%E5%9B%BE.png"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E7%81%B0%E5%BA%A6%E6%95%B0%E6%8D%AE%E6%B5%81.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#28784;&amp;#24230;&amp;#21457;&amp;#24067;&amp;#25968;&amp;#25454;&amp;#27969;&amp;#22270;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E7%81%B0%E5%BA%A6%E6%95%B0%E6%8D%AE%E6%B5%81.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#24179;&amp;#21488;&amp;#21270;&amp;#25805;&amp;#20316;"&gt;&lt;/a&gt;平台化操作&lt;/h3&gt;  &lt;p&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E7%81%B0%E5%BA%A6%E5%8F%91%E5%B8%83.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#24179;&amp;#21488;&amp;#21270;&amp;#30028;&amp;#38754;&amp;#22270;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E7%81%B0%E5%BA%A6%E5%8F%91%E5%B8%83.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h2&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#39033;&amp;#30446;&amp;#32467;&amp;#26500;"&gt;&lt;/a&gt;项目结构&lt;/h2&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#gray-config-server-&amp;#37197;&amp;#32622;&amp;#20013;&amp;#24515;"&gt;&lt;/a&gt;gray-config-server 配置中心&lt;/h3&gt;  &lt;p&gt;端口：6007，方便起见直接读取配置文件，生产环境可以读取git。先启动配置中心，所有服务的配置（包括注册中心的地址）均从配置中心读取。&lt;/p&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#gray-xxx-service-&amp;#26381;&amp;#21153;&amp;#28040;&amp;#36153;&amp;#32773;"&gt;&lt;/a&gt;gray-xxx-service 服务消费者&lt;/h3&gt;  &lt;p&gt;调用服务提供者和服务提供者，验证是否进入灰度服务。&lt;/p&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#gray-core-&amp;#26694;&amp;#26550;&amp;#26680;&amp;#24515;&amp;#21253;"&gt;&lt;/a&gt;gray-core 框架核心包&lt;/h3&gt;  &lt;p&gt;核心jar包，所有微服务均引用该包，用于负载自定义策略规则，是实现灰度发布的核心架包。&lt;/p&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#gray-service-registry-center-&amp;#27880;&amp;#20876;&amp;#20013;&amp;#24515;"&gt;&lt;/a&gt;gray-service-registry-center 注册中心&lt;/h3&gt;  &lt;p&gt;端口：6006，用于统筹各个注册服务。&lt;/p&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#gray-api-gateway-&amp;#32593;&amp;#20851;"&gt;&lt;/a&gt;gray-api-gateway 网关&lt;/h3&gt;  &lt;p&gt;端口：4002，拉取灰度策略，进行请求的把标签操作。&lt;/p&gt;  &lt;h2&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#24212;&amp;#29992;&amp;#22330;&amp;#26223;"&gt;&lt;/a&gt;应用场景&lt;/h2&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#28784;&amp;#24230;&amp;#21457;&amp;#24067;"&gt;&lt;/a&gt;灰度发布&lt;/h3&gt;  &lt;p&gt;通过灰度版本的控制，实现符合灰度策略的对象，优先进入灰度服务进行体验。&lt;/p&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#24322;&amp;#26500;&amp;#26381;&amp;#21153;&amp;#30340;&amp;#20849;&amp;#23384;"&gt;&lt;/a&gt;异构服务的共存&lt;/h3&gt;  &lt;p&gt;例如，根据不同的策略，有根据不同的渠道、地域、门店、品牌等，优先使用不同的服务。例如，广州地域的用户，仅能使用基于广州部署的微服务。&lt;/p&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#21516;&amp;#31561;&amp;#32423;&amp;#26381;&amp;#21153;&amp;#30340;&amp;#35843;&amp;#29992;"&gt;&lt;/a&gt;同等级服务的调用&lt;/h3&gt;  &lt;p&gt;例如，业务场景，根据不同的渠道和来源进行下单。微信的下单，仅能调用微信的order-service服务;官网下单，仅能调用官网的order--service下单;
通过这样的方式，上层业务无须调用何种具体服务统一底层进行负载调用，实现业务的解耦和服务的可插拔配置；&lt;/p&gt;  &lt;h2&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#23454;&amp;#29616;&amp;#24605;&amp;#36335;"&gt;&lt;/a&gt;实现思路&lt;/h2&gt;  &lt;p&gt;根据标签的控制，我们当然放到之前写的Ribbon的**    &lt;code&gt;CustomMetadataRule&lt;/code&gt;    &lt;strong&gt;中，每个实例配置的不同规则也是跟之前一样放到注册中心的metadata中，关键是标签数据如何传过来。自定义规则[&lt;/strong&gt;    &lt;code&gt;CustomMetadataRule&lt;/code&gt;    &lt;strong&gt;]的实现思路里面有答案，请求都通过&lt;/strong&gt;    &lt;code&gt;gray-api-gateway&lt;/code&gt;    &lt;strong&gt;进来，因此我们可以在zuul里面给请求打标签，基于用户，IP或其他看你的需求，然后将标签信息放入Thystrix。hystrix的原理，为了做到故障隔离，hystrix启用了自己的线程。另外使用sleuth方案，他的链路跟踪就能够将spam传递下去，翻翻sleuth源码，找找其他资料，发现可以使用&lt;/strong&gt;    &lt;code&gt;HystrixRequestVariableDefault&lt;/code&gt;    &lt;strong&gt;，这里不建议直接使用&lt;/strong&gt;    &lt;code&gt;HystrixConcurrencyStrategy&lt;/code&gt;    &lt;strong&gt;，会和sleuth的strategy冲突。代码参见&lt;/strong&gt;    &lt;code&gt;CoreHeaderInterceptor&lt;/code&gt;**。现在可以测试zuul里面的rule，看能否拿到标签内容了。&lt;/p&gt;  &lt;p&gt;这里还不是终点，解决了zuul的路由，服务A调服务B这里的路由怎么处理呢？zuul算出来的标签如何往后面依次传递下去呢，我们还是抄sleuth：把标签放入header，服务A调服务B时，将服务A header里面的标签放到服务B的header里，依次传递下去。这里的关键点就是：内部的微服务在接收到发来的请求时（gateway--&amp;gt;A，A--&amp;gt;B都是这种情况）。&lt;/p&gt;  &lt;p&gt;总结一下：zuul依据用户或IP等计算标签，并将标签放入header里向后传递，后续的微服务通过拦截器，将header里的标签放入RestTemplate请求的header里继续向后接力传递。将灰度标识放入（    &lt;strong&gt;      &lt;code&gt;HystrixRequestVariableDefault&lt;/code&gt;&lt;/strong&gt;），使Ribbon Rule可以使用。&lt;/p&gt;  &lt;h2&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#20195;&amp;#30721;&amp;#20998;&amp;#26512;&amp;#23454;&amp;#29616;&amp;#27969;&amp;#31243;"&gt;&lt;/a&gt;代码分析实现流程&lt;/h2&gt;  &lt;p&gt;自定义的规则，该处可以实现针对不同的策略，使用不同的负载机制[    &lt;strong&gt;轮询、随机、权重随机&lt;/strong&gt;]&lt;/p&gt;  &lt;div&gt;    &lt;pre&gt;publicclassCustomMetadataRuleextendsZoneAvoidanceRule{//检测灰度开关是否启动privateHttpResultcheckGraySwitch() {Stringurl=&amp;quot;http://10.200.102.136:6015/eureka/apps/switch&amp;quot;;HttpResultresult=newHttpResult();
		result.statusCode=500;try{
			result=HttpClient.get(url,null);
		}catch(Exceptione1) {
			e1.printStackTrace();
		}returnresult;
	}@OverridepublicServerchoose(Objectkey) {//获取是否存在存活的服务可调用List&amp;lt;Server&amp;gt;serverList=this.getPredicate().getEligibleServers(this.getLoadBalancer().getAllServers());//获取不到服务if(CollectionUtils.isEmpty(serverList)) {returnnull;
		}//获取灰度开关是否启动HttpResultresult=checkGraySwitch();//灰度开关被设置成关闭状态,默认走空metadata或者是特定标识是正常的服务,轮询访问BooleanisOpen=Boolean.parseBoolean(JSONObject.parseObject(result.content).getString(&amp;quot;errorMsg&amp;quot;));if(result.statusCode==200&amp;amp;&amp;amp;!isOpen) {
			isOpen=true;returnRoundRobinRuleBySelf.getInstance().choose(this.getLoadBalancer(), key,isOpen);
		}//灰度发布启动状态,未被设置成灰度对象,默认走空metadata或者是特定标识是正常的服务,轮询访问if(StringUtils.isEmpty(CoreHeaderInterceptor.label.get())) {
			isOpen=false;returnRoundRobinRuleBySelf.getInstance().choose(this.getLoadBalancer(), key,isOpen);
		}//灰度发布启动状态,被设置成灰度对象,走空特定标识的服务,轮询访问returnRoundRobinRuleBySelf.getInstance().choose(this.getLoadBalancer(), key,!isOpen);
	}
}&lt;/pre&gt;&lt;/div&gt;  &lt;p&gt;feignClient 调用flag位透传的问题&lt;/p&gt;  &lt;div&gt;    &lt;pre&gt;publicclassCoreFeignRequestInterceptorimplementsRequestInterceptor{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(CoreHttpRequestInterceptor.class);@Overridepublicvoidapply(RequestTemplatetemplate) {Stringheader=StringUtils.collectionToDelimitedString(CoreHeaderInterceptor.label.get(),CoreHeaderInterceptor.HEADER_LABEL_SPLIT);Stringtag=CoreHeaderInterceptor.tag.get();
		template.header(CoreHeaderInterceptor.HEADER_LABEL, header).header(CoreHeaderInterceptor.HEADER_TAG, tag);
		logger.info(&amp;quot;label:&amp;quot;+header+&amp;quot;tag :&amp;quot;+tag);
	}

}&lt;/pre&gt;&lt;/div&gt;  &lt;p&gt;HttpRequest 调用flag位透传的问题&lt;/p&gt;  &lt;div&gt;    &lt;pre&gt;publicclassCoreHttpRequestInterceptorimplementsClientHttpRequestInterceptor{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(CoreHttpRequestInterceptor.class);@OverridepublicClientHttpResponseintercept(HttpRequestrequest,byte[]body,ClientHttpRequestExecutionexecution)throwsIOException{HttpRequestWrapperrequestWrapper=newHttpRequestWrapper(request);Stringheader=StringUtils.collectionToDelimitedString(CoreHeaderInterceptor.label.get(),CoreHeaderInterceptor.HEADER_LABEL_SPLIT);Stringtag=CoreHeaderInterceptor.tag.get();
        
        logger.info(&amp;quot;label:&amp;quot;+header+&amp;quot;tag :&amp;quot;+tag);HttpHeadersheaders=requestWrapper.getHeaders();
        headers.add(CoreHeaderInterceptor.HEADER_LABEL, header);
        headers.add(CoreHeaderInterceptor.HEADER_TAG, tag);returnexecution.execute(requestWrapper, body);
    }
}&lt;/pre&gt;&lt;/div&gt;  &lt;p&gt;配置生效&lt;/p&gt;  &lt;div&gt;    &lt;pre&gt;@Configuration@EnableWebMvcpublicclassCoreAutoConfigurationextendsWebMvcConfigurerAdapter{@BeanpublicDefaultPropertiesFactorydefaultPropertiesFactory() {returnnewDefaultPropertiesFactory();
	}@LoadBalanced@BeanpublicRestTemplaterestTemplate() {RestTemplaterestTemplate=newRestTemplate();
		restTemplate.getInterceptors().add(newCoreHttpRequestInterceptor());returnrestTemplate;
	}//用于配置feignClient透传生效@BeanpublicFeign.BuilderfeignBuilder() {returnFeign.builder().requestInterceptor(newCoreFeignRequestInterceptor());
	}@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry) {
		registry.addInterceptor(newCoreHeaderInterceptor());
	}
}&lt;/pre&gt;&lt;/div&gt;  &lt;h2&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#27979;&amp;#35797;"&gt;&lt;/a&gt;测试&lt;/h2&gt;  &lt;p&gt;测试/验证流程说明：&lt;/p&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#31532;&amp;#19968;&amp;#27493;&amp;#27979;&amp;#35797;&amp;#28784;&amp;#24230;&amp;#21457;&amp;#24067;&amp;#24635;&amp;#24320;&amp;#20851;&amp;#26159;&amp;#21542;&amp;#29983;&amp;#25928;"&gt;&lt;/a&gt;第一步,测试灰度发布总开关是否生效&lt;/h3&gt;  &lt;h4&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#31616;&amp;#26131;&amp;#24418;&amp;#24335;"&gt;&lt;/a&gt;简易形式：&lt;/h4&gt;  &lt;p&gt;1.先启动 order服务;&lt;/p&gt;  &lt;p&gt;1.1 未标识灰度服务时，前端每一次访问都是随机的情况
访问url：    &lt;a href="http://127.0.0.1:4002/order/inner/order/getOrderInfoListByUserName?userName=liulianyuan" rel="nofollow"&gt;http://127.0.0.1:4002/order/inner/order/getOrderInfoListByUserName?userName=liulianyuan&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/1.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#19968;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/1.png"&gt;&lt;/img&gt;&lt;/a&gt;1.2 分别启动灰度服务和正常服务。一开始启动的时候是无差别的。我们可以在 metadata.html 进行动态配置，指定某个服务是灰度的。
以下，设置了order-service2 是灰度服务。
访问url：    &lt;a href="http://127.0.0.1:4002/order/inner/order/getOrderInfoListByUserName?userName=liulianyuan" rel="nofollow"&gt;http://127.0.0.1:4002/order/inner/order/getOrderInfoListByUserName?userName=liulianyuan&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/3.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/3.png"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/4.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/4.png"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/5.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/5.png"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/6.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/6.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h3&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#31532;&amp;#20108;&amp;#27493;&amp;#27979;&amp;#35797;&amp;#28784;&amp;#24230;&amp;#21457;&amp;#24067;&amp;#30340;&amp;#27491;&amp;#24120;&amp;#34892;&amp;#20026;"&gt;&lt;/a&gt;第二步,测试灰度发布的正常行为&lt;/h3&gt;  &lt;h4&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#26041;&amp;#24335;1------&amp;#28784;&amp;#24230;&amp;#29992;&amp;#25143;-&amp;#21069;&amp;#31471;--&amp;#32593;&amp;#20851;--&amp;#27491;&amp;#24120;&amp;#26381;&amp;#21153;--&amp;#28784;&amp;#24230;&amp;#26381;&amp;#21153;"&gt;&lt;/a&gt;方式1------(灰度用户): 前端 ==&amp;gt; 网关 ==&amp;gt; 正常服务 ==&amp;gt; 灰度服务&lt;/h4&gt;  &lt;p&gt;1.启动 order服务 和 user服务;&lt;/p&gt;  &lt;p&gt;1.1 user-service是正常服务，标识user-service2为灰度服务；order-service 均是正常服务。
1.2 启动所有服务。一开始启动的时候是无差别的。我们可以在 metadata.html 进行动态配置，指定某个服务是灰度的。&lt;/p&gt;  &lt;p&gt;请求url:    &lt;a href="http://127.0.0.1:4002/order/test?userName=liulianyuan" rel="nofollow"&gt;http://127.0.0.1:4002/order/test?userName=liulianyuan&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/7.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/7.png"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/8.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/8.png"&gt;&lt;/img&gt;&lt;/a&gt;该处是随机访问正常的order-service服务的。多试几次，就可以看见order-service和order-service2的出现。【该处如果需要做成轮需，需要改代码】&lt;/p&gt;  &lt;h4&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#26041;&amp;#24335;2------&amp;#28784;&amp;#24230;&amp;#29992;&amp;#25143;-&amp;#21069;&amp;#31471;--&amp;#32593;&amp;#20851;--&amp;#28784;&amp;#24230;&amp;#26381;&amp;#21153;--&amp;#27491;&amp;#24120;&amp;#26381;&amp;#21153;"&gt;&lt;/a&gt;方式2------(灰度用户): 前端 ==&amp;gt; 网关 ==&amp;gt; 灰度服务 ==&amp;gt; 正常服务&lt;/h4&gt;  &lt;p&gt;1.启动 order服务 和 user服务;&lt;/p&gt;  &lt;p&gt;1.1 user-service是正常服务，标识user-service2为灰度服务；order-service 均是正常服务。
1.2 启动所有服务。一开始启动的时候是无差别的。我们可以在 metadata.html 进行动态配置，指定某个服务是灰度的。    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/9.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/9.png"&gt;&lt;/img&gt;&lt;/a&gt;请求url:    &lt;a href="http://127.0.0.1:4002/user/getOrderInfo?userName=liulianyuan" rel="nofollow"&gt;http://127.0.0.1:4002/user/getOrderInfo?userName=liulianyuan&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/10.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/10.png"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/11.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/11.png"&gt;&lt;/img&gt;&lt;/a&gt;该处是随机访问正常的order-service服务的。多试几次，就可以看见order-service和order-service2的出现。【该处如果需要做成轮需，需要改代码】&lt;/p&gt;  &lt;h4&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#26041;&amp;#24335;3------&amp;#28784;&amp;#24230;&amp;#29992;&amp;#25143;-&amp;#21069;&amp;#31471;--&amp;#32593;&amp;#20851;--&amp;#28784;&amp;#24230;&amp;#26381;&amp;#21153;--&amp;#28784;&amp;#24230;&amp;#26381;&amp;#21153;"&gt;&lt;/a&gt;方式3------(灰度用户): 前端 ==&amp;gt; 网关 ==&amp;gt; 灰度服务 ==&amp;gt; 灰度服务&lt;/h4&gt;  &lt;p&gt;1.启动 order服务 和 user服务;&lt;/p&gt;  &lt;p&gt;1.1 user-service是正常服务，标识user-service2为灰度服务；order-service 均是正常服务。
1.2 启动所有服务。一开始启动的时候是无差别的。我们可以在 metadata.html 进行动态配置，指定某个服务是灰度的。    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/12.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/12.png"&gt;&lt;/img&gt;&lt;/a&gt;请求url:    &lt;a href="http://127.0.0.1:4002/order/test?userName=liulianyuan" rel="nofollow"&gt;http://127.0.0.1:4002/order/test?userName=liulianyuan&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/13.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/13.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;    &lt;a href="https://github.com/JeromeLiuLly/springcloud-gray#&amp;#26041;&amp;#24335;4------&amp;#27491;&amp;#24120;&amp;#29992;&amp;#25143;-&amp;#21069;&amp;#31471;--&amp;#32593;&amp;#20851;--&amp;#27491;&amp;#24120;&amp;#26381;&amp;#21153;--&amp;#27491;&amp;#24120;&amp;#26381;&amp;#21153;"&gt;&lt;/a&gt;方式4------(正常用户): 前端 ==&amp;gt; 网关 ==&amp;gt; 正常服务 ==&amp;gt; 正常服务&lt;/h4&gt;  &lt;p&gt;1.启动 order服务 和 user服务;&lt;/p&gt;  &lt;p&gt;1.1 user-service是正常服务，标识user-service2为灰度服务；order-service 均是正常服务。
1.2 启动所有服务。一开始启动的时候是无差别的。我们可以在 metadata.html 进行动态配置，指定某个服务是灰度的。    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/14.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/14.png"&gt;&lt;/img&gt;&lt;/a&gt;请求url:    &lt;a href="http://127.0.0.1:4002/order/test?userName=lly" rel="nofollow"&gt;http://127.0.0.1:4002/order/test?userName=lly&lt;/a&gt;    &lt;a href="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/15.png" rel="noopener noreferrer" target="_blank"&gt;      &lt;img alt="&amp;#22270;&amp;#20108;" src="https://raw.githubusercontent.com/JeromeLiuLly/springcloud-gray/master/SpringCloudGray/%E6%B5%8B%E8%AF%95%E5%9B%BE/15.png"&gt;&lt;/img&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 />
      <guid isPermaLink="true">https://itindex.net/detail/60368-springcloud-%E7%81%B0%E5%BA%A6</guid>
      <pubDate>Sun, 16 Feb 2020 21:43:55 CST</pubDate>
    </item>
    <item>
      <title>基于大数据企业网络威胁发现模型实践</title>
      <link>https://itindex.net/detail/60250-%E5%A4%A7%E6%95%B0%E6%8D%AE-%E4%BC%81%E4%B8%9A%E7%BD%91%E7%BB%9C-%E5%8F%91%E7%8E%B0</link>
      <description>&lt;div&gt;  &lt;p&gt;   &lt;strong&gt;0x01 前言&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; &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;0x02 沙漏威胁处理模型&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;img height="386" width="690"&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;图1.威胁分析沙漏模型&lt;/strong&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;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;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;代理流量&lt;/strong&gt;：代理是一种概括的统称，很多企业都有网关设备，7层或4层，这种设备服务会产生流相关量日志数据，并具有准入认证的功能。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;镜像流量&lt;/strong&gt;：镜像流量比较常见，通过流量镜像发给威胁分析设备与分析服务，设备系统反馈威胁检测报警。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;真实流量&lt;/strong&gt;：Nginx日志， 蜜罐日志等真实服务的流量数据产生的落地日志信息。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;主机数据&lt;/strong&gt;: 无论是探针APM、Zabbix Agent、OSQuery、HIDS都会产生与主机相关的指标数据， 这些数据异常阀值同样能起动预示报警的作用。   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;设备数据&lt;/strong&gt;：重要敏感设备产生的数据， 这数据有自己的异常数据监控。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;扫描数据&lt;/strong&gt;：主动扫描采集的数据：端口、服务扫描等。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;模型层次划分：&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;第一层：输入层（数据集中）&lt;/strong&gt;：在输入层出现了以上提到的各种服务、设备产生的数据。这一层关键点是数据的收集，如果没有数据的收集，后续的横向和垂直的分析工作都无数据可分析处理。   &lt;strong&gt;    &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;    &lt;br /&gt;&lt;/strong&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;em&gt;1.比如数据的快速非格式化。&lt;/em&gt;   &lt;em&gt;（切割）&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;em&gt;2.后期数据聚类统计提纯的结构化。&lt;/em&gt;   &lt;em&gt;（整形）&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;em&gt;3.数据清洗过滤与打标签。&lt;/em&gt;   &lt;em&gt;（加工）&lt;/em&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;br /&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;|输入                                 |    处理                          |输出          |&lt;/p&gt;  &lt;p&gt;---------------------------------------------------------------------&lt;/p&gt;  &lt;p&gt;|WAF|IDS|蜜罐|扫描|HIDS|采集|整型|切割|过滤|报警|报警|可视化|&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;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;0x03 安全角色分工&lt;/strong&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;strong&gt;每一种职业种类，都有自己特长的和弱点，在某些场景下工作，有人适合在对抗路，有人适合在后期发力。各种职业人对威胁信息碎片组合不一样，不同威胁碎片信息的属性，不同的职业有不同的解读和运用。&lt;/strong&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;strong&gt;数据运维&lt;/strong&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;提供操作界面，都所有可用的日志数据，提供查询界面，查询接口，完成信息查询交互。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;大数据算法&lt;/strong&gt;：&lt;/p&gt;  &lt;p&gt;AI分析是安全分析的大脑。安全威胁发的方式方法有很多的种类，比如DNS解析相关、僵尸网络相关、 WEB相关的，比如：XSS反射、SQL注入等等。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;面一种同一种威胁事件数据，有多种检测方法，比如针对 SQL注意和XSS注入这种威胁的发现方式就有：&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;em&gt;    1.基于正则匹配。&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;em&gt;    2.基于SQL Injection模式配对。&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;em&gt;    3.基于自然语言处理算法。&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;em&gt;    4.基于神经网络算法。&lt;/em&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;同样是神经网络，使用的具体算法不同，样本不同，效果也不同。比如：LSTM、MLP等。&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; &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;/p&gt;  &lt;p&gt;比如，我们可以对于基于正则模式匹配XSS分析结果，再用自然语言处理的方式进行确认，也可以对基于自然语言处理的报警，通过神经网络算法，或是开源威胁分析库的方式多次分析，通过交叉检查的方式，进行误报过滤，交叉检查是对威胁信息多重检查，叠加确认的过程。&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;网络环境中不只有一种监测手段存在，我们可以从不同的维度进行，对资产进行安全监控保护：&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;叠加堆砌威胁分析设备与服务，是为了提高发现的威胁准确率，减少漏报。有时会用多种不同的装备在同一区域叠加使用，强化某一效果，A装备效果不够快，可以用B装备。A看不见的，B可以看见。A不便于部署的，B可以便于部署。&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;第1种：流量监听&lt;/strong&gt;，我们可以会把相关某一区域的网络流量，镜像给网络检查分析模块（开源商业），通过流量分析，分析出针对某台服务操作的可疑流量数据，及威胁报警。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;第2种：部署蜜罐&lt;/strong&gt;，我们会在重要服务器所在环境部署蜜罐系统，通过蜜罐检查当前网段的可疑行为。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;第3种：加入审计监听&lt;/strong&gt;，我们可以对服务器安装类似OSQuery这种主机审计组件，分析主机配置变化的可疑行为。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;第4种：主动扫描，&lt;/strong&gt;我们可以定时对服务器发起主动扫描，服务扫描和端口扫描，通过扫描返回结果，建立漏洞库等相关情况，判断主机是否异常。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;第5种：访问控制，&lt;/strong&gt;我们可以建立服务主机的访问控制，生成通信聚类的白名单与黑名单，分析异常访问行为。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;第6种：威胁情报库，&lt;/strong&gt;我们可以将访问服务的IP与威胁情报库进行对比，发现异常访问行为。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;横向的威胁检查方法可能还会很多，这里只是举例一些。&lt;/p&gt;  &lt;p&gt;他们都有一个共同之处：这些检测分析服务都会产生，围绕同一主体的威胁报警信息，所以对于同一IP主体，可以通过各种检测手段，垂直确认后，再横向与其它分析模块的威胁数据进行比较。&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;/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;strong&gt;0x04 实现工具技术栈&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;    &lt;img height="388" width="690"&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;图2.威胁分析沙漏模型（技术栈）&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;今天的开源社区变的异常的强大，可以用各种开源软件，构建我们的安全检测系统，大家使用有类似的技术栈、像ELK、Hadoop、Spark这种工具都非常的常见，大家使用的技术工具手段都非常常见。&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;strong&gt;实现工具&lt;/strong&gt;：工具是构建服务的武器，武器有不同的属性。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;威胁发现系统是一个渐进发展的过程，在时间线上，根据规模和发展的状况不同，调用合适工具武器来达到自己夺标的目的，规模小的时候，发展初期，可以使用一般的统计工具就可以，ES单结点，Mysql数据，随着规模和时间的发展，适应大的数据量，就可以更重型的武器来解决，更复杂的需求。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;ES单结点无法满足就使用集群，一个集群不够，使用多个集群。MySQL不够就用ClickHouse。&lt;/p&gt;  &lt;p&gt;   &lt;br /&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;：对于数据输入收集阶段，各种各样的数据收集手段都能利用上。filebeat、nxlog、logstash、syslog等，各种能便捷取得数据的手段都可以用，根据不同的平台。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;第二层.处理层&lt;/strong&gt;：数据的处理之前是要对数据进行存储的，不然也没法分析数据。安全大数据中很重要的一点是数据缓存，解决输入数据量过大，处理不过来的问题。ElasticSearch是现在最行的一种数据存储方案之一，我们也不例外的使用的ES保存数据。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;用ES一个很大的好处是，我们不用想使用关系型数据库时先创建表结构，可快速想报警数据收集。对安全威胁数据来说，ES前期收集数据更快捷。高危的报警数据，理论上应该和交通数据不一样，那么巨大的并发量，所以一般的ES就可以，另外ES本身可以扩展吞吐量。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;我们对大量的日志数据驱动，还是比较担心的。&lt;/p&gt;  &lt;p&gt;所以我们用了ClickHouse。ClickHouse相对于其它的大数据工具，上手更快，更轻量，但是效果速度确实相当的好。&lt;/p&gt;  &lt;p&gt;我们可以在Clickhouse对威胁进行打标签。如果数据的级别没有达到这个量，可以使用Mysql。&lt;/p&gt;  &lt;p&gt;其实ES同样可以实现索引的SQL查询。&lt;/p&gt;  &lt;p&gt;                &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;第三层.输出层:&lt;/strong&gt;数据准备就位以后，可以用各种手段分析、展示、报警数据，可能根据偏向技术栈，使用开源的解决方案，比如商业BI分析工具superset等。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;沙漏模式就是将数据由多变少，人肉一天处理几万报警，是处理不过来的。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;0x05 流模式威胁处理模型&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;img height="388" width="690"&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;图3.威胁分析处理流模型&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;/p&gt;  &lt;p&gt;使用ES收集数据的几个好处，如果结构化数据库相关于“定长表”来说，
 
ES的储存是一种“变长表”，数据的“字段”可以灵活的增加或是减少。当输入段的数据结构发生变化时，数据结构不用频繁变更字段的定义，不用频繁的修改表结构。利用这种灵活性，可以在这个阶段对数据进行整形处理，数据的维护成本会降低。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;采用 ClickHouse与MySQL数据库是为了结构化查询，能用SQL解决的问题，其实不用再多写很多的脚本，可减少脚本编写量，SQL本身可以当成很强大的DSL使用，对于主机审计应用OSQuery来说，支持SQL审计也是一种提高审计效率的方法。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;0x06 威胁数据处理过滤模式(PULL、PUSH)&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;img height="389" width="690"&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;图4.传统威胁处理模型A&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;面对各种分类的海量数据，如何进行数据处理？&lt;/p&gt;  &lt;p&gt;方法一个个针对性的处理。从历史发展迭代出来，基本可以归类的模式有2种，实际的威胁分析应用，本质上就是两大操作：&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;1.单数据流的威胁垂直多重威胁判定确认。&lt;/p&gt;  &lt;p&gt;2.多分析模块间的威胁数据的横向比较关联。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;A/B模式数据采集与处理过程    &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;1.PULL模式:&lt;/strong&gt;分析服务主动拉取各威胁分析模块的威胁报警信息数据，集中监听模式分析。需要把各种报警，分表异结构存储。（多表异构）&lt;/p&gt;  &lt;p&gt;                 &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;2.PUSH模式&lt;/strong&gt;：各威胁过滤模块，针对不同的报警进行垂直过滤后，将过滤后的数据&lt;/p&gt;  &lt;p&gt;按同样的结构推送到，集中的威胁数据表中。（单表同构）&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;img height="389" width="690"&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;图5.传统威胁处理模型B&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;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;A/B模式的优缺点对比&lt;/strong&gt; &lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;PULL处理模式&lt;/strong&gt;：&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;优点&lt;/strong&gt;：快速审计分析，PULL模式最快，不同分析模块间的威胁数据互相不干扰，处理异构数据，操作很多关联数据，但是对单威胁数据流审计，没有那些关联数据操作。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;缺点&lt;/strong&gt;：数据不集中，相对不利于统计，要进行各种SQL和脚本的关联。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;PUSH处理模式&lt;/strong&gt;：&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;优点&lt;/strong&gt;：如果单Stream数据流过滤之后，多准备一份数据处理，把报警威胁信息过滤后，本地存一份，在集中表中再存储一份同构数据。之后统计威胁关联，只操作一份数据就可以了，减少了关联数据的多次操作。&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;strong&gt;0x07  碰撞表:威胁检测模式&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;    &lt;img height="387" width="690"&gt;&lt;/img&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;图6.威胁分析碰撞表模型&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;如果我们采用了PUSH模式，将各种数据收集，我们就可以对不同标签来源数据进行整合。在威胁数据被格式化之前，我们都是针对不同的威胁数据进行了一定程度的垂直过滤。然后把可能是真的威胁，放入我们的中心威胁情报表结构：&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;strong&gt;所谓碰撞表，就是能过建立一个统一属性结构的威胁报警二维关系表，将不同设备和服务的报警数据集中存储，根据威胁情报在表中，重复次数的多少，威胁等级的高低，综合累计威胁事件的多寡，来判断威胁严重性。&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt; &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;简单说，同一个IP有多个威胁事件发生的越多，并且情报源来自不同服务和设备，威胁越大。&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;PULL的模式是对数据进行关联，通过脚本读取结构数据关联，通过表关联。   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;而在PUSH处理模式下生成的集中碰撞表，是按威胁共通属性进行威胁信息集中的，无论是什么类型的威胁那都是威胁，区别在于威胁级别和威胁分析有来源不一样，如果我们在碰撞表中，发现同一个IP多次出现，来自不同的威胁分析模块，而且威胁的级别还很高。各种威胁事件发生都这个IP相关，就需要关注一下这个IP。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;我们对不同的威胁级别打分，并对同一IP累计分数，最后得出一个分数， 最后根据得分的高低，匹配不同的处理级别，报警级别。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;攻击者的情报，我们可以在积累的内外部威胁情报中， 寻找回溯历史数据。被攻击者的情报， 我们可以在CMDB资产系统中，找到资产对应的责任人。将爆破表中的威胁情报，进行分类、统计、可视化给安全运维人员做报警提示。&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;0x08总结&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;不同规模的环境中   &lt;strong&gt;：    &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;输入层：&lt;/strong&gt;输入源的收集数据信息的多寡，数据量大小。   &lt;strong&gt;    &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;处理层：&lt;/strong&gt;对数据分析处理逻辑复杂程度。   &lt;strong&gt;    &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;strong&gt;输出层&lt;/strong&gt;，提示的多样性。   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;综合起来决定的防护系统防护能力与构建成本。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;过去我们在运用ES和ClickHouse大数据工具的实践中，迭代演进，总结出了这种沙漏式的威胁处理模型，然后摸索出了一些共通性的内容，这篇没有过多涉及到具体的代码和工具使用方法。&lt;/p&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>dev</category>
      <guid isPermaLink="true">https://itindex.net/detail/60250-%E5%A4%A7%E6%95%B0%E6%8D%AE-%E4%BC%81%E4%B8%9A%E7%BD%91%E7%BB%9C-%E5%8F%91%E7%8E%B0</guid>
      <pubDate>Fri, 27 Dec 2019 00:00:00 CST</pubDate>
    </item>
  </channel>
</rss>

