• apisix动态性


    https://www.taohui.org.cn/2021/08/10/%E5%BC%80%E6%BA%90%E7%BD%91%E5%85%B3APISIX%E6%9E%B6%E6%9E%84%E5%88%86%E6%9E%90/#more

    Nginx采用了epoll + nonblock socket这种多路复用机制实现事件处理模型,其中每个worker进程会循环处理网络IO及定时器事件,ngx_event_expire_timers函数会调用所有超时事件的handler方法。事实上,定时器由红黑树实现,其中key是每个事件的绝对过期时间。这样,只要将最小节点与当前时间做比较,就能快速找到过期事件。OpenResty封装了Lua接口,通过ngx.timer.at将ngx_timer_add这个C函数暴露给了Lua语言:当我们调用ngx.timer.at这个Lua定时器时,就是在Nginx的红黑树定时器里加入了ngx_http_lua_timer_handler回调函数,这个函数不会阻塞Nginx。

    APISIX在每个Nginx Worker进程的启动过程中,通过ngx.timer.at函数将_automatic_fetch插入定时器。_automatic_fetch函数执行时会通过sync_data函数,基于watch机制接收etcd中的配置变更通知,这样,每个Nginx节点、每个Worker进程都将保持最新的配置。如此设计还有1个明显的优点:etcd中的配置直接写入Nginx Worker进程中,这样处理请求时就能直接使用新配置,无须在进程间同步配置,这要比启动1个agent进程更简单!

    竟然在这里  config_etcd.lua 循环注册_automatic_fetch定时器

    function _M.new(key, opts)
        ...
        if automatic then
            if not key then
                return nil, "missing `key` argument"
            end
    
            if loaded_configuration[key] then
                local res = loaded_configuration[key]
                loaded_configuration[key] = nil -- tried to load
    
                log.notice("use loaded configuration ", key)
    
                local dir_res, headers = res.body, res.headers
                load_full_data(obj, dir_res, headers)
            end
    
            ngx_timer_at(0, _automatic_fetch, obj)
    
        else
            local etcd_cli, err = get_etcd()
            if not etcd_cli then
                return nil, "failed to start a etcd instance: " .. err
            end
            obj.etcd_cli = etcd_cli
        end
    
        if key then
            created_obj[key] = obj
        end
    
        return obj
    end
    local function _automatic_fetch(premature, self)
        ...
           local i = 0
        while not exiting() and self.running and i <= 32 do
            i = i + 1
    
            local ok, err = xpcall(function()
                if not self.etcd_cli then
                    local etcd_cli, err = get_etcd()
                    if not etcd_cli then
                        error("failed to create etcd instance for key ["
                              .. self.key .. "]: " .. (err or "unknown"))
                    end
                    self.etcd_cli = etcd_cli
                end
    
                local ok, err = sync_data(self)
        ...
        if not exiting() and self.running then
            ngx_timer_at(0, _automatic_fetch, self)
        end
    end
    local function sync_data(self)
        ...
        local dir_res, err = waitdir(self.etcd_cli, self.key, self.prev_index + 1, self.timeout)
        log.info("waitdir key: ", self.key, " prev_index: ", self.prev_index + 1)
        log.info("res: ", json.delay_encode(dir_res, true))
    ...
    local function waitdir(etcd_cli, key, modified_index, timeout)
       ...
        local opts = {}
        opts.start_revision = modified_index
        opts.timeout = timeout
        opts.need_cancel = true
        local res_func, func_err, http_cli = etcd_cli:watchdir(key, opts)
        if not res_func then
            return nil, func_err
        end
    
        -- in etcd v3, the 1st res of watch is watch info, useless to us.
        -- try twice to skip create info
        local res, err = res_func()
        if not res or not res.result or not res.result.events then
            res, err = res_func()
        end
    
        if http_cli then
            local res_cancel, err_cancel = etcd_cli:watchcancel(http_cli)
            if res_cancel == 1 then
                log.info("cancel watch connection success")
            else
                log.error("cancel watch failed: ", err_cancel)
            end
        end
  • 相关阅读:
    使用自定义RadioButton和ViewPager实现TabHost效果和带滑动的页卡效果
    Android 实现文件上传功能(upload)
    Hibernate配置文件
    ICMP报文分析
    AVC1与H264的差别
    内存泄漏以及常见的解决方法
    数据挖掘十大经典算法
    关于java的JIT知识
    Ubuntu安装二:在VM中安装Ubuntu
    hdu 1520Anniversary party(简单树形dp)
  • 原文地址:https://www.cnblogs.com/it-worker365/p/15423128.html
Copyright © 2020-2023  润新知