说明:以下代码均在php56以上,Yii2框架环境下
有时候会遇到这种情况,明明设置了缓存,memcache什么的设置都ok,但是就是没有起效果,每次都是直接去数据库拿数据。这个时候就应该考虑,是不是数据量超出了memcache的最大限制【这个限制跟对应的memcache有关,可以通过配置重新编译更改大小,默认是1M】
一般情况下是不建议更改memcache的默认配置,原因1,你无法预测哪些少数数据量超大的数据,后续会继续增长到什么程度,有时候有些可能会到几十甚至上百M。原因2,可以参考这篇文章https://blog.csdn.net/u011386690/article/details/9316545
我们可以在程序层面去实现将缓存数据分片,以下提供一个demo
class CacheUtil
{
const KEY_PREFIX = __CLASS__;
const KEY_SLICE = 'slice';
const KEY_INFO = 'info';
/** @const int 当个value最大长度 1000kb 避免1M出现临界值无法set进去 */
const MAX_LENGTH = 1024000;
const KEY_COMPRESS = 'cacheCompress';
const KEY_COMPRESS_LEVEL = 'cacheCompressLevel';
private static $cache = null;
/** @var $compress bool 是否开启压缩数据 针对分片 不分片默认使用缓存内部的压缩策略 */
private static $compress = null;
private static $compressLevel = null;
private static function getCache()
{
return empty(self::$cache) ? self::$cache = \Yii::$app->getCache() : self::$cache;
}
public static function set($key, $value, $sliceFlag = false, $duration = null)
{
$cache = self::getCache();
if (!$sliceFlag) {
return $cache->set($key, $value, $duration);
}
$value = serialize($value);
if (self::getCompress()) {
$value = gzcompress($value, self::getCompressLevel());
}
$len = strlen($value);
$size = ceil($len / self::MAX_LENGTH);
$info = [
'size' => $size,
'compress' => self::getCompress(),
];
$infoKey = self::getInfoKey($key);
if (!$cache->set($infoKey, $info, $duration)) {
return false;
}
// 分片存储
for ($i = 0; $i < $size; $i++) {
$sliceKey = self::getSliceKey($key, $i);
$startIndex = $i * self::MAX_LENGTH;
$_value = substr($value, $startIndex, self::MAX_LENGTH);
if (!$cache->set($sliceKey, $_value, $duration)) {
return false;
}
unset($_value);
}
return true;
}
public static function get($key, $sliceFlag = false)
{
$cache = self::getCache();
if (!$sliceFlag) {
// 不分片
return $cache->get($key);
}
$infoKey = self::getInfoKey($key);
$info = $cache->get($infoKey);
if (empty($info)) {
return false;
}
$value = '';
$size = $info['size'];
for ($i = 0; $i < $size; $i++) {
$sliceKey = self::getSliceKey($key, $i);
$_value = $cache->get($sliceKey);
if (empty($_value)) {
return false;
}
$value .= $_value;
unset($_value);
}
if ($info['compress']) {
$value = gzuncompress($value);
}
return unserialize($value);
}
private static function getInfoKey($key)
{
return self::KEY_PREFIX . $key . self::KEY_INFO;
}
private static function getSliceKey($key, $slice)
{
return self::KEY_PREFIX . $key . self::KEY_SLICE . $slice;
}
private static function getCompress()
{
if (self::$compress === null) {
$params = \Yii::$app->params;
if (isset($params[self::KEY_COMPRESS])) {
self::$compress = $params[self::KEY_COMPRESS];
} else {
// 默认打开压缩
self::$compress = true;
}
}
return self::$compress;
}
private static function getCompressLevel()
{
if (self::$compressLevel === null) {
$params = \Yii::$app->params;
if (isset($params[self::KEY_COMPRESS_LEVEL])) {
self::$compressLevel = $params[self::KEY_COMPRESS_LEVEL];
} else {
// 使用默认压缩级别
self::$compressLevel = -1;
}
}
return self::$compressLevel;
}
}
代码大部分情况下是跟Yii2框架无关,除了获取缓存操作对象以及一些基本配置是使用yii2的写法以外,其他的都是通用的
网友评论