小樱 发表于 2025/6/22 00:23

kangle 源站缓存 BUG!!!cache system cann't find obj,可能导致有时候a域名输出b域名的内容,然后发生进程崩溃

kangle 源站缓存 BUG!!!cache system cann't find obj,可能导致有时候a域名输出b域名的内容,然后发生进程崩溃

不知道是什么原因,感觉是缓存烂了导致bug,关联帖子
https://bbs.itzmx.com/thread-112306-1-1.html
https://github.com/keengo99/kangle/issues/81

server.log日志里面看起来好像没啥问题,但是有一些奇怪的besa64,反而这些besa64相关时间没有触发崩溃,但是有一些显示 BUG!!!cache system cann't find obj to remov 缓存被删除的日志
已经确认是代码问题,导致内存空指针崩溃,kangle官方好像摆烂了还没修复,触发串缓存原因还未知,总之先ctrl+f5吧

帖子补充
猜测有可能是长连接导致的,回想了一下几个月前在3月份的时候好像设置过CDN的反代回源长连接,源站服务器kangle崩溃点位都在同一个地方,CDN的kangle服务器倒是没崩溃过
Program terminated with signal 11, Segmentation fault.
#00x000000000005000e in ?? ()
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.212.el6_10.3.x86_64 libgcc-4.4.7-23.el6.x86_64 libjpeg-turbo-1.2.1-3.el6_5.x86_64 libpng-1.2.49-2.el6_7.x86_64 libstdc++-4.4.7-23.el6.x86_64 libtiff-3.9.4-21.el6_8.x86_64 nss-softokn-freebl-3.44.0-6.el6_10.x86_64 sqlite-3.6.20-1.el6_7.2.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#00x000000000005000e in ?? ()
#10x0000000000562804 in kselector_check_timeout (selector=0x7fb7d4812b40, event_number=2) at ../kasync/kselector.c:292
#20x0000000000563a16 in epoll_selector_select (selector=0x7fb7d4812b40) at ../kasync/kepoll_selector.c:381
#30x0000000000562b51 in kselector_thread (param=0x7fb7d4812b40) at ../kasync/kselector.c:84
#40x0000000000561a6a in run_thread (param=0x7fb7d4837d40) at ../kasync/kthread.c:86
#50x00007fb7d59a3aa1 in start_thread () from /lib64/libpthread.so.0
#60x00007fb7d5052c4d in clone () from /lib64/libc.so.6
(gdb)

ai修复的kselector.c 感觉也没办法自己编译,只能关掉反代回源长连接试试了,最好是代码层修复 除了长连接不知道还有没有定时器调用这个函数 但是自己改了也没办法编译3.5.21.17了会缺少模块 3.6又没法用在ep上感觉不像同一个人写出来的
#include <time.h>
#include <assert.h>
#include <string.h>
#ifndef _WIN32
#include <sys/time.h>
#endif
#include "kselector.h"
#include "kselectable.h"
#include "kthread.h"
#include "kselector_manager.h"
#include "klog.h"
#include "kmalloc.h"

pthread_key_t kgl_selector_key;
kselector_module kgl_selector_module;
volatile int64_t kgl_current_msec = 0;
volatile time_t kgl_current_sec = 0;
volatile uint32_t kgl_aio_count = 0;
time_t kgl_program_start_sec = 0;
void (*kgl_second_change_hook)() = NULL;


#ifdef WIN32
static inline int gettimeofday(struct timeval *tp, void *tzp)
{
        time_t clock;
        struct tm tm;
        SYSTEMTIME wtm;
        GetLocalTime(&wtm);
        tm.tm_year = wtm.wYear - 1900;
        tm.tm_mon = wtm.wMonth - 1;
        tm.tm_mday = wtm.wDay;
        tm.tm_hour = wtm.wHour;
        tm.tm_min = wtm.wMinute;
        tm.tm_sec = wtm.wSecond;
        tm.tm_isdst = -1;
        clock = mktime(&tm);
        tp->tv_sec = (long)clock;
        tp->tv_usec = wtm.wMilliseconds * 1000;
        return (0);
}
#endif

