1. 程式人生 > >AndroidO Treble架構下HIDL服務查詢過程

AndroidO Treble架構下HIDL服務查詢過程

通過前面的分析我們知道,Hal程序啟動時,會向hwservicemanager程序註冊hidl服務,那麼當Framework Server需要通過hal訪問硬體裝置時,首先需要查詢對應的hidl服務,那麼Client程序是如何查詢hidl服務的呢?這篇文章將展開分析,這裡再次以IComposer為例進行展開。

frameworks\native\services\surfaceflinger\DisplayHardware\ComposerHal.cpp

Composer::Composer(bool useVrComposer)
    : mWriter(kWriterInitialSize),
      mIsUsingVrComposer(useVrComposer)
{
    if (mIsUsingVrComposer) {
        mComposer = IComposer::getService("vr");
    } else {
        mComposer = IComposer::getService(); // use default name
    }

    if (mComposer == nullptr) {
        LOG_ALWAYS_FATAL("failed to get hwcomposer service");
    }

    mComposer->createClient(
            [&](const auto& tmpError, const auto& tmpClient)
            {
                if (tmpError == Error::NONE) {
                    mClient = tmpClient;
                }
            });
    if (mClient == nullptr) {
        LOG_ALWAYS_FATAL("failed to create composer client");
    }
}

這裡通過IComposer::getService()函式來查詢IComposer這個HIDL服務,由於這裡沒有傳遞任何引數,因此函式最終會呼叫:

composer\2.1\[email protected]_genc++_headers\gen\android\hardware\graphics\composer\2.1\IComposer.h

static ::android::sp<IComposer> getService(const std::string &serviceName="default", bool getStub=false);

注意,這裡的getStub為false,說明載入hidl服務方式是由當前hidl服務的transport型別決定。

    <hal format="hidl">
        <name>android.hardware.graphics.composer</name>
        <transport>hwbinder</transport>
        <version>2.1</version>
        <interface>
            <name>IComposer</name>
            <instance>vr</instance>
        </interface>
    </hal>

由於IComposer的transport是hwbinder型別,那麼將從hwservicemanager中查詢hidl服務。

composer\2.1\[email protected]_genc++\gen\android\hardware\graphics\composer\2.1\ComposerAll.cpp  

::android::sp<IComposer> IComposer::getService(const std::string &serviceName, const bool getStub) {
    using ::android::hardware::defaultServiceManager;
    using ::android::hardware::details::waitForHwService;
    using ::android::hardware::getPassthroughServiceManager;
    using ::android::hardware::Return;
    using ::android::sp;
    using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport;

    sp<IComposer> iface = nullptr;

    const sp<::android::hidl::manager::V1_0::IServiceManager> sm = defaultServiceManager();
    if (sm == nullptr) {
        ALOGE("getService: defaultServiceManager() is null");
        return nullptr;
    }

    Return<Transport> transportRet = sm->getTransport(IComposer::descriptor, serviceName);

    if (!transportRet.isOk()) {
        ALOGE("getService: defaultServiceManager()->getTransport returns %s", transportRet.description().c_str());
        return nullptr;
    }
    Transport transport = transportRet;
    const bool vintfHwbinder = (transport == Transport::HWBINDER);
    const bool vintfPassthru = (transport == Transport::PASSTHROUGH);

    #ifdef __ANDROID_TREBLE__

    #ifdef __ANDROID_DEBUGGABLE__
    const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
    const bool trebleTestingOverride =  env && !strcmp(env, "true");
    const bool vintfLegacy = (transport == Transport::EMPTY) && trebleTestingOverride;
    #else // __ANDROID_TREBLE__ but not __ANDROID_DEBUGGABLE__
    const bool trebleTestingOverride = false;
    const bool vintfLegacy = false;
    #endif // __ANDROID_DEBUGGABLE__

    #else // not __ANDROID_TREBLE__
    const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
    const bool trebleTestingOverride =  env && !strcmp(env, "true");
    const bool vintfLegacy = (transport == Transport::EMPTY);

    #endif // __ANDROID_TREBLE__

    for (int tries = 0; !getStub && (vintfHwbinder || (vintfLegacy && tries == 0)); tries++) {
        if (tries > 1) {
            ALOGI("getService: Will do try %d for %s/%s in 1s...", tries, IComposer::descriptor, serviceName.c_str());
            sleep(1);
        }
        if (vintfHwbinder && tries > 0) {
            waitForHwService(IComposer::descriptor, serviceName);
        }
        Return<sp<::android::hidl::base::V1_0::IBase>> ret = 
                sm->get(IComposer::descriptor, serviceName);
        if (!ret.isOk()) {
            ALOGE("IComposer: defaultServiceManager()->get returns %s", ret.description().c_str());
            break;
        }
        sp<::android::hidl::base::V1_0::IBase> base = ret;
        if (base == nullptr) {
            if (tries > 0) {
                ALOGW("IComposer: found null hwbinder interface");
            }continue;
        }
        Return<sp<IComposer>> castRet = IComposer::castFrom(base, true /* emitError */);
        if (!castRet.isOk()) {
            if (castRet.isDeadObject()) {
                ALOGW("IComposer: found dead hwbinder service");
                continue;
            } else {
                ALOGW("IComposer: cannot call into hwbinder service: %s; No permission? Check for selinux denials.", castRet.description().c_str());
                break;
            }
        }
        iface = castRet;
        if (iface == nullptr) {
            ALOGW("IComposer: received incompatible service; bug in hwservicemanager?");
            break;
        }
        return iface;
    }
    return iface;
}

