framework icon indicating copy to clipboard operation
framework copied to clipboard

缓存读取报错:unserialize(): Error at offset 2 of 24544 bytes

Open cffycls opened this issue 1 year ago • 4 comments

所属功能组件

缓存(cache)

ThinkPHP 版本

v6.1.4

操作系统

Debian11

错误信息

    [code] => 8
    [message] => unserialize(): Error at offset 2 of 24544 bytes
    [file] => /www/wwwroot/[project]/vendor/topthink/framework/src/think/cache/Driver.php
    [line] => 262

错误所在片段

    /**
     * 反序列化数据
     * @access protected
     * @param string $data 缓存数据
     * @return mixed
     */
    protected function unserialize($data)
    {
        if (is_numeric($data)) {
            return $data;
        }

        $unserialize = $this->options['serialize'][1] ?? "unserialize";

        return $unserialize($data);
    }

其它说明

或许是因为cache数据量过大,但是没有设置缓存的报错提示。时而出现,暂不确定解决方案

cffycls avatar Sep 06 '24 10:09 cffycls

参考解决方案:

1、可以考虑改用json

<?php

// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------

return [
    // 默认缓存驱动
    'default' => env('cache.driver', 'file'),

    // 缓存连接方式配置
    'stores'  => [
        'file' => [
            // 驱动方式
            'type'       => 'File',
            // 缓存保存目录
            'path'       => '',
            // 缓存前缀
            'prefix'     => '',
            // 缓存有效期 0表示永久缓存
            'expire'     => 86400 * 7,
            // 缓存标签前缀
            'tag_prefix' => 'tag:',
            // 序列化机制 例如 ['serialize', 'unserialize']
            'serialize'  => ['json_encode', 'json_decode'],
        ],
    ]
];

2、自定义函数,重新封装下序列化函数

<?php

// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------

function myUnserialize(...$vars) {
    try {
        return unserialize(...$vars);
    } catch(\Throwable $e) {
        return null;
    }
}

return [
    // 默认缓存驱动
    'default' => env('cache.driver', 'file'),

    // 缓存连接方式配置
    'stores'  => [
        'file' => [
            // 驱动方式
            'type'       => 'File',
            // 缓存保存目录
            'path'       => '',
            // 缓存前缀
            'prefix'     => '',
            // 缓存有效期 0表示永久缓存
            'expire'     => 86400 * 7,
            // 缓存标签前缀
            'tag_prefix' => 'tag:',
            // 序列化机制 例如 ['serialize', 'unserialize']
            'serialize'  => ['serialize', 'myUnserialize'],
        ],
    ]
];

big-dream avatar Sep 13 '24 01:09 big-dream

框架层面感觉可以捕抓到异常时,删除缓存,然后返回默认值。但这样会导致开发者不知道这块有异常(自定义序列化机制时)

big-dream avatar Sep 13 '24 01:09 big-dream

支持,框架层面可以处理一下。增加一个配置项,当读取缓存错误时,是抛出源异常还是视为缓存数据不存在。 我在使用workerman多进程,使用到数据库和缓存这部分时,经常遇到这个报错,有时候刚启动项目会有出错。改用redis也不会有改善。

augushong avatar Sep 21 '24 07:09 augushong

我也遇到过这个问题 经过调试发现问题出在vendor\topthink\framework\src\think\cache\driver\Redis.php. 不同进程用同一个hander就会出现, 所以临时修改增加 static protected array $instance = []; //redis实例化时静态变量,防止fork多进程后数据污染 微信截图_20241007115518

xieyongfa123 avatar Oct 07 '24 03:10 xieyongfa123

https://github.com/top-think/framework/commit/5ee69f53eb519aae874c7e48b97c61b3998a7e3b

big-dream avatar Dec 20 '24 08:12 big-dream