Flare是广泛投产于腾讯广告后台的现代化C++开发框架,包含了基础库、RPC、各种客户端等。主要特点为易用性强、长尾延迟低。

Flare 后台服务开发框架

license NewBSD Python Code Style Platform

腾讯广告 是腾讯公司最重要的业务之一,其后台大量采用 C++ 开发。

Flare 是我们吸收先前服务框架和业界开源项目及最新研究成果开发的现代化的后台服务开发框架,旨在提供针对目前主流软硬件环境下的易用、高性能、平稳的服务开发能力。

Flare 项目开始于 2019 年,目前广泛应用于腾讯广告的众多后台服务,拥有数以万计的运行实例,在实际生产系统上经受了足够的考验。

2021 年 5 月,本着回馈社区、技术共享的精神,正式对外开源。

特点

  • 现代 C++ 设计风格,广泛采用了 C++11/14/17/2a 的新的语法特性和标准库
  • 提供了 M:N 的线程模型的微线程实现Fiber,方便业务开发人员以便利的同步调用语法编写高性能的异步调用代码
  • 支持基于消息的流式 RPC支持
  • 除了 RPC 外,还提供了一系列便利的基础库,比如字符串、时间日期、编码处理、压缩、加密解密、配置、HTTP 客户端等,方便快速上手开发业务代码
  • 提供了灵活的扩充机制。方便支持多种协议、服务发现、负载均衡、监控告警、调用追踪
  • 针对现代体系结构做了大量的优化。比如 NUMA 感知调度组对象池零拷贝缓冲区
  • 高质量的代码。严格遵守 Google C++ 代码规范,测试覆盖率达 80%
  • 完善的文档示例以及调试支持,方便快速上手

系统要求

  • Linux 3.10 及以上内核,暂不支持其他操作系统
  • x86-64 处理器,也支持 aarch64 及 ppc64le,但是未在生产环境上实际使用过
  • GCC 8 及以上版本的编译器

开始使用

Flare 是开箱即用的,已经自带了所需的第三方库,因此通常不需要额外安装依赖库。只需要在 Linux 下,拉取代码,即可使用。

thirdparty/下面的压缩包我们通过Git LFS存储,因此在拉取代码之前您需要确保git-lfs已经正确的安装了。

构建

我们使用blade进行日常开发。

  • 编译:./blade build ...
  • 测试:./blade test ...

之后就可以参考入门导引中的介绍,搭建一个简单的RPC服务了。

调试

我们相信,调试体验也是开发维护过程中很重要的一部分,我们为此也做了如下一些支持:

测试

为了改善编写单测的体验,我们提供了一些用于编写单测的工具

这包括但不限于:

示例

我们提供了一些使用示例以供参考,下面是一个简单的转发服务(同时包含RPC客户端及服务端的使用)。

set_body(result->body()); } else { ctlr->SetFailed(result.error().code(), result.error().message()); } } private: EchoService_SyncStub stub_{FLAGS_forward_to}; }; int Entry(int argc, char** argv) { flare::Server server{flare::Server::Options{.service_name = "relay_server"}}; server.AddProtocol("flare"); server.AddService(std::make_unique()); server.ListenOn(flare::EndpointFromIpv4(FLAGS_ip, FLAGS_port)); FLARE_CHECK(server.Start()); flare::WaitForQuitSignal(); return 0; } } // namespace example int main(int argc, char** argv) { return flare::Start(argc, argv, example::Entry); } ">
#include "thirdparty/gflags/gflags.h"

#include "flare/example/rpc/echo_service.flare.pb.h"
#include "flare/example/rpc/relay_service.flare.pb.h"
#include "flare/fiber/this_fiber.h"
#include "flare/init.h"
#include "flare/rpc/rpc_channel.h"
#include "flare/rpc/rpc_client_controller.h"
#include "flare/rpc/rpc_server_controller.h"
#include "flare/rpc/server.h"

using namespace std::literals;

DEFINE_string(ip, "127.0.0.1", "IP address to listen on.");
DEFINE_int32(port, 5569, "Port to listen on.");
DEFINE_string(forward_to, "flare://127.0.0.1:5567",
              "Target IP to forward requests to.");

