5 分钟 – 永夜 https://www.shuijingwanwq.com 没有不值得去解决的问题,也没有不值得去学习的技术! Sun, 17 May 2026 05:25:30 +0000 zh-Hans hourly 1 https://wordpress.org/?v=7.0 行业资讯页面缓存未及时更新的排查分析 https://www.shuijingwanwq.com/2025/08/26/9281/ https://www.shuijingwanwq.com/2025/08/26/9281/#respond Tue, 26 Aug 2025 01:46:16 +0000 https://www.shuijingwanwq.com/?p=9281 Post Views: 163 1、行业资讯页面缓存未及时更新 。当后台添加了新的文章后,前台的列表页面未及时更新,总是需要等上 5 分钟后才更新,感觉页面缓存的依赖未生效。后台的最新的两篇文章未同步在前台更新。如图1
行业资讯页面缓存未及时更新 。当后台添加了新的文章后,前台的列表页面未及时更新,总是需要等上 5 分钟后才更新,感觉页面缓存的依赖未生效。后台的最新的两篇文章未同步在前台更新。

图1

2、但是同样的程序在本地环境是正常可用的。仔细分析差异,发现生产环境的后台的文章的更新时间要较之北京时间 早 8 小时。如果 updated_at 存的是 UTC 时间(即比北京时间晚 8 小时),而你用的是北京时间做判断(比如看页面没更新),会出现: 数据实际已更新(北京时间 15:30), 但 updated_at 是 2025-06-05 07:30:25(UTC), 所以缓存判断依赖的 MAX(updated_at) 没变化,页面继续用旧缓存。


public function behaviors()
    {
        $request = Yii::$app->request;
        $alias = $request->get('alias');
        $id = $request->get('id');
        $categoryId = (int)$request->get('c', 0);
        $keyword = trim($request->get('k'));
        $tag = $request->get('tag');
        $page = (int)$request->get('page', 1);

        $detect = new MobileDetect();
        $isMobile = $detect->isMobile() ? PageElementType::DEVICE_TYPE_MOBILE : PageElementType::DEVICE_TYPE_PC;

        $behaviors = [];

        // view 页面缓存
        if (!empty($alias)) {
            $dependency = new DbDependency([
                'sql' => 'SELECT updated_at FROM articles WHERE alias = :alias LIMIT 1',
                'params' => [':alias' => $alias],
            ]);
        } elseif (!empty($id)) {
            $dependency = new DbDependency([
                'sql' => 'SELECT updated_at FROM articles WHERE id = :id LIMIT 1',
                'params' => [':id' => $id],
            ]);
        } else {
            $dependency = null;
        }

        $behaviors['pageCacheView'] = [
            'class' => PageCache::class,
            'only' => ['view'],
            'duration' => 300,
            'variations' => [$id, $alias, $isMobile],
            'dependency' => $dependency,
            'cache' => 'fileCache',
        ];

        // index 页面缓存,仅当无关键词和标签时启用
        if ($keyword === '' && empty($tag)) {

            $category = null;
            if (!empty($alias) && UrlHelper::isValidAlias($alias)) {
                $category = Yii::$app->db->cache(fn() => ArticleCategory::find()
                    ->where(['alias' => $alias, 'status' => CommonArticleCategory::STATUS_NORMAL])
                    ->limit(1)
                    ->one(), 300);
            } elseif (!empty($categoryId)) {
                $category = Yii::$app->db->cache(fn() => ArticleCategory::find()
                    ->where(['id' => $categoryId, 'status' => CommonArticleCategory::STATUS_NORMAL])
                    ->limit(1)
                    ->one(), 300);
            }

            if ($category !== null) {
                // 有分类筛选,仅依赖该分类的文章更新时间
                $indexDependency = new DbDependency([
                    'sql' => 'SELECT MAX(updated_at) FROM articles WHERE status = 1 AND category_id = :categoryId',
                    'params' => [':categoryId' => $category->id],
                ]);
            } else {
                // 无分类筛选,才依赖全表(不建议再进一步切分,否则复杂度会上升)
                $indexDependency = new DbDependency([
                    'sql' => 'SELECT MAX(updated_at) FROM articles WHERE status = 1',
                ]);
            }

            $behaviors['pageCacheIndex'] = [
                'class' => PageCache::class,
                'only' => ['index'],
                'duration' => 300,
                'variations' => [
                    $categoryId,
                    $alias,
                    $page,
                    $isMobile,
                ],
                'dependency' => $indexDependency,
                'cache' => 'fileCache',
            ];
        }

        return $behaviors;
    }


3、查看 php.ini 中的时区设置,其与 date.timezone = Asia/Shanghai 是等效的。决定修改为 date.timezone = Asia/Shanghai


date.timezone = PRC


4、设置 MySQL 连接时区,确保你的 PHP 连接数据库时设置了时区为 +08:00。在 Yii2 中可以这样做:


