bgwriter 的睡眠时间差异
开始
简单说就是一开始启动的很频繁(200ms 级),后来没有什么事情可做,就懒惰了。变成了 10秒级别。
实际验证如下
postgresql.conf 中和 log 相关部分:
log_line_prefix = '%m' log_min_messages = info logging_collector = off
对 bufmgr.c 的 BgBufferSync的调试:
bool BgBufferSync(void) { …… /* Execute the LRU scan */ while (num_to_scan > 0 && reusable_buffers < upcoming_alloc_est) { //added by gaojian fprintf(stderr,"num_to_scan is: %d \n",num_to_scan); int buffer_state = SyncOneBuffer(next_to_clean, true); if (++next_to_clean >= NBuffers) { next_to_clean = 0; elog(INFO,"------------------next_passes++.\n"); next_passes++; } num_to_scan--; if (buffer_state & BUF_WRITTEN) { reusable_buffers++; if (++num_written >= bgwriter_lru_maxpages) { BgWriterStats.m_maxwritten_clean++; break; } } else if (buffer_state & BUF_REUSABLE) reusable_buffers++; } elog(INFO,".......BgBufferSync Called."); /* Return true if OK to hibernate */ return (bufs_to_lap == 0 && recent_alloc == 0); }
运行的结果是:
[作者:技术者高健@博客园 mail: luckyjackgao@gmail.com ]
[postgres@localhost bin]$ ./postgres -D /usr/local/pgsql/data 2012-11-02 16:09:55.139 CSTLOG: database system was shut down at 2012-11-02 16:01:26 CST saved_info_valid false. 2012-11-02 16:09:55.199 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:09:55.199 CSTLOG: autovacuum launcher started 2012-11-02 16:09:55.201 CSTLOG: database system is ready to accept connections 2012-11-02 16:09:55.399 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:09:55.599 CSTINFO: .......BgBufferSync Called. …… 2012-11-02 16:12:11.350 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:12:11.550 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:12:11.751 CSTINFO: ------------------next_passes++. 2012-11-02 16:12:11.751 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:12:11.951 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:12:12.151 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:12:22.360 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:12:32.568 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:12:42.777 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:12:52.985 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:13:03.194 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:13:13.403 CSTINFO: .......BgBufferSync Called. 2012-11-02 16:13:23.614 CSTINFO: .......BgBufferSync Called.
bgwriter 会在循环中 睡眠-->醒来->调用BgBufferSync-->睡眠。
基本上,其睡眠应该分”浅睡眠“和”深睡眠“
再回头来看 bgwriter.c 的代码:
/* * GUC parameters */ int BgWriterDelay = 200; /* * Multiplier to apply to BgWriterDelay when we decide to hibernate. * (Perhaps this needs to be configurable?) */ #define HIBERNATE_FACTOR 50 …… /* * Main entry point for bgwriter process * * This is invoked from AuxiliaryProcessMain, which has already created the * basic execution environment, but not enabled signals yet. */ void BackgroundWriterMain(void) { …… /* * Loop forever */ for (;;) { …… /* * Sleep until we are signaled or BgWriterDelay has elapsed. * * Note: the feedback control loop in BgBufferSync() expects that we * will call it every BgWriterDelay msec. While it's not critical for * correctness that that be exact, the feedback loop might misbehave * if we stray too far from that. Hence, avoid loading this process * down with latch events that are likely to happen frequently during * normal operation. */ rc = WaitLatch(&MyProc->procLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, BgWriterDelay /* ms */ ); /* * If no latch event and BgBufferSync says nothing's happening, extend * the sleep in "hibernation" mode, where we sleep for much longer * than bgwriter_delay says. Fewer wakeups save electricity. When a * backend starts using buffers again, it will wake us up by setting * our latch. Because the extra sleep will persist only as long as no * buffer allocations happen, this should not distort the behavior of * BgBufferSync's control loop too badly; essentially, it will think * that the system-wide idle interval didn't exist. * * There is a race condition here, in that a backend might allocate a * buffer between the time BgBufferSync saw the alloc count as zero * and the time we call StrategyNotifyBgWriter. While it's not * critical that we not hibernate anyway, we try to reduce the odds of * that by only hibernating when BgBufferSync says nothing's happening * for two consecutive cycles. Also, we mitigate any possible * consequences of a missed wakeup by not hibernating forever. */ if (rc == WL_TIMEOUT && can_hibernate && prev_hibernate) { /* Ask for notification at next buffer allocation */ StrategyNotifyBgWriter(&MyProc->procLatch); /* Sleep ... */ rc = WaitLatch(&MyProc->procLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, BgWriterDelay * HIBERNATE_FACTOR); /* Reset the notification request in case we timed out */ StrategyNotifyBgWriter(NULL); } …… } }
可以看到,一开始是睡 BgWriterDelay 就会醒。
然后,睡了若干次再醒后,如果发现 (rc == WL_TIMEOUT && can_hibernate && prev_hibernate) 得到了满足。
那么, 就进入新的睡眠模式:
/* Sleep ... */
rc = WaitLatch(&MyProc->procLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
BgWriterDelay * HIBERNATE_FACTOR);
最后一个参数变成了 BgWriterDelay * HIBERNATE_FACTOR 正好等于 10秒。
[作者:技术者高健@博客园 mail: luckyjackgao@gmail.com ]
结束