namespace example {

class RelayServiceImpl : public SyncRelayService {
 public:
  void Relay(const RelayRequest& request, RelayResponse* response,
             flare::RpcServerController* ctlr) override {
    flare::RpcClientController our_ctlr;
    EchoRequest echo_req;
    echo_req.set_body(request.body());
    if (auto result = stub_.Echo(echo_req, &our_ctlr)) {
      response->set_body(result->body());
    } else {
      ctlr->SetFailed(result.error().code(), result.error().message());
    }
  }

 private:
  EchoService_SyncStub stub_{FLAGS_forward_to};
};

int Entry(int argc, char** argv) {
  flare::Server server{flare::Server::Options{.service_name = "relay_server"}};

  server.AddProtocol("flare");
  server.AddService(std::make_unique());
  server.ListenOn(flare::EndpointFromIpv4(FLAGS_ip, FLAGS_port));
  FLARE_CHECK(server.Start());

  flare::WaitForQuitSignal();
  return 0;
}

}  // namespace example

int main(int argc, char** argv) {
  return flare::Start(argc, argv, example::Entry);
}

Flare内部基于M:N的用户态线程实现,因此通过Flare同步的请求外界服务、使用Flare内置的各种客户端的同步接口均不会导致性能问题。如果有更复杂的并发或异步等需求可以参考我们的文档

另外,示例中*.flare.pb.h通过我们的Protocol Buffers插件生成。这样生成的接口相对于Protocol Buffers生成的cc_generic_services而言,更易使用。

更复杂的示例

实际使用中,往往会面对需要并发请求多种后端的场景,下面的示例介绍了如何在Flare中进行这种操作:

body(), flare::FlattenSlow(cos->bytes), rpc->body()); } // Now fill `response` accordingly. response->set_body("Great success."); } ">
// For illustration purpose only. Normally you wouldn't want to declare them as
// global variables.
flare::HttpClient http_client;
flare::CosClient cos_client;
EchoService_SyncStub echo_stub(FLAGS_echo_server_addr);

void FancyServiceImpl::FancyJob(const FancyJobRequest& request,
                                FancyJobResponse* response,
                                flare::RpcServerController* ctlr) {
  // Calling different services concurrently.
  auto async_http_body = http_client.AsyncGet(request.uri());
  auto async_cos_data =
      cos_client.AsyncExecute(flare::CosGetObjectRequest{.key = request.key()});
  EchoRequest echo_req;
  flare::RpcClientController echo_ctlr;
  echo_req.set_body(request.echo());
  auto async_rpc_resp = echo_stub.AsyncEcho(EchoRequest(), &echo_ctlr);

  // Now wait for all of them to complete.
  auto&& [http, cos, rpc] = flare::fiber::BlockingGet(
      flare::WhenAll(&async_http_body, &async_cos_data, &async_rpc_resp));

  if (!http || !cos || !rpc) {
    FLARE_LOG_WARNING("Failed.");
  } else {
    // All succeeded.
    FLARE_LOG_INFO("Got: {}, {}, {}", *http->body(),
                   flare::FlattenSlow(cos->bytes), rpc->body());
  }

  // Now fill `response` accordingly.
  response->set_body("Great success.");
}

这个示例中,我们:

  • 通过三种不同的客户端(HTTP腾讯云COS、RPC)发起了三个异步请求;
  • 通过flare::fiber::BlockingGet同步等待所有请求完成。这儿我们只会阻塞用户态线程,不会存在性能问题;
  • 打印日志输出各个服务的响应。

出于展示目的,我们这儿请求了三个异构的服务。如果有必要,也可以通过这种方式请求同构的、或者部分同构部分异构的服务。

二次开发

我们非常欢迎参与共同建设,对于希望了解 Flare 更多内部设计的开发者,或需要对 Flare 进行二次开发的开发者而言,flare/doc/下有更多的技术文档可供参考。

详情请参考CONTRIBUTING.md

性能

由于业务需求的特点,我们在设计过程中更倾向于优化延迟及抖动的平稳性而非吞吐,但是也在这个前提下尽量保证性能。

出于简单的对比目的,我们提供了初步的性能数据