這裡通過sm->get(IComposer::descriptor, serviceName)查詢IComposer這個hidl服務,得到IBase物件後,在通過IComposer::castFrom轉換為IComposer物件。

服務查詢

[email protected]_genc++\gen\android\hidl\manager\1.0\ServiceManagerAll.cpp
::android::hardware::Return<::android::sp<::android::hidl::base::V1_0::IBase>> BpHwServiceManager::get(const ::android::hardware::hidl_string& fqName, const ::android::hardware::hidl_string& name){
    ::android::hardware::Return<::android::sp<::android::hidl::base::V1_0::IBase>>  _hidl_out = ::android::hidl::manager::V1_0::BpHwServiceManager::_hidl_get(this, this, fqName, name);

    return _hidl_out;
}
::android::hardware::Return<::android::sp<::android::hidl::base::V1_0::IBase>> BpHwServiceManager::_hidl_get(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, const ::android::hardware::hidl_string& fqName, const ::android::hardware::hidl_string& name) {
    #ifdef __ANDROID_DEBUGGABLE__
    bool mEnableInstrumentation = _hidl_this_instrumentor->isInstrumentationEnabled();
    const auto &mInstrumentationCallbacks = _hidl_this_instrumentor->getInstrumentationCallbacks();
    #else
    (void) _hidl_this_instrumentor;
    #endif // __ANDROID_DEBUGGABLE__
    atrace_begin(ATRACE_TAG_HAL, "HIDL::IServiceManager::get::client");
    #ifdef __ANDROID_DEBUGGABLE__
    if (UNLIKELY(mEnableInstrumentation)) {
        std::vector<void *> _hidl_args;
        _hidl_args.push_back((void *)&fqName);
        _hidl_args.push_back((void *)&name);
        for (const auto &callback: mInstrumentationCallbacks) {
            callback(InstrumentationEvent::CLIENT_API_ENTRY, "android.hidl.manager", "1.0", "IServiceManager", "get", &_hidl_args);
        }
    }
    #endif // __ANDROID_DEBUGGABLE__

    ::android::hardware::Parcel _hidl_data;
    ::android::hardware::Parcel _hidl_reply;
    ::android::status_t _hidl_err;
    ::android::hardware::Status _hidl_status;

    ::android::sp<::android::hidl::base::V1_0::IBase> _hidl_out_service;

    _hidl_err = _hidl_data.writeInterfaceToken(BpHwServiceManager::descriptor);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    size_t _hidl_fqName_parent;

    _hidl_err = _hidl_data.writeBuffer(&fqName, sizeof(fqName), &_hidl_fqName_parent);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    _hidl_err = ::android::hardware::writeEmbeddedToParcel(
            fqName,
            &_hidl_data,
            _hidl_fqName_parent,
            0 /* parentOffset */);

    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    size_t _hidl_name_parent;

    _hidl_err = _hidl_data.writeBuffer(&name, sizeof(name), &_hidl_name_parent);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    _hidl_err = ::android::hardware::writeEmbeddedToParcel(
            name,
            &_hidl_data,
            _hidl_name_parent,
            0 /* parentOffset */);

    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    _hidl_err = ::android::hardware::IInterface::asBinder(_hidl_this)->transact(1 /* get */, _hidl_data, &_hidl_reply);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    _hidl_err = ::android::hardware::readFromParcel(&_hidl_status, _hidl_reply);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    if (!_hidl_status.isOk()) { return _hidl_status; }

    {
        ::android::sp<::android::hardware::IBinder> _hidl__hidl_out_service_binder;
        _hidl_err = _hidl_reply.readNullableStrongBinder(&_hidl__hidl_out_service_binder);
        if (_hidl_err != ::android::OK) { goto _hidl_error; }

        _hidl_out_service = ::android::hardware::fromBinder<::android::hidl::base::V1_0::IBase,::android::hidl::base::V1_0::BpHwBase,::android::hidl::base::V1_0::BnHwBase>(_hidl__hidl_out_service_binder);
    }

    atrace_end(ATRACE_TAG_HAL);
    #ifdef __ANDROID_DEBUGGABLE__
    if (UNLIKELY(mEnableInstrumentation)) {
        std::vector<void *> _hidl_args;
        _hidl_args.push_back((void *)&_hidl_out_service);
        for (const auto &callback: mInstrumentationCallbacks) {
            callback(InstrumentationEvent::CLIENT_API_EXIT, "android.hidl.manager", "1.0", "IServiceManager", "get", &_hidl_args);
        }
    }
    #endif // __ANDROID_DEBUGGABLE__

    _hidl_status.setFromStatusT(_hidl_err);
    return ::android::hardware::Return<::android::sp<::android::hidl::base::V1_0::IBase>>(_hidl_out_service);

_hidl_error:
    _hidl_status.setFromStatusT(_hidl_err);
    return ::android::hardware::Return<::android::sp<::android::hidl::base::V1_0::IBase>>(_hidl_status);
}

