LogicServer初探

构造函数中启动的是一些管理器

template <typename T>
LogicServer<T>::LogicServer(pm::common::Context &ctx, MgrEventDelegator *delegator,
                            const pm::ServerRole &role)
    : ctx_(ctx), event_delegator_(delegator), role_(role) {
    //比如一个xxxServer与另一个xxxServer连接,内部其实是靠
    //xxxServer内部的xxxServiceServer连接的
    //这个ServiceManager应该就是xxxServiceServer连接的管理器
    pm::common::ServiceManager::set(&sm_);
    T::manager::set(&tm_);
    pm::common::RpcCallbackRef::set(&rpc_cb_ref_);
    pm::db::RedisManager::set(&rm_);
    pm::common::ServerStatManager::set(&ssm_);
}
// 具体的LoginApp,GateApp或者GameApp会调用这个函数
template <typename T> void LogicServer<T>::work() {
    // start thread pool 启动线程池
    thread_pool_.reset(new pm::common::ThreadPool(CFG(loop_threads)));
    //初始化一个线程池的单例
    pm::common::ThreadPool::set(thread_pool_.get());
    thread_pool_->start();
    thread_pool_->waitForReady();

    //初始化http
    http_manager_.reset(new HttpManager(thread_pool_->chooseBestThreadBase()));
    // init mgr_client 初始化mgr_client,
    // 获得与MgrApp连接的线程
    auto &mgr_base = thread_pool_->chooseBestThreadBase();

    std::promise<std::shared_ptr<pm::common::TcpConnection>> mgr_handler_promise;
    auto mgr_handler_future = mgr_handler_promise.get_future();

    mgr_base.post([&mgr_base, &mgr_handler_promise] {
        auto tcp_conn = std::make_shared<pm::common::TcpConnection>(mgr_base, -1);
        mgr_handler_promise.set_value(std::move(tcp_conn));
    });

    //等待mgr_handler_promise的set_value被调用(会阻塞主线程)
    //确保创建tcp连接的实例
    auto tcp_conn = mgr_handler_future.get();

    mgr_client_.reset(new pm::common::MgrHandler(
        ctx_, std::make_shared<pm::common::RpcChannel>(
                  ctx_, std::static_pointer_cast<pm::common::DiscreteConnection>(
                            std::make_shared<pm::common::TcpDiscreteConnection>(tcp_conn))),
        event_delegator_));

    //初始化redis
    if (CFG(enable_redis)) {
        if (CFG(enable_redis_cluster)) {
            pm::db::RedisManager::inst().initForCluster(ctx_, CFG(redis_cluster_addr));
        } else {
            pm::db::RedisManager::inst().init(ctx_, CFG(redis_ip), CFG(redis_port));
        }
    }

    // set lua env
    //----------------
    std::string script_dir = CFG(script_dir);
    std::string lua_loader_file = script_dir + "/framework/loader.lua";
    // init lua
    auto &lua_stack = ctx_.getLuaStack();
    lua_stack.setString("script_dir", script_dir)
        .setString("component", getServerRoleName(role_))
        .setInt("server_id", FLAGS_server_id)
        .setString("server_tag", CFG(tag))
        .setData("config", ServerConfig::inst().getCfgReader().getCfg())
        .setRegisterUserData(pm::consts::mgr_client_key_name, mgr_client_.get())
        .setRegisterUserData(pm::consts::http_manager_key_name, http_manager_.get());
    //---------------
    if (!lua_stack.dofile(lua_loader_file)) {
        REPORT_LOG(ERROR) << "execute lua failed: " << lua_loader_file;
    } else if (!_startLocalServer()) {
        //具体连接工作(连接mgr)在_startLocalServer()中进行
        REPORT_LOG(ERROR) << "start local server failed";
    } else if (!_startLater()) {
        REPORT_LOG(ERROR) << "call startLater failed";
    } else {
        ctx_.getLuaStack().postEvent(LuaEventType::ON_READY);
    }

    lua_settop(lua_stack.state(), 0);

    _loopUntilExit();
}

 