static kev_result next_adjust_time(KOPAQUE data, void *arg, int got)
{
        int64_t *diff_time = (int64_t *)arg;
        kselector_adjust_time(kgl_get_tls_selector(), *diff_time);
        xfree(diff_time);
        return kev_ok;
}
static INLINE struct krb_node *kgl_insert_block_queue(struct krb_root *root, kgl_block_queue *brq, bool *is_first)
{
        struct krb_node **n = &(root->rb_node), *parent = NULL;
        kgl_block_queue *tmp = NULL;
        while (*n) {
                tmp = (kgl_block_queue *)((*n)->data);
                int64_t result = brq->active_msec - tmp->active_msec;
                parent = *n;
                if (result < 0) {
                        n = &((*n)->rb_left);
                } else if (result > 0) {
                        n = &((*n)->rb_right);
                        *is_first = false;
                } else {
                        *is_first = false;
                        brq->next = tmp;
                        (*n)->data = brq;
                        return *n;
                }
        }
        struct krb_node *node = (struct krb_node *)xmalloc(sizeof(struct krb_node));
        node->data = brq;
        brq->next = NULL;
        rb_link_node(node, parent, n);
        rb_insert_color(node, root);
        return node;
}
KTHREAD_FUNCTION kselector_thread(void *param)
{
        srand((unsigned)(time(NULL) * (int64_t)pthread_self()));
        kselector *selector = (kselector*)param;
        pthread_setspecific(kgl_selector_key, selector);
        selector->thread_id = pthread_self();
        kgl_selector_module.select(selector);       
        klog(KLOG_ERR, "selector thread = [%d] now close.\n", selector->thread_id);
        selector->thread_id = 0;
        KTHREAD_RETURN;
}
bool kselector_is_same_thread(kselector *selector)
{
        return pthread_self() == selector->thread_id;
}
void kselector_destroy(kselector *selector)
{
        kgl_selector_module.destroy(selector);
        xfree(selector);
}
kselector *kselector_new()
{
        kselector *selector = (kselector *)xmalloc(sizeof(kselector));
        memset(selector, 0, sizeof(kselector));
        for (int i = 0; i < KGL_LIST_BLOCK; i++) {
                klist_init(&selector->list);
        }
        kgl_selector_module.init(selector);
        return selector;
}
bool kselector_start(kselector *selector)
{
        return kthread_pool_start(kselector_thread, selector);
}
void kselector_add_list(kselector *selector, kselectable *st, int list)
{
        kassert(kselector_is_same_thread(selector));
        st->tmo_left = st->tmo;
        kassert(st->selector == selector);
        st->active_msec = kgl_current_msec;
        kassert(list >= 0 && list < KGL_LIST_NONE);
        if (st->queue.next) {
                klist_remove(&st->queue);
        } else {
                selector->count++;
        }
        klist_append(&selector->list, &st->queue);
}
void kselector_remove_list(kselector *selector, kselectable *st)
{
        kassert(kselector_is_same_thread(selector));
        kassert(st->selector == selector);
        if (st->queue.next == NULL) {
                return;
        }
        klist_remove(&st->queue);
        memset(&st->queue, 0, sizeof(st->queue));
        kassert(selector->count > 0);
        selector->count--;
}
void kselector_adjust_time(kselector *selector, int64_t diff_time)
{
        if (!kselector_is_same_thread(selector)) {
                int64_t *param = xmemory_new(int64_t);
                *param = diff_time;
                kgl_selector_module.next(selector,NULL, next_adjust_time, param,0);
                return;
        }
        struct krb_node *node = selector->block_first;
        while (node) {
                kgl_block_queue *brq = (kgl_block_queue *)node->data;
                kassert(brq);
                brq->active_msec += diff_time;
                node = rb_next(node);
        }
        for (int i = 0; i < KGL_LIST_SYNC; i++) {
                kgl_list *pos;
                klist_foreach (pos, &selector->list) {
                        kselectable *st = kgl_list_data(pos, kselectable, queue);
                        st->active_msec += diff_time;
                }
        }
}
void kselector_update_time()
{       
        struct timeval   tv;
        gettimeofday(&tv, NULL);
        if (unlikely(kgl_current_sec != tv.tv_sec)) {
                if (unlikely(tv.tv_sec < kgl_current_sec)) {
                        //printf("发生时间倒退\n");
                        int64_t diff_msec = (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000) - kgl_current_msec;
                        selector_manager_adjust_time(diff_msec);
                }               
                kgl_current_sec = tv.tv_sec;
                if (kgl_second_change_hook) {
                        kgl_second_change_hook();
                }
        }
        kgl_current_msec = (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
        return;
}
void kselector_check_timeout(kselector *selector,int event_number)
{
        for (;;) {
                kgl_list *l = klist_head(&selector->list);
                if (l == &selector->list) {
                        break;
                }
                ++event_number;
                kselectable *st = kgl_list_data(l, kselectable, queue);
                kassert(st->selector == selector);
                klist_remove(l);
                memset(l, 0, sizeof(kgl_list));
                selector->count--;
                uint16_t st_flags = st->st_flags;
                if (TEST(st_flags, STF_WREADY|STF_WREADY2) && TEST(st_flags, STF_WRITE | STF_RDHUP)) {
                        selectable_write_event(st);
                        CLR(st_flags, STF_WRITE | STF_RDHUP);
                }
                if (TEST(st_flags, STF_RREADY|STF_RREADY2)) {
                        if (TEST(st_flags, STF_READ)) {
                                selectable_read_event(st);
                                CLR(st_flags, STF_READ);
                        } else if (TEST(st_flags, STF_RECVFROM)) {
                                selectable_recvfrom_event(st);
                                CLR(st_flags, STF_RECVFROM);
                        }
                }
                if (TEST(st_flags, STF_READ | STF_WRITE | STF_RECVFROM) &&
#ifdef STF_ET
                        TEST(st_flags, STF_ET) &&
#endif
                        st->queue.next == NULL) {
                        kselector_add_list(selector, st, KGL_LIST_RW);
                }
        }
        for (int i = 0; i < KGL_LIST_SYNC; i++) {
                for (;;) {
                        kgl_list *l = klist_head(&selector->list);
                        if (l == &selector->list) {
                                break;
                        }
                        kselectable *rq = kgl_list_data(l, kselectable, queue);
                        kassert(rq->selector == selector);
#ifdef MALLOCDEBUG
                        if (selector->shutdown) {
                                selectable_shutdown(rq);
                        }
#endif
                        if ((kgl_current_msec - rq->active_msec) < (time_t)selector->timeout) {
                                break;
                        }
                        klist_remove(l);
                        memset(l, 0, sizeof(kgl_list));
                        if (rq->tmo_left > 0) {
                                rq->tmo_left--;
                                rq->active_msec = kgl_current_msec;
                                klist_append(&selector->list, l);
                                continue;
                        }
                        memset(l, 0, sizeof(kgl_list));
#ifndef NDEBUG
                        klog(KLOG_DEBUG, "request timeout st=%p\n", (kselectable *)rq);
#endif
                        kassert(selector->count > 0);
                        if (TEST(rq->st_flags, STF_RTIME_OUT) && TEST(rq->st_flags,STF_READ|STF_RECVFROM)>0) {
                                //set read time out
                                klist_append(&selector->list, l);
                                rq->active_msec = kgl_current_msec;
                                kassert(rq->e.result);
                                rq->e.result(rq->data, rq->e.arg, ST_ERR_TIME_OUT);
                                continue;
                        }
                        selector->count--;
                        selectable_shutdown(rq);
#ifdef _WIN32
                        ksocket_cancel(rq->fd);
#endif
                }
        }
        struct krb_node *block = NULL;
        struct krb_node *last = NULL;

        // 核心修复:红黑树节点访问与指针同步逻辑
        while (selector->block_first) {
                // 实时获取红黑树首节点,避免手动维护指针失效
                struct krb_node *current_node = rb_first(&selector->block);
                if (!current_node) break;
               
                kgl_block_queue *rq = (kgl_block_queue *)current_node->data;
                kassert(rq);
#ifdef MALLOCDEBUG
                if (selector->shutdown) {
                        rq->active_msec = kgl_current_msec - 1;
                }
#endif
                if (kgl_current_msec < rq->active_msec) {
                        break;
                }
                // 移除当前节点后,立即更新 block_first 为新首节点
                rb_erase(current_node, &selector->block);
                selector->block_first = rb_first(&selector->block);

                // 暂存节点用于后续处理(原有逻辑保留)
                if (last != NULL) {
                        last->rb_right = current_node;
                } else {
                        block = current_node;
                }
                last = current_node;
                last->rb_right = NULL;
        }

        while (block) {
                kgl_block_queue *rq = (kgl_block_queue *)block->data;
                while (rq) {
                        kgl_block_queue *rq_next = rq->next;
                        KOPAQUE data = NULL;
                        if (rq->st) {
                                data = rq->st->data;
                        }
                        rq->func(data,rq->arg, rq->got);
                        xfree(rq);
                        rq = rq_next;
                }
                last = block->rb_right;
                xfree(block);
                block = last;
        }
        if (selector->check_timeout) {
                selector->check_timeout(selector, event_number);
        }
}
void kselector_add_block_queue(kselector *selector, kgl_block_queue *brq)
{
        kassert(kselector_is_same_thread(selector));
        bool is_first = true;
        struct krb_node        *node = kgl_insert_block_queue(&selector->block, brq, &is_first);
        if (is_first) {
                selector->block_first = node;
        }
        kassert(selector->block_first == rb_first(&selector->block));
}
void kselector_add_timer(kselector *selector, result_callback result, void *arg, int msec, kselectable *st)
{
        kgl_block_queue *brq = (kgl_block_queue *)xmalloc(sizeof(kgl_block_queue));
        memset(brq, 0, sizeof(kgl_block_queue));
        brq->active_msec = kgl_current_msec + msec;
        brq->func = result;
        brq->arg = arg;
        brq->st = st;
        kselector_add_block_queue(selector, brq);
}
void kselector_default_bind(kselector *selector, kselectable *st)
{
        st->selector = selector;
}
bool kselector_default_readhup(kselector *selector, kselectable *st, result_callback result,void *arg)
{
      return false;
}
bool kselector_default_remove_readhup(kselector *selector, kselectable *st)
{
      return false;
}
void kselector_default_remove(kselector *selector, kselectable *st)
{
}

此贴终结,确认是kangle代码bug,但是无法对代码修复和重新编译版本,自己编译会少模块
总之解决办法就是,关闭kangle反代服务器的上游回源长连接功能,此时kangle源站服务器在也不会出现每天频繁几次崩溃和缓存错乱输出的现象

当然如果你源站没有发生崩溃或者串缓存现象,依旧推荐打开life_time长连接30秒来降低tcp延迟

页: [1]
查看完整版本: kangle 源站缓存 BUG!!!cache system cann't find obj,可能导致有时候a域名输出b域名的内容,然后发生进程崩溃