整個呼叫過程和hidl服務過程完全一致,就是一個從BpHwServiceManager --> BnHwServiceManager --> ServiceManager的過程。但需要注意,BpHwServiceManager得到BnHwServiceManager返回過來的binder代理後,會通過fromBinder函式進行物件轉換:

::android::hardware::fromBinder<::android::hidl::base::V1_0::IBase,::android::hidl::base::V1_0::BpHwBase,::android::hidl::base::V1_0::BnHwBase>(_hidl__hidl_out_service_binder)

hwservicemanager將IComposer的binder代理BpHwBinder發給Framework Server程序,Framework Server程序拿到的依然是IComposer的binder代理BpHwBinder物件,因此在fromBinder函式中將建立BpHwBase物件來封裝BpHwBinder。

::android::status_t BnHwServiceManager::_hidl_get(
        ::android::hidl::base::V1_0::BnHwBase* _hidl_this,
        const ::android::hardware::Parcel &_hidl_data,
        ::android::hardware::Parcel *_hidl_reply,
        TransactCallback _hidl_cb) {
    #ifdef __ANDROID_DEBUGGABLE__
    bool mEnableInstrumentation = _hidl_this->isInstrumentationEnabled();
    const auto &mInstrumentationCallbacks = _hidl_this->getInstrumentationCallbacks();
    #endif // __ANDROID_DEBUGGABLE__

    ::android::status_t _hidl_err = ::android::OK;
    if (!_hidl_data.enforceInterface(BnHwServiceManager::Pure::descriptor)) {
        _hidl_err = ::android::BAD_TYPE;
        return _hidl_err;
    }

    const ::android::hardware::hidl_string* fqName;
    const ::android::hardware::hidl_string* name;

    size_t _hidl_fqName_parent;

    _hidl_err = _hidl_data.readBuffer(sizeof(*fqName), &_hidl_fqName_parent,  reinterpret_cast<const void **>(&fqName));

    if (_hidl_err != ::android::OK) { return _hidl_err; }

    _hidl_err = ::android::hardware::readEmbeddedFromParcel(
            const_cast<::android::hardware::hidl_string &>(*fqName),
            _hidl_data,
            _hidl_fqName_parent,
            0 /* parentOffset */);

    if (_hidl_err != ::android::OK) { return _hidl_err; }

    size_t _hidl_name_parent;

    _hidl_err = _hidl_data.readBuffer(sizeof(*name), &_hidl_name_parent,  reinterpret_cast<const void **>(&name));

    if (_hidl_err != ::android::OK) { return _hidl_err; }

    _hidl_err = ::android::hardware::readEmbeddedFromParcel(
            const_cast<::android::hardware::hidl_string &>(*name),
            _hidl_data,
            _hidl_name_parent,
            0 /* parentOffset */);

    if (_hidl_err != ::android::OK) { return _hidl_err; }

    atrace_begin(ATRACE_TAG_HAL, "HIDL::IServiceManager::get::server");
    #ifdef __ANDROID_DEBUGGABLE__
    if (UNLIKELY(mEnableInstrumentation)) {
        std::vector<void *> _hidl_args;
        _hidl_args.push_back((void *)fqName);
        _hidl_args.push_back((void *)name);
        for (const auto &callback: mInstrumentationCallbacks) {
            callback(InstrumentationEvent::SERVER_API_ENTRY, "android.hidl.manager", "1.0", "IServiceManager", "get", &_hidl_args);
        }
    }
    #endif // __ANDROID_DEBUGGABLE__

    ::android::sp<::android::hidl::base::V1_0::IBase> _hidl_out_service = static_cast<BnHwServiceManager*>(_hidl_this)->_hidl_mImpl->get(*fqName, *name);

    ::android::hardware::writeToParcel(::android::hardware::Status::ok(), _hidl_reply);

    if (_hidl_out_service == nullptr) {
        _hidl_err = _hidl_reply->writeStrongBinder(nullptr);
    } else {
        ::android::sp<::android::hardware::IBinder> _hidl_binder = ::android::hardware::toBinder<
                ::android::hidl::base::V1_0::IBase>(_hidl_out_service);
        if (_hidl_binder.get() != nullptr) {
            _hidl_err = _hidl_reply->writeStrongBinder(_hidl_binder);
        } else {
            _hidl_err = ::android::UNKNOWN_ERROR;
        }
    }
    /* _hidl_err ignored! */

    atrace_end(ATRACE_TAG_HAL);
    #ifdef __ANDROID_DEBUGGABLE__
    if (UNLIKELY(mEnableInstrumentation)) {
        std::vector<void *> _hidl_args;
        _hidl_args.push_back((void *)&_hidl_out_service);
        for (const auto &callback: mInstrumentationCallbacks) {
            callback(InstrumentationEvent::SERVER_API_EXIT, "android.hidl.manager", "1.0", "IServiceManager", "get", &_hidl_args);
        }
    }
    #endif // __ANDROID_DEBUGGABLE__

    _hidl_cb(*_hidl_reply);
    return _hidl_err;
}

BnHwServiceManager通過ServiceManager物件查詢到對應的hidl服務,返回IBase物件後,會呼叫toBinder函式轉換為IBinder型別物件:

::android::hardware::toBinder< ::android::hidl::base::V1_0::IBase>(_hidl_out_service)

由於在hwservicemanager這邊,儲存的是IComposer的BpHwBase物件,因此在toBinder函式中將呼叫IInterface::asBinder來得到BpHwBase的成員變數中的BpHwBinder物件。

if (ifacePtr->isRemote()) {
	return ::android::hardware::IInterface::asBinder(static_cast<ProxyType *>(ifacePtr));
}

fromBinder和toBinder函式在之前的文章中已經詳細分析了,這裡就不再展開。

服務查詢過程其實就是根據介面包名及服務名稱,從hwservicemanager管理的表中查詢對應的IBase服務物件,然後在Client程序空間分別建立BpHwBinder和BpHwBase物件。

介面轉換

Framework Server程序通過上述hidl服務查詢,得到了BpHwBase物件後,需要將其轉換為與業務相關的代理物件,這就是通過:Return<sp<IComposer>> castRet = IComposer::castFrom(base, true /* emitError */);

composer\2.1\[email protected]_genc++\gen\android\hardware\graphics\composer\2.1\ComposerAll.cpp

::android::hardware::Return<::android::sp<IComposer>> IComposer::castFrom(const ::android::sp<::android::hidl::base::V1_0::IBase>& parent, bool emitError) {
    return ::android::hardware::details::castInterface<IComposer, ::android::hidl::base::V1_0::IBase, BpHwComposer>(
            parent, "[email protected]::IComposer", emitError);
}

system\libhidl\transport\include\hidl\HidlTransportSupport.h