'components' => [
    'db' => [
        // ... 其他配置
        'on afterOpen' => function($event) {
            $event->sender->createCommand("SET time_zone = '+08:00'")->execute();
        },
    ],
],


5、编辑一篇文章后,其更新时间已经是北京时区。如图2
编辑一篇文章后,其更新时间已经是北京时区

图2

]]>
https://www.shuijingwanwq.com/2025/08/26/9281/feed/ 0
对接微信第三方平台,修复1天内,其中存在1个小时,令牌不可用的情况。重新调整后的规则,在保证令牌绝对永久有效的情况下,尽量减少获取令牌的 HTTP 请求次数 https://www.shuijingwanwq.com/2021/07/05/5020/ https://www.shuijingwanwq.com/2021/07/05/5020/#respond Mon, 05 Jul 2021 03:18:11 +0000 https://www.shuijingwanwq.com/?p=5020 Post Views: 82 1、现阶段对接微信第三方平台的实现,在 接收验证票据(接收微信服务器推送) 的接口中,会判断 令牌(component_access_token) 在 Redis 中是否存在,如果不存在,则获取令牌(HTTP 请求)。相当于将微信服务器间隔 10分钟 的推送,当做了定时命令使用。具体情况基于时间顺序如下所示:


11:25 获取验证票据(component_verify_ticket)

11:25 获取并生成令牌(component_access_token),存储至 Redis,设置过期时间:13:20

13:15 获取验证票据,不会存储至 Redis

13:20 令牌过期

13:25 获取验证票据,存储至 Redis

结论:在 13:20 - 13:25 之间,这 5 分钟以内,微信的令牌不存在,则微信发布不可用。


2、重新调整后的规则,在保证令牌绝对永久有效的情况下,尽量减少获取令牌的 HTTP 请求次数。具体情况基于时间顺序如下所示:
<pre class="wp-block-syntaxhighlighter-code">

11:25 获取验证票据(component_verify_ticket)

11:25 获取并生成令牌(component_access_token),添加字段:有效截止时间(13:25),存储至 Redis

13:05 判断规则:有效截止时间(13:25) - 20分钟 < 13:05。结果为假,不会获取令牌,不会存储至 Redis

13:15 判断规则:有效截止时间(13:25) - 20分钟 < 13:15。结果为真,获取令牌,添加字段:有效截止时间(15:15),存储至 Redis。备注:此时令牌数据已变化,只要执行获取令牌的 HTTP 请求,则会生成新的令牌

13:25 判断规则:有效截止时间(15:15) - 20分钟 < 13:25。结果为假,不会获取令牌,不会存储至 Redis

结论:
1、官方建议在 1小时50分 后重新获取令牌。渠道发布在 1小时40分 后就开始判断是否要重新获取令牌。即在2个小时内,以确保在 1小时50分 后重新获取令牌。
2、官方的验证票据(component_verify_ticket)的推送,平均间隔 10分钟,但是实际上存在 30秒 左右的误差。以下是官方的验证票据(component_verify_ticket)的推送的请求参数的时间戳与转换后普通时间:
1625109905 2021-07-01 11:25:05
1625196309 2021-07-02 11:25:09
1625205285 2021-07-02 13:54:45
1625222097 2021-07-02 18:34:57
3、在 13:05、13:15 的时间点,皆有可能重新获取令牌。

</pre>
3、查看每一次获取令牌的 HTTP 请求的具体时间点。如图1
查看每一次获取令牌的 HTTP 请求的具体时间点

图1



-rw-r--r-- 1 nginx nginx  231 Jul  2 18:15 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625220904.5864-1284321044.txt
-rw-r--r-- 1 nginx nginx  231 Jul  2 20:05 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625227518.8292-2034263273.txt
-rw-r--r-- 1 nginx nginx  231 Jul  2 21:54 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625234060.9016-2037842134.txt
-rw-r--r-- 1 nginx nginx  231 Jul  2 23:34 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625240074.6086-129234930.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 01:24 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625246642.1858-1357575717.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 03:04 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625252663.3032-96333903.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 04:53 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625259239.382-1358398298.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 06:34 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625265273.2847-949998836.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 08:14 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625271273.5153-1059028888.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 09:54 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625277298.7813-310601964.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 11:44 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625283877.9521-412669108.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 13:24 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625289886.807-2092152976.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 15:14 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625296463.0599-1080955996.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 16:54 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625302484.4032-1651010868.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 18:44 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625309067.7121-1067986815.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 20:24 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625315074.8086-1306110047.txt
-rw-r--r-- 1 nginx nginx  231 Jul  3 22:14 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625321659.2166-403019843.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 00:04 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625328259.0217-93337953.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 01:44 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625334265.2403-81093374.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 03:34 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625340861.6377-119559848.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 05:14 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625346863.7426-1003494675.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 06:54 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625352868.7146-1351258397.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 08:34 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625358895.2811-350216025.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 10:15 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625364905.1292-483282692.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 12:05 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625371510.5863-1975502382.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 13:54 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625378081.9596-379002381.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 15:34 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625384084.4452-1094694829.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 17:14 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625390088.3557-588511027.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 19:05 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625396707.8423-1886295111.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 20:54 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625403282.8031-1069721276.txt
-rw-r--r-- 1 nginx nginx  231 Jul  4 22:44 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625409877.6077-1660123114.txt
-rw-r--r-- 1 nginx nginx  231 Jul  5 00:34 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625416464.5966-45554414.txt
-rw-r--r-- 1 nginx nginx  231 Jul  5 02:23 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625423039.146-1550811908.txt
-rw-r--r-- 1 nginx nginx  231 Jul  5 04:04 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625429059.9922-66909225.txt
-rw-r--r-- 1 nginx nginx  231 Jul  5 05:54 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625435642.6323-187433523.txt
-rw-r--r-- 1 nginx nginx  231 Jul  5 07:34 frontend-controllers-WxMsgEventController-componentAccessTokenData-1625441682.8374-716247506.txt