_loopUntilExit()就进入了主线程的循环当中

template <typename T> void LogicServer<T>::_loopUntilExit() {
    //从配置文件读取,服务器帧频率的概念,默认是10,也就是一秒执行10次
    int hz = CFG(tick_hertz);
    if (hz > 0) {
        auto tick_interval = static_cast<int>(1000 * 1.0 / hz);
        ctx_.getLuaStack().setInt("tick_interval", tick_interval);

        uint64_t cycles = 0;

        while (!ctx_.isStopped()) {
            tick(cycles++, tick_interval);
        }

    } else {
        ctx_.dispatch();
    }
}
#define PER_SECOND(x)                                                                              \
    if (cycles % (static_cast<int>(static_cast<double>(x) * CFG(tick_hertz))) == 0)

template <typename T> void LogicServer<T>::tickBefore(uint64_t cycles) {
    //这个应该是检查和mgr是否还连接着吧?
    //心跳检查
    PER_SECOND(10) {
        if (mgr_client_) {
            pm::mgr::MgrTickMessage req;
            req.set_server_id(ServerConfig::inst().getLocalInfo().id());
            mgr_client_->callMethod(&pm::mgr::MgrService::tick, &req);
        }
    }
    //和lua垃圾回收有关
    PER_SECOND(30) {
        auto gc_count = ctx_.getLuaStack().gcCount();
        if (gc_count > CFG(gc_warn_size)) {
            LOG(WARNING) << "lua vm size: " << gc_count;
        }
    }
}

template <typename T> void LogicServer<T>::tick(uint64_t cycles, int tick_interval) {
    auto start_time = pm::common::nowtime();
    //非阻塞去进行一次event_base_loop,处理堆积的事务
    
    {
        MICROPROFILE_SCOPEI("_loopUntilExit", "dispatch_once", MP_YELLOW);
        ctx_.dispatch_once(); 
    }

    {
        MICROPROFILE_SCOPEI("_loopUntilExit", "onTick", MP_BROWN);
        //tickBefore做一些和mgr之间心跳检查以及检查lua虚拟机的gc工作
        this->tickBefore(cycles);
        this->onTick(cycles);
    }

    {
        MICROPROFILE_SCOPEI("_loopUntilExit", "sleep", MP_BLUE);
        auto end_time = pm::common::nowtime();
        auto tick_execution_time = end_time - start_time;
        int quota_per_tick = CFG(quota_per_tick);
        if (tick_execution_time > quota_per_tick) {
            LOG(WARNING) << "execution time of tick more than " << quota_per_tick << ", execution time: " << tick_execution_time;
            ctx_.getLuaStack().postEvent(pm::LuaEventType::ON_EXCEED_TICK_QUOTA, tick_execution_time);
        }

        auto sleep_time = tick_interval - tick_execution_time;

        double load_smooth_bias = CFG(load_smooth_bias);
        // clamp
        double new_ratio =
            (std::min)((std::max)(1 - static_cast<double>(sleep_time) / tick_interval, 0.0), 1.0);
        server_load_ = (1 - load_smooth_bias) * server_load_ + load_smooth_bias * new_ratio;

        SET_STAT(double, app_load, server_load_);

        beforeSleep(sleep_time);

        auto real_sleep_time = tick_interval - (pm::common::nowtime() - start_time);

        if (real_sleep_time > 0) {
            std::this_thread::sleep_for(std::chrono::milliseconds(real_sleep_time)); 
        }
    }
    MicroProfileFlip(nullptr);
}

一帧中,主线程先处理堆积的事务(dispatch_once),然后在tickBefore里做一下mgr心跳检查和lua垃圾回收检查相关的事情,然后算一下各种性能指标和剩余睡觉时间,最后

std::this_thread::sleep_for(std::chrono::milliseconds(real_sleep_time))

 


posted @ 2017-11-25 11:09  vaevaevae  阅读(335)  评论(0)    收藏  举报