// cast the interface IParent to IChild.
// Return nonnull if cast successful.
// Return nullptr if:
// 1. parent is null
// 2. cast failed because IChild is not a child type of IParent.
// 3. !emitError, calling into parent fails.
// Return an error Return object if:
// 1. emitError, calling into parent fails.
template<typename IChild, typename IParent, typename BpChild, typename BpParent>
Return<sp<IChild>> castInterface(sp<IParent> parent, const char *childIndicator, bool emitError) {
    if (parent.get() == nullptr) {
        // casts always succeed with nullptrs.
        return nullptr;
    }
    Return<bool> canCastRet = details::canCastInterface(parent.get(), childIndicator, emitError);
    if (!canCastRet.isOk()) {
        // call fails, propagate the error if emitError
        return emitError
                ? details::StatusOf<bool, sp<IChild>>(canCastRet)
                : Return<sp<IChild>>(sp<IChild>(nullptr));
    }

    if (!canCastRet) {
        return sp<IChild>(nullptr); // cast failed.
    }
    // TODO b/32001926 Needs to be fixed for socket mode.
    if (parent->isRemote()) {
        // binderized mode. Got BpChild. grab the remote and wrap it.
        return sp<IChild>(new BpChild(toBinder<IParent, BpParent>(parent)));
    }
    // Passthrough mode. Got BnChild and BsChild.
    return sp<IChild>(static_cast<IChild *>(parent.get()));
}

}  // namespace details

這個模板函式展開後如下:

Return<sp<IComposer>> castInterface(sp<IBase> parent, const char *childIndicator, bool emitError) {
    if (parent.get() == nullptr) {
        // casts always succeed with nullptrs.
        return nullptr;
    }
    Return<bool> canCastRet = details::canCastInterface(parent.get(), childIndicator, emitError);
    if (!canCastRet.isOk()) {
        // call fails, propagate the error if emitError
        return emitError
                ? details::StatusOf<bool, sp<IComposer>>(canCastRet)
                : Return<sp<IComposer>>(sp<IComposer>(nullptr));
    }

    if (!canCastRet) {
        return sp<IComposer>(nullptr); // cast failed.
    }
    // TODO b/32001926 Needs to be fixed for socket mode.
    if (parent->isRemote()) {
        // binderized mode. Got BpChild. grab the remote and wrap it.
        return sp<IComposer>(new BpHwComposer(toBinder<IBase, BpParent>(parent)));
    }
    // Passthrough mode. Got BnChild and BsChild.
    return sp<IComposer>(static_cast<IComposer *>(parent.get()));
}

因此最終會建立一個BpHwComposer物件。

new BpHwComposer(toBinder<IBase, BpParent>(parent))

相關推薦

AndroidO Treble架構HIDL服務查詢過程

通過前面的分析我們知道,Hal程序啟動時,會向hwservicemanager程序註冊hidl服務,那麼當Framework Server需要通過hal訪問硬體裝置時,首先需要查詢對應的hidl服務,那麼Client程序是如何查詢hidl服務的呢?這篇文章將展開分析,這裡再次

AndroidO Treble架構Tranport型別查詢過程

通過前面文章的分析,我們知道,Client程序在查詢hidl服務介面物件時,會根據該hidl服務的Tranport型別選擇載入方式,如果是HWBINDER,那麼就從hwservicemanager中查詢,如果是PASSTHROUGH,那麼就通過PassthroughServi

AndroidO Treble架構HIDL服務Java框架實現

前面介紹了HIDL服務在native層的實現過程,包括HIDL服務載入建立、服務註冊、服務查詢過程等,那麼Java層是否也實現了相關的服務框架呢? 通常情況下,

AndroidO Treble架構Hal程序啟動及HIDL服務註冊過程--不全

通過前面對Treble架構的介紹,我們知道,Android Framework程序和Hal分離,每個Hal獨立執行在自己的程序地址空間,那麼這些Hal程序是如何啟動的呢?本文以composer hal為例展開分析。在以下路徑有composer hal的rc啟動指令碼:hard

AndroidO Treble架構Hal程序啟動及HIDL服務註冊過程

通過前面對Treble架構的介紹,我們知道,Android Framework程序和Hal分離,每個Hal獨立執行在自己的程序地址空間,那麼這些Hal程序是如何啟動的呢?本文以composer hal為例展開分析。在以下路徑有composer hal的rc啟動指令碼:hard

AndroidO Treble架構Binder物件的轉換過程

上文中詳細分析了Hal的整個啟動過程,這裡將補充上文中沒有詳細分析的Binder物件轉換過程,下圖為hidl服務的完整註冊過程:1.  HwcHal繼承於IBase類,是對hw_module_t的封裝,該物件位於Hal程序空間;2.  通過hwservicemanager的b