4、在总计 45 次的请求中,大部分的调用平均间隔 1小时50分 左右(28次),小部分的调用平均间隔 1小时40分 左右(17次)。


1小时50分:
18:15 - 20:05
20:05 - 21:54
23:34 - 01:24
03:04 - 04:53
09:54 - 11:44
13:24 - 15:14
16:54 - 18:44
20:24 - 22:14
22:14 - 00:04
01:44 - 03:34
10:15 - 12:05
12:05 - 13:54
17:14 - 19:05
19:05 - 20:54
20:54 - 22:44
22:44 - 00:34
00:34 - 02:23
04:04 - 05:54

1小时40分:
21:54 - 23:34
01:24 - 03:04
04:53 - 06:34
06:34 - 08:14
08:14 - 09:54
11:44 - 13:24
15:14 - 16:54
18:44 - 20:24
00:04 - 01:44
03:34 - 05:14
05:14 - 06:54
06:54 - 08:34
08:34 - 10:15
13:54 - 15:34
15:34 - 17:14
02:23 - 04:04
05:54 - 07:34


5、查看其响应的内容。 抽样:20:05、21:54、23:34。其响应的访问令牌的过期截止时间分别为:2021-07-02 22:05:18、2021-07-02 23:54:20、2021-07-03 01:34:34。符合预期。如图2
查看其响应的内容。 抽样:20:05、21:54、23:34。其响应的访问令牌的过期截止时间分别为:2021-07-02 22:05:18、2021-07-02 23:54:20、2021-07-03 01:34:34。符合预期

图2



[root@api-7f9d76b849-kckxz runtime]# cat frontend-controllers-WxMsgEventController-componentAccessTokenData-1625227518.8292-2034263273.txt
Array
(
    [component_access_token] => 46_yRwzjrgTGzx94RykB9pycN-nlEXnvYQNSbXC0gfWJ9b091k-wLhFgyeZTIovEIVVJpWvBk4em_byyQrNzfxjjMGj6mKfz-tKHWUKJmxGZDA02t5rdWOvcaYez7EmRZYJ6szrAR4qcHDHeXgPZTXjAGAEYC
    [expires_at] => 1625234718
)
[root@api-7f9d76b849-kckxz runtime]# cat frontend-controllers-WxMsgEventController-componentAccessTokenData-1625234060.9016-2037842134.txt
Array
(
    [component_access_token] => 46_2hBMmx4Ww0pMYSsLCun4EW80WOcNHUMrOE0i-niX0599OTCi5xOHw5yrJ3It7Um9tyXt9x3MiGuazXgPLAXKUP-3WMIO9Du8ECPk4nM8Ls_iKOGGLrn5QAyGlXueXI4d8glGjPexUdFi53iSERYdAFALYF
    [expires_at] => 1625241260
)
[root@api-7f9d76b849-kckxz runtime]# cat frontend-controllers-WxMsgEventController-componentAccessTokenData-1625240074.6086-129234930.txt
Array
(
    [component_access_token] => 46_FfM2ZagUut2Z33lVf-PZrUzKrauKTrMU4EcDjZ39sIB3B6RmbKKTNqWfioZgpSEubmUkQEF3foT6gUO5JR-ILanvR8zF7eafBgKh22CRFX8yLcGEMlPDw9zVJPiXWt774FVh2H-u5oV1taXJGQVhAHANXC
    [expires_at] => 1625247274
)
[root@api-7f9d76b849-kckxz runtime]# 


6、最终将 20分钟 调整为 25分钟,即在2个小时内,以确保在 1小时40分 后重新获取令牌。如果获取失败,还可以继续在 1小时50分 后重新获取令牌。即总计 2 次机会。容错性更强。]]>
https://www.shuijingwanwq.com/2021/07/05/5020/feed/ 0