致谢

  • 我们的底层实现大量参考了brpc的设计。
  • RPC部分,grpc给了我们很多启发。
  • 我们依赖了不少开源社区的第三方库,站在巨人的肩膀上使得我们可以更快更好地开发本项目,也因此积极地回馈给开源社区。

在此,我们对上述项目一并致以谢意。

Comments
  • 有人能编译成功吗?

    有人能编译成功吗?

    ./blade build ...编译失败。

    image

    后来我cd到flare/flare目录,执行 ../blade build

    没有上述报错了。但是会卡住:

    [2/788] CMAKE BUILD //thirdparty/opentracing-cpp:opentracing-cpp_build
    
    
    

    进度不继续走。

    已经安装了git lfs

  • -D__const__= 在高版本gcc下会报错

    -D__const__= 在高版本gcc下会报错

    类似于brpc,这里fiber实现中也定义了-D__const__=

    https://github.com/Tencent/flare/blob/master/flare/fiber/BUILD#L209

    目前brpc遇到了高版本gcc下编译错误的问题:https://github.com/apache/incubator-brpc/issues/1693

    fiber这里可能也会遇到

  • [yadcc ARM] spinlock 在 arm 构建中找不到符号 __aarch64_swp1_acq

    [yadcc ARM] spinlock 在 arm 构建中找不到符号 __aarch64_swp1_acq

    https://github.com/Tencent/flare/blob/64d72fc8c05d87b506f91f8230dc9ffb8a28146f/flare/base/thread/BUILD#L162

    在 arm 上构建 yadcc 的时候报错

    gcc-10.3.0/include/c++/10.3.0/bits/atomic_base.h:443: undefined reference to `__aarch64_swp1_acq'
    

    经查此符号只在 libatomic.a 中有,似乎 gcc 与 atomic 关系有点复杂, 临时规避后继续通行

    diff --git a/flare/base/thread/BUILD b/flare/base/thread/BUILD
    index 60e4805..9a2bed7 100644
    --- a/flare/base/thread/BUILD
    +++ b/flare/base/thread/BUILD
    @@ -163,6 +163,9 @@ cc_library(
       deps = [
         '//flare/base:likely',
       ],
    +  linkflags = [
    +    '-Wl,-Bstatic -latomic -Wl,-Bdynamic',
    +  ],
       visibility = 'PUBLIC',
     )
    
    
  • Question about looping for read_events_ and write_events_

    Question about looping for read_events_ and write_events_

    Could anyone help to explain why to use a loop for read_events_ here.

    if (read_events_.fetch_add(1, std::memory_order_acquire) == 0) {
          RefPtr self_ref(ref_ptr, this);
    
          do {
            auto rc = OnReadable();
            if (FLARE_LIKELY(rc == EventAction::Ready)) {
              continue;
            } else if (FLARE_UNLIKELY(rc == EventAction::Leaving)) {
              FLARE_CHECK(read_mostly_.seldomly_used->cleanup_reason.load(
                              std::memory_order_relaxed) != CleanupReason::None,
                          "Did you forget to call `Kill()`?");
              GetEventLoop()->AddTask([this] {
                read_events_.store(0, std::memory_order_relaxed);
                QueueCleanupCallbackCheck();
              });
              break;
            } else if (rc == EventAction::Suppress) {
              SuppressReadAndClearReadEventCount();
              break;
            }
          } while (read_events_.fetch_sub(1, std::memory_order_release) !=
                   1);
          QueueCleanupCallbackCheck();
        });
    

    We can only get read_events_ == 1 after the if condition, so is there any special case that looping to decrease read_events_ is necessary?

  • How to build flare using blade?

    How to build flare using blade?

    Hi there, I have installed blade and ninja but don't know how to build flare or examples in flare project. I have no experience of blade and ninja. I think I installed blade and ninja correctly. Below is some log:

    `[email protected]:/mnt/hgfs/E/flare/flare/example$ blade -h usage: blade [-h] [--version] {build,run,test,clean,query,dump} ...

    blade [options...] [targets...]

    positional arguments: {build,run,test,clean,query,dump} Available subcommands build Build specified targets run Build and runs a single target test Build the specified targets and runs tests clean Remove all blade-created output query Execute a dependency graph query dump Dump specified internal information

    optional arguments: -h, --help show this help message and exit --version show program's version number and exit [email protected]:/mnt/hgfs/E/flare/flare/example$ ninja --version 1.10.0 [email protected]:/mnt/hgfs/E/flare/flare/example$ `

  • Unable to link, ubuntu 20.04

    Unable to link, ubuntu 20.04

    blade build ... works, no errors, however when running blade test, many .so cannot be correctly linked. Latest head of flare, latest head of blade-build

    Details

    blade test flare/base:endian_test Blade(info): Loading BUILD files... Blade(info): Loading done. Blade(info): Analyzing dependency graph... Blade(info): Analyzing done. Blade(info): Generating backend build code... Blade(info): Generating done. Blade(info): Building... Blade(info): Adjust build jobs number(-j N) to be 20 ninja: warning: bad deps log signature or version; starting over [46/46] LINK BINARY build64_release/flare/base/endian_test Blade(info): Build success. Blade(info): Adjust test jobs number(-j N) to be 10 Blade(notice): 1 tests to run Blade(info): Spawn 1 worker thread(s) to run concurrent tests repo/flare/build64_release/flare/base/endian_test: error while loading shared libraries: libgtest_main.so: cannot open shared object file: No such file or directory Blade(info): [1/0/1] Test //flare/base:endian_test finished : FAILED:127

    ldd result:

    ~/repo/flare$ ldd blade-bin/flare/base/endian_test linux-vdso.so.1 (0x00007ffc89d05000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007feb7aab2000) libgtest_main.so => not found libgtest.so => not found libtcmalloc.so.4 => not found libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007feb7a8d1000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007feb7a8b6000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007feb7a6c2000) /lib64/ld-linux-x86-64.so.2 (0x00007feb7aafe000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007feb7a573000)

    I wonder how does link work in blade?

  • Question About Future and Async: Will it blocking until the the result has been product

    Question About Future and Async: Will it blocking until the the result has been product

    Since that brpc do not has the future type, and std::async will:

    If the std::future obtained from std::async is not moved from or bound to a reference, the destructor of the std::future will block at the end of the full expression until the asynchronous operation completes, essentially making code such as the following synchronous

    And folly::Future will detach when destructor.

    I have through the documents:

    1. https://github.com/Tencent/flare/blob/master/flare/doc/fiber.md
    2. https://github.com/Tencent/flare/blob/master/flare/doc/future.md

    I didn't find anywhere that says if it will block or detach when destruct. And I go through the code, and find it will share a std::shared_ptr<Core>, and it will do like detached. Did I catched it?

  • Fail to build

    Fail to build

    ./blade build ... gave me the following errors

    ERROR:root:code` for hash sha512 was not found.
    Traceback (most recent call last):
      File "/home/server_dev/.blade_boost/lib/python2.7/hashlib.py", line 139, in <module>
        globals()[__func_name] = __get_hash(__func_name)
      File "/home/server_dev/.blade_boost/lib/python2.7/hashlib.py", line 91, in __get_builtin_constructor
        raise ValueError('unsupported hash type %s' % name)
    ValueError: unsupported hash type sha512
    ...
    ... (similar error for other hashes)
    ...
    Traceback (most recent call last):
      File "/home/server_dev/.blade_boost/lib/python2.7/runpy.py", line 162, in _run_module_as_main
        "__main__", fname, loader, pkg_name)
      File "/home/server_dev/.blade_boost/lib/python2.7/runpy.py", line 72, in _run_code
        exec code in run_globals
      File "/home/server_dev/repo/flare/thirdparty/blade/blade.zip/__main__.py", line 14, in <module>
      File "/home/server_dev/repo/flare/thirdparty/blade/blade.zip/blade/__init__.py", line 6, in <module>
      File "/home/server_dev/repo/flare/thirdparty/blade/blade.zip/blade/config.py", line 422, in <module>
      File "/home/server_dev/repo/flare/thirdparty/blade/blade.zip/blade/config.py", line 44, in __init__
    AttributeError: 'module' object has no attribute 'md5'
    

    I though it was my openssl lib being missing, reinstalled but still no luck.

  • http json 转 protobuf message 出错

    http json 转 protobuf message 出错

    https://github.com/Tencent/flare/blob/6d3bf3c46ab5e4178a0676de6d1172930bc45a3a/flare/rpc/protocol/protobuf/gdt_json_proto_conversion.cc#L326

    这里处理repeated字段,是不是应该写成 item.asString() , 而不是value.asString(),因为value是一个数组。

    } else if (auto opt = TryParse(item.asString())) {

  • Why use std::common_type in TryParseTraits

    Why use std::common_type in TryParseTraits

    Could anyone help to explain why std::common_type is need here instead of just using T()?

    template <class T, class>
    struct TryParseTraits {
      // The default implementation delegates calls to `TryParse` found by ADL.
      template <class... Args>
      static std::optional<T> TryParse(std::string_view s, const Args&... args) {
        return TryParse(std::common_type<T>(), s, args...);
      }
    };
    
  • 无法编译项目, 提示没有 GIT LFS? 但是我我确定已经安装

    无法编译项目, 提示没有 GIT LFS? 但是我我确定已经安装

    [email protected]_test_server:~/flare
    $ git lfs install
    Updated git hooks.
    Git LFS initialized.
    
    [email protected]_test_server:~/flare
    $ ./blade build
    Blade(error): This repository need GIT LFS, see README.md
    Blade(error): Blade will exit...
    [email protected]_test_server:~/flare
    $ ./blade build flare
    Blade(error): This repository need GIT LFS, see README.md
    Blade(error): Blade will exit...
    [email protected]_test_server:~/flare
    $ ./blade build flare/BUILD
    Blade(error): This repository need GIT LFS, see README.md
    Blade(error): Blade will exit...
    [email protected]_test_server:~/flare
    
  • Add constexpr to `insert` function

    Add constexpr to `insert` function

    https://github.com/Tencent/flare/blob/64d72fc8c05d87b506f91f8230dc9ffb8a28146f/flare/base/experimental/byte_set.h#L33

    ./flare/base/experimental/byte_set.h: In constructor 'constexpr flare::experimental::ByteSet::ByteSet(std::string_view)':
    ./flare/base/experimental/byte_set.h:33:11: error: call to non-'constexpr' function 'void flare::experimental::ByteSet::insert(std::string_view)'
       33 |     insert(bytes);
    
  • compile fail

    compile fail

    编译环境 gcc 版本 11.2.0 (GCC)

    flare2

    这里缺少头文件, 加入头文件 optional 就行

    flare

    这个我暂时将/usr/include/sys/cdefs.h中的__glibc_has_attribute (const)删了,希望有更好的解决办法

    flare3

    在thirdparty/curl/BUILD的configure_options里加入'--without-librtmp'和'--without-libpsl'

  • How could I use flare in my own project?

    How could I use flare in my own project?

    Flare is an awesome rpc framework and flare/base has many usefull function capsulations, and I want to use them in my own project. There is no CMakeFiles or configure script, I do no know how to build it as an indepedent lib. So I tried to use BLADE too. My project has the following directory tree.

    |__code
        |__BLADE_ROOT: my own BLADE_ROOT
        |__thirdparty
            |__flare: a git submodule pointing to Tencent/flare
    

    I event wrote a tool (https://gist.github.com/ericuni/627cacb9978c9db58ae7360c4d31de6b) to process all BUILD files and BLADE_ROOT in flare. But still failed.

Packio - An asynchronous msgpack-RPC and JSON-RPC library built on top of Boost.Asio.

Header-only | JSON-RPC | msgpack-RPC | asio | coroutines This library requires C++17 and is designed as an extension to boost.asio. It will let you bu

Nov 26, 2022
RPC++ is a tool for Discord RPC (Rich Presence) to let your friends know about your Linux system
RPC++ is a tool for Discord RPC (Rich Presence) to let your friends know about your Linux system

RPC++ RPC++ is a tool for Discord RPC (Rich Presence) to let your friends know about your Linux system Installing requirements Arch based systems pacm

Jul 6, 2022
Cap'n Proto serialization/RPC system - core tools and C++ library
Cap'n Proto serialization/RPC system - core tools and C++ library

Cap'n Proto is an insanely fast data interchange format and capability-based RPC system. Think JSON, except binary. Or think Protocol Buffers, except

Nov 28, 2022
Comprehensive RPC framework with support for C++, C#, Java, JavaScript, Python and more.

Ice - Comprehensive RPC Framework Ice helps you network your software with minimal effort. By taking care of all interactions with low-level network p

Nov 28, 2022
C++ framework for json-rpc (json remote procedure call)
C++ framework for json-rpc (json remote procedure call)

I am currently working on a new C++17 implementation -> json-rpc-cxx. Master Develop | libjson-rpc-cpp This framework provides cross platform JSON-RPC

Dec 2, 2022
rpclib is a modern C++ msgpack-RPC server and client library

rpclib rpclib is a RPC library for C++, providing both a client and server implementation. It is built using modern C++14, and as such, requires a rec

Nov 27, 2022
a simple RPC wrapper generator to C/C++ functions

This project initiated from the following practical problem. To control experimental equipment via computers, manufactures provide software drivers wi

Jan 25, 2022
Cap'n Proto serialization/RPC system - core tools and C++ library
Cap'n Proto serialization/RPC system - core tools and C++ library

Cap'n Proto is an insanely fast data interchange format and capability-based RPC system. Think JSON, except binary. Or think Protocol Buffers, except

Dec 1, 2022
Support for multiple RPC protocols in a single library

AnyRPC A multiprotocol remote procedure call system for C++ Overview AnyRPC provides a common system to work with a number of different remote procedu

Nov 17, 2022
Nov 4, 2022
Groupware server backend with RPC/HTTP, MAPI/HTTP, IMAP, POP3 and PHP-MAPI support

Gromox is the central groupware server component of grammm. It is capable of serving as a replacement for Microsoft Exchange and compatibles. Connecti

Nov 30, 2022
c++11, high performance, cross platform, easy to use rpc framework.

modern C++(C++11), simple, easy to use rpc framework

Nov 25, 2022
Bypass UAC at any level by abusing the Program Compatibility Assistant with RPC, WDI, and more Windows components
Bypass UAC at any level by abusing the Program Compatibility Assistant with RPC, WDI, and more Windows components

ByeIntegrity 8.0 The eighth Windows privilege escalation attack in the ByeIntegrity family. ByeIntegrity 8.0 is the most complex one I've created so f

Dec 2, 2022
🚀 Discord RPC Blocker for Lunar Client
🚀 Discord RPC Blocker for Lunar Client

?? Soyuz Soyuz has one simple purpose; listen for incoming Discord RPC requests from Lunar Client and block them! Limitations Windows only Soon to com

Oct 6, 2022
C++ framework for json-rpc (json remote procedure call)
C++ framework for json-rpc (json remote procedure call)

I am currently working on a new C++17 implementation -> json-rpc-cxx. Master Develop | libjson-rpc-cpp This framework provides cross platform JSON-RPC

Nov 30, 2022
modern C++(C++11), simple, easy to use rpc framework

modern C++(C++11), simple, easy to use rpc framework

Dec 4, 2022
gRPC - An RPC library and framework Baind Unity 3D Project

Unity 3D Compose for Desktop and Android, a modern UI framework for C ++ , C# that makes building performant and beautiful user interfaces easy and enjoyable.

May 19, 2022
RPC based on C++ Workflow. Supports Baidu bRPC, Tencent tRPC, thrift protocols.
RPC based on C++ Workflow. Supports Baidu bRPC, Tencent tRPC, thrift protocols.

中文版入口 SRPC Introduction SRPC is an RPC system developed by Sogou. Its main features include: Base on Sogou C++ Workflow, with the following features:

Dec 1, 2022
Gromox - Groupware server backend with MAPI/HTTP, RPC/HTTP, IMAP, POP3 and PHP-MAPI support for grommunio

Gromox is the central groupware server component of grommunio. It is capable of serving as a replacement for Microsoft Exchange and compatibles. Conne

Nov 26, 2022
Fastest RPC in the west
Fastest RPC in the west

smf - the fastest RPC in the West We're looking for a new maintainer for the SMF project. As I have little time to keep up with issues. Please let me

Dec 1, 2022