AndroidO Treble架構的變化--

AndroidO引入Treble架構後,有那些變化呢? 1. 增加了多個服務管家,AndroidO之前版本有且只有一個servicemanager,現在增加到3個,他們分管不同的服務。 2. 增加了binder通訊庫,這是為了適配binder域的

AndroidO Treble架構的變化

AndroidO引入Treble架構後,有那些變化呢? 1. 增加了多個服務管家,AndroidO之前版本有且只有一個servicemanager,現在增加到3個,他們分管不同的服務。 2. 增加了binder通訊庫,這是為了適配binder域的擴充套件

AndroidO Treble架構分析【轉】

本文轉載自:https://blog.csdn.net/yangwen123/article/details/79835965 從AndroidO開始,google引入了Treble架構,目的是為了方便系統升級,將oem定製的東西和Framework分離。AndroidO之前的版本:在此之前的Android

AndroidO Treble架構分析

從AndroidO開始,google引入了Treble架構,目的是為了方便系統升級,將oem定製的東西和Framework分離。 AndroidO之前的版本: 在此之前的Android系統架構當中,Android Framework與Android HAL是

X86架構Linux啟動過程分析

重要 ack csdn 檢查 point article span 註意 eap 1、X86架構下的從開機到Start_kernel啟動的整體過程 這個過程簡要概述為: 開機——>BIOS——>GRUB/LILO——>Linux Kernel

服務架構的分布式數據管理

數據庫更新 event 可擴展 存儲 展現 文檔數據庫 and 持久化 class 1.1 分布式數據管理之痛點 為了確保微服務之間松耦合,每個服務都有自己的數據庫, 有的是關系型數據庫(SQL),有的是非關系型數據庫(NoSQL)。 開發企業事務往往牽涉到多個服務,要

從 0 開始的微服務架構:(四)如何保障微服務架構的數據一致性

網上 行數 解決方案 open 了解 傳播 發的 目的 cati 雖然已經紅了很久,但是“微服務架構”正變得越來越重要,也將繼續火下去。各個公司與技術人員都在分享微服務架構的相關知識與實踐經驗,但我們發現,目前網上的這些相關文章中,要麽上來就是很有借鑒意義的幹貨,要麽就是以

Spring Cloud雲服務架構 - common-service 項目過程構建

activit 架構 rip mes edi service 2.4 .cn sta 我們將對common-service整個項目進行剖析,將整個構建的流程給記錄下來,讓更多的關註者來參考學習。 首先在構建spring cloud的common-service之前,我們需要

服務架構業務單機QPS跑不上去應從哪些角度分析

應用運維 性能分析 微服務 這是做應用運維老生常談的一個事兒,經常做,今天把他總結一下。不管什麽性質的業務,吞吐量的本質是木桶原理,能跑多大量取決於木桶最短的那個板,腦袋裏是不是立刻可以出現木桶的那個模型,哈哈!!換句話說,當有能力提高短板的高度時,業務的吞吐量就會有所上升,但同樣有個邊際效應,經

linux怎麽查詢服務器的信息

php linux參考:https://zhidao.baidu.com/question/621368750657770092.html 1,查看內存大小:cat /proc/meminfo |grep MemTotal 2,其他一些可以查看詳細linux系統信息的命令和方法:uname -a

Spring Cloud雲服務架構 - commonservice-eureka 項目過程構建

Spring Cloud Spring Boot mybatis 我們針對於HongHu cloud的eureka項目做以下構建,整個構建的過程很簡單,我會將每一步都構建過程記錄下來,希望可以幫助到大家: 創建一個名為particle-common-eureka的maven項目,繼承parti

服務架構使用Spring Cloud Zuul作為網關將多個微服務整合到一個Swagger服務

turn 接口文檔 vid 使用方法 數據操作 prefix opera tor font 註意:   如果你正在研究微服務,那必然少不了服務之間的相互調用,哪麽服務之間的接口以及api就必須生成系統的管理文檔了。如果你希望更好的管理你的API,你希望有一個工具能一站式地解

服務架構 Service Mesh 會是閃亮的明天嗎?

在一起 7月 部署 服務發現 代理 負載 開源項目 images 我們 7月7日,時速雲企業級容器 PaaS 技術沙龍第 10 期在上海成功舉辦,時速雲容器架構負責人魏巍為大家詳細講解了 Service Mesh 中代表性的實踐方案、並以 Istio 為例詳細講解了 Ser