百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

C++和Rust通过wasmtime实现相互调用实例

bigegpt 2025-01-08 11:20 11 浏览

C++和Rust通过wasmtime实现相互调用实例

1 wasmtime介绍

wasmtime是一个可以运行WebAssembly代码的运行时环境。

WebAssembly是一种可移植的二进制指令集格式,其本身与平台无关,类似于Java的class文件字节码。

WebAssembly本来的设计初衷是想让浏览器可以运行C语言这种编译型语言的代码。通常我们的C语言代码会使用gcc或clang等编译器直接编译链接成与平台相关的二进制可执行文件,这种与平台相关的二进制文件浏览器是无法直接运行的。如果想让浏览器运行C语言代码,就需要使用可将C语言编译成WebAssembly指令的编译器,编译好的代码是wasm格式。然后就可以使用各种wasm运行时来执行wasm代码,这就类似于JVM虚拟机执行class文件。

由于指令集和运行时环境本身与web场景并不绑定,因此随着后来的发展,WebAssembly指令集出现了可以脱离浏览器的独立运行时环境,WebAssembly的用途也变得更加广泛。

相比于浏览器的运行时,wasmtime是一个独立运行时环境,它可以脱离Web环境来执行wasm代码。它本身提供了命令行工具和API两种方式来执行wasm代码。本文主要介绍如何使用API方式来运行wasm代码。

2 wasmtime安装

2.1 wasmtime-cli安装

wasmtime-cli包含wasmtime命令,可以让我们直接在shell中运行wasm格式的代码。我们这里安装wasmtime主要是为了测试方便。

在shell中执行如下命令

curl https://wasmtime.dev/install.sh -sSf | bash

wasmtime的可执行文件会被安装在${HOME}/.wasmtime目录下

运行以上命令后会在${HOME}/.bashrc或${HOME}/.bash_profile文件中帮我们添加以下环境变量

export WASMTIME_HOME="${HOME}/.wasmtime"

export PATH="$WASMTIME_HOME/bin:$PATH"

如果希望所有用户(包括root)可以使用wasmtime命令,可以将以上环境变量设置到/etc/profile.d中,我们可以在该目录下创建wasmtime.sh文件,并添加一下代码

export WASMTIME_HOME=/home/<xxx>/.wasmtime # 将xxx替换成自己的home目录

export PATH="$WASMTIME_HOME/bin:$PATH"

可以使用如下命令直接运行wasm文件

wasmtime hello.wasm

2.2 wasmtime库安装

如果想在代码中加载wasm文件并运行其中的代码,我们需要为我们使用的语言安装wasmtime库。注意这里的wasmtime库是为了让我们从代码中能够加载wasm文件并在wasmtime运行时中运行。wasmtime并不是wasm编译器,不能将C++或Rust代码编译成wasm文件,如果我们想将其他语言编译成wasm代码,需要下载各个语言自己的wasm编译器,具体安装方式在本文第3节。

目前wasmtime支持的语言有:

Rust

C

C++

Python

.NET

Go

我们这里以Rust和C++为例介绍如何安装wasmtime库

Rust

在Rust中使用wasmtime库非常简单,我们只需要在Cargo.toml配置文件中添加如下依赖

[dependencies]

wasmtime = "12.0.2"

C++

wasmtime的C++库需要我们引入wasmtime-cpp这个项目,wasmtime-cpp依赖wasmtime的C API,因此需要先安装C API。

可以在wasmtime的release中找到后缀为-c-api的包,比如我们安装的平台是x86_64-linux,那么我们可以下载如下文件

wget https://github.com/bytecodealliance/wasmtime/releases/download/v12.0.2/wasmtime-v12.0.2-x86_64-linux-c-api.tar.xz

解压以上文件并将其移动到/usr/local目录下

tar -xvf wasmtime-v12.0.2-x86_64-linux-c-api.tar.xz

sudo mv ./wasmtime-v12.0.2-x86_64-linux-c-api /usr/local/wasmtime

在/etc/profile.d/wasmtime.sh中添加环境变量

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/wasmtime/lib

export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/wasmtime/lib

export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/wasmtime/include

export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/wasmtime/include

下载wasmtime-cpp项目的include/wasmtime.hh文件,将其放到wasmtime.h所在的目录下,按照我们的安装步骤,需要放置到/usr/local/wasmtime/include目录下

如此就可以在我们的C++项目中引入wasmtime库了

#include <wasmtime.hh>

3 wasm编译器安装

3.1 Rust

安装

Rust语言的编译器目前其实是一个LLVM的编译前端,它将代码编译成LLVM IR,然后经过LLVM编译成相应的目标平台代码。

因此我们并不需要替换Rust语言本身的编译器,只需要在编译时设置目标平台为wasm即可。我们在安装rust时,通常只会安装本机平台支持的目标,因此我们需要先安装wasm目标。

# 列出所有可安装的target列表

rustup target list

使用上面的命令后可以看到很多可以安装的target列表,其中已经安装的target后面会有(installed)标示。注意到其中有3个wasm相关的target。

wasm32-unknown-emscripten

wasm32-unknown-unknown

wasm32-wasi

wasm32-unknown-emscripten:这个target是为了在Emscripten工具链下编译Wasm。Emscripten是一个将C/C++代码编译为Wasm和JavaScript的工具链。使用这个target,你可以在浏览器环境中运行编译后的Wasm代码。

wasm32-unknown-unknown:这个target是为了在没有任何操作系统支持的情况下运行WebAssembly代码而设计的。这种情况下,WebAssembly代码将运行在一个“裸机”环境中,没有任何操作系统提供的支持。因此,如果你需要在裸机环境中运行WebAssembly代码,那么使用这个target是一个不错的选择。

wasm32-wasi:这个target是为了在WebAssembly System Interface (WASI)上运行WebAssembly代码而设计的。WASI是一个标准接口,它提供了一些操作系统级别的功能,如文件系统和网络访问等。因此,如果你需要在WebAssembly中访问这些操作系统级别的功能,那么使用这个target是一个不错的选择。

由于我们不需要在Web环境中运行Rust代码,因此我们选择安装wasm32-unknown-unknown和wasm32-wasi两个目标。运行以下两条指令,将这两个目标平台加入到当前使用的Rust工具链中。

rustup target add wasm32-unknown-unknown

rustup target add wasm32-wasi

使用

当我们需要将一个Rust项目编译成wasm时,可以选择执行如下的两种编译命令

# 在项目根目录执行

cargo build --target wasm32-unknown-unknown # 将在target/wasm32-unknown-unknown目录中生成build中间结果和wasm文件

# 或者执行

cargo build --target wasm32-wasi # 将在target/wasm32-wasi目录中生成build中间结果和wasm文件

3.2 C++

安装

目前,要将C++项目编译成WebAssembly,最常用的工具链是emscripten。emscripten支持将C,C++或任何使用了LLVM的语言编译成浏览器,Node.js或wasm运行时可以运行的代码。

Emscripten is a complete compiler toolchain to WebAssembly, using LLVM, with a special focus on speed, size, and the Web platform.

WebAssembly目前支持两种标准API:

Web APIs

WASI APIs

Emscripten对JavaScript API做了重构,将其包装在与WASI接口一样的API中,然后Emscripten在编译代码时,将尽可能的使用WASI APIs,以此来避免不必要的API差异。因此Emscripten编译出来的wasm文件大部分时候可以同时运行在Web和非Web环境中。

使用如下命令下载emsdk

git clone https://github.com/emscripten-core/emsdk.git


cd emsdk

使用如下命令安装最新的工具

git pull


./emsdk install latest


./emsdk activate latest

如果临时将emsdk的工具目录加入环境变量,可以运行

source ./emsdk_env.sh

或者可以在/etc/profile.d目录中创建emsdk.sh文件,并加入如下环境变量的配置,需要将<emsdk_installed_dir>替换为emsdk所在的目录。

export PATH=$PATH:<emsdk_installed_dir>/emsdk:<emsdk_installed_dir>/emsdk/node/16.20.0_64bit/bin:<emsdk_installed_dir>/emsdk/upstream/emscripten

export EMSDK=<emsdk_installed_dir>/emsdk

export EMSDK_NODE=<emsdk_installed_dir>/emsdk/node/16.20.0_64bit/bin/node

使用如下命令测试是否安装成功,如果输出下面的信息,说明我们已经可以正常使用emscripten的工具链。

> emcc -v


emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.45 (ef3e4e3b044de98e1811546e0bc605c65d3412f4)

clang version 18.0.0 (https://github.com/llvm/llvm-project d1e685df45dc5944b43d2547d0138cd4a3ee4efe)

Target: wasm32-unknown-emscripten

Thread model: posix

InstalledDir: <emsdk_installed_dir>/emsdk/upstream/bin

使用

由于我们不使用Web运行时,下面将只介绍将C或C++代码编译成独立wasm二进制文件的使用方法。

简单使用

emcc -O3 hello.cpp -o hello.wasm

当我们将输出目标的后缀名指定为wasm时,编译器会自动帮我们设置如下连接选项,上面的命令与下面的命令是等价的

emcc -O3 hello.cpp -o hello.wasm -s STANDALONE_WASM

这样编译出来的结果不会包含js文件,只会包含一个可被wasmtime运行的wasm文件。

结合cmake使用

更常用的方式通常是将整个C++项目编译成wasm,因此我们需要将工具链与cmake结合来构建整个项目。

假设我们有一个cmake项目有如下项目结构

hello_project

|-hello.cpp

|-CMakeLists.txt

其中hello.cpp中有如下代码

#include <stdio.h>


int main() {

printf("hello, world!\n");

return 0;

}

CMakeLists.txt应该按照下面的方式进行改写

cmake_minimum_required(VERSION 3.26)

project(hello_project)


add_definitions(-std=c++17)

set(CMAKE_CXX_STANDARD 17)


if (DEFINED EMSCRIPTEN)

add_executable(hello hello.cpp)


set(CMAKE_EXECUTABLE_SUFFIX ".wasm")


set_target_properties(hello PROPERTIES COMPILE_FLAGS "-Os")

set_target_properties(hello PROPERTIES LINK_FLAGS "-Os -s WASM=1 -s STANDALONE_WASM")

else()

add_executable(hello hello.cpp)

endif ()


以上CMakeLists.txt表示,当我们使用emscripten工具链进行编译时,将输出.wasm文件,且添加对应的编译和连接选项。当我们使用其他工具链编译时,将直接输出对应平台的可执行文件。

按照上面的方式写好CMakeLists.txt后,需要使用以下命令来执行编译的过程

# 在项目根目录下

mkdir build

cd build

# 执行emcmake命令会帮我们自动配置cmake中指定的工具链为emscripten的工具链,这样就确保了使用的编译工具为emcc或em++,同时使用的标准库更改为emscripten提供的标准库

emcmake cmake ..

# 再执行make进行编译,编译后可以发现build目录中生成了hello.wasm文件

make

使用wasmtime-cli运行hello.wasm文件

> wasmtime hello.wasm


hello, world!

4 小试牛刀

4.1 实验场景

需要测试Rust代码被编译成wasm,C++代码被编译成wasm,在wasmtime中正确运行。其中C++代码可以调用Rust代码中的函数,然后外部可以调用C++代码中的函数。

Rust项目:包含一个add函数,做两个整数的加法并返回结果,可以被外部调用。需要编译成wasm。

C++项目:包含一个foo函数,调用Rust中的add函数并返回结果。需要编译成wasm。

wasmtime项目:需要加载前面两个项目生成的wasm文件,并运行foo函数,看是否能获取正确的结果。

4.2 Rust项目编译成wasm

创建一个项目叫做demo-rust-wasmtime

cargo new demo-rust-wasmtime --lib

创建好的项目结构如下

demo-rust-wasmtime

├── Cargo.lock

├── Cargo.toml

└── src

└── lib.rs

首先需要在Cargo.toml中配置生成的库为cdylib,这表示按照C语言的FFI来生成动态库,要想不同语言之间能够互相调用对方的函数,通常需要将不同的语言按照相同的FFI来进行编译,确保函数调用的方式是相同的。这里同时我们将Rust项目的名称修改为calc。

[package]

name = "calc"

version = "0.1.0"

edition = "2021"


# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]

crate-type = ["cdylib"]


[dependencies]


在lib.rs中实现我们需要的add函数

#[no_mangle]

pub extern "C" fn add(left: i32, right: i32) -> i32 {

left + right

}

这里有两个地方需要注意:

#[no_mangle]会通知Rust编译器,其后面的函数编译时名字不要进行混淆,确保使用add这个名称进行链接时能找到正确的函数。

extern "C"表示编译器需要确保函数在编译时使用与C语言相同的调用约定(ABI),从而使得函数可以与C语言代码无缝地进行交互,当然如果我们将不同的语言都遵照C语言的ABI进行编译,那么它们之间就可以互相调用。

C语言的调用约定规定了函数参数的传递方式、返回值的处理方式以及堆栈的清理方式。

这样就定义好了Rust项目中可以让外部使用的add方法。

我们使用如下命令对项目进行编译

cargo build --target wasm32-unknown-unknown

# 或

cargo build --target wasm32-wasi

这里两种target都可以使用,因为我们的项目中并没有使用任何系统的API,所以通常使用第一种target即可。

编译后可以在target/wasm-xxx/debug/目录下看到生成的calc.wasm文件。

可以使用wasmtime-cli实验一下是否能够调用add方法:

> wasmtime calc.wasm --invoke add 101 202


warning: using `--invoke` with a function that takes arguments is experimental and may break in the future

warning: using `--invoke` with a function that returns values is experimental and may break in the future

303

可以看到已经正确输出了结果,说明这个Rust项目已经被正确编译成了wasm。

4.3 C++项目编译成wasm

创建一个项目叫做demo-cpp-wasmtime,使用cmake作为构建工具,其目录结构如下

demo-cpp-wasmtime

├── CMakeLists.txt

├── toolbox.cpp

└── toolbox.h

正如第3节讲到的,我们需要使用emscripten工具链代替gcc工具链来将这个C++项目编译成wasm。

cmake配置

因此我们需要按照如下方式配置CMakeLists.txt文件

cmake_minimum_required(VERSION 3.26)

project(demo_cpp_wasmtime)


add_definitions(-std=c++17)

set(CMAKE_CXX_STANDARD 17)


if (DEFINED EMSCRIPTEN)

add_executable(toolbox toolbox.cpp toolbox.h)


set(CMAKE_EXECUTABLE_SUFFIX ".wasm")


set_target_properties(toolbox PROPERTIES COMPILE_FLAGS "-Os -s SIDE_MODULE=1")

set_target_properties(toolbox PROPERTIES LINK_FLAGS "-Os -s WASM=1 -s SIDE_MODULE=1 -s STANDALONE_WASM --no-entry")

else()

add_library(toolbox toolbox.cpp)

endif ()


这里有几点需要注意的

在使用emscripten时,我们使用add_executable指定编译目标为可执行文件,这是因为wasm本身是可执行的二进制代码,在没有特殊配置时,编译后的wasm代码中会生成一个_start函数,这个函数就是运行时执行wasm代码的入口。这里如果我们将add_executable替换成add_library,则使用emscripten编译后只会生成libtoolbox.a库文件,而不会生成wasm代码。

针对emscripten编译工具链,我们配置了编译参数和链接参数

-Os表示开启编译优化

-s SIDE_MODULE=1表示将toolbox编译成module,这样生成的wasm就类似动态链接库,可以让wasmtime在运行时动态链接这份wasm代码。

emscripten支持将代码编译成两种不同的module

Main modules:系统库会被链接进去

Side modules:系统库不会被链接进去

通常一个完整的项目只能有一个Main module,这个Main module可以链接多个Side module

这里的编译选项SIDE_MODULE可以被设置为1或者2,设置成2则编译器会优化掉大量未被使用的代码或未被标记为EMSCRIPTEN_KEEPALIVE的代码,设置成1则会保留所有代码。

-s WASM=1表示只输出wasm文件,设置为0表示只输出js代码,设置成2表示两种代码都输出

-s STANDALONE_WASM表示编译的wasm是不依赖web环境而运行的

--no-entry编译生成的wasm代码通常需要有一个入口函数,也就是C++中需要有main函数,然而我们这里toolbox.cpp中将只有一个foo函数,因此我们需要使用这个链接参数来表示我们不需要入口函数。

代码实现

toolbox.h头文件如下

#pragma once


extern "C" {

int foo(int right);

}

类似Rust,这里我们声明了一个函数foo,并使用extern "C"表示这个foo函数需要按照C语言ABI进行编译。

接下来是toolbox.cpp的实现

#ifdef __EMSCRIPTEN__

#include <emscripten.h>

#else

#define EMSCRIPTEN_KEEPALIVE

#define EM_IMPORT(NAME)

#endif



extern "C" {

EM_IMPORT(add) int add(int a, int b);

}


extern "C" {

EMSCRIPTEN_KEEPALIVE int foo(int right) {

return add(1, right);

}

}

下面解释一下代码中的几个宏的作用:

#ifdef __EMSCRIPTEN__:当我们使用emscripten工具链编译这个项目时,__EMSCRIPTEN__会被自动定义

EMSCRIPTEN_KEEPALIVE和EM_IMPORT(NAME):

这是头文件emscripten.h中定义的宏,查看源码可以发现

#define EMSCRIPTEN_KEEPALIVE __attribute__((used))


#ifdef __wasm__

#define EM_IMPORT(NAME) __attribute__((import_module("env"), import_name(#NAME)))

#else

#define EM_IMPORT(NAME)

#endif

__attribute__((used))的作用是告诉编译器,即使该变量或函数没有被直接使用,也不要将其优化掉。这在一些特殊的情况下很有用,例如当你想要确保某个变量或函数在编译后的可执行文件中存在,即使它在代码中没有被显式调用或使用。这样就确保了我们的foo函数不会被编译器优化掉

__attribute__((import_module("env"), import_name(#NAME)))是用于WebAssembly的特殊属性,用于指定导入函数所属的模块和导入函数的名称。在WebAssembly中,可以从外部导入函数,这些函数通常由宿主环境(如浏览器或wasmtime)提供。当你使用__attribute__((import_module("env"), import_name(#NAME)))属性时,它告诉WebAssembly运行时,该函数属于名为"env"的模块,并且其导入名称为#NAME。

使用EM_IMPORT(add)宏告诉编译器,这里声明的add方法其具体实现来自于其他模块,具体就是来自于env模块中的add函数。因此这里声明的add方法其实可以起任意的名字,只要签名与env模块中的add方法相同即可。

当我们使用IDE编辑上面的C++代码时,IDE可能无法索引到#include <emscripten.h>这个头文件,这是因为我们使用emcmake进行构建时,emcmake才会自动把相关的头文件路径添加到编译选项中,因此这里即使IDE无法索引,也不会影响我们使用emcmake构建。

编译

使用如下命令进行编译

# 在项目根目录下

mkdir build

cd build


emcmake cmake ..

make

编译后在build目录下会生成toolbox.wasm二进制文件。

我们可以使用wasm2wat命令将编译好的wasm二进制文件转换成可读的wat文件来看一下生成的代码的结构

如果没有安装wasm2wat命令可以使用一下命令来安装

sudo apt install wabt

执行wasm2wat toolbox.wasm -o toolbox.wat命令后,可以打开toolbox.wat文件查看其结构如下

(module

(type (;0;) (func (param i32 i32) (result i32)))

(type (;1;) (func))

(type (;2;) (func (param i32) (result i32)))

(import "env" "add" (func (;0;) (type 0)))

(func (;1;) (type 1))

(func (;2;) (type 2) (param i32) (result i32)

i32.const 1

local.get 0

call 0)

(export "__wasm_call_ctors" (func 1))

(export "__wasm_apply_data_relocs" (func 1))

(export "foo" (func 2)))

可以看出,代码中import "env" "add"表示add函数来自env module的add函数。同时export "foo"表示toolbox.wasm对外暴露了foo函数。

4.4 wasmtime项目

wasmtime项目可以使用wasmtime支持的各种语言实现,这里我们以C++为例,看看如何将前面两个项目生成的.wasm文件调用起来。

创建一个项目叫做demo-run,使用cmake进行项目构建,其目录结构如下

demo-run

├── CMakeLists.txt

└── main.cpp

cmake配置

wasmtime项目可以使用gcc工具链进行编译,因此它的CMakeLists.txt可以正常进行配置

cmake_minimum_required(VERSION 3.26)

project(demo_run)


set(CMAKE_CXX_STANDARD 17)


add_executable(demo_run main.cpp)

target_link_libraries(demo_run PUBLIC wasmtime)

因为我们需要在代码中使用wasmtime的库,因此这里需要使用target_link_libraries(demo_run PUBLIC wasmtime)将wasmtime链接进来。这也就要求必须先按照第2节中的安装方式配置好wasmtime的环境变量。

代码实现

具体wasmtime提供的每个API的用法在这里不多做赘述,具体可以参考wasmtime官方文档和官方提供的examples

#include <iostream>

#include <wasmtime.hh>

#include <fstream>


using namespace wasmtime;



std::vector<unsigned char> readFile(const char *name) {

std::ifstream watFile(name, std::ios::binary);

std::vector<unsigned char> arr;

char byte;

while (watFile.get(byte)) {

arr.push_back(byte);

}

return arr;

}


int main() {

std::cout << "Compiling module" << std::endl;

Engine engine;


// 加载calc.wasm成为module

auto calcByteArr = readFile("calc.wasm");

Span<uint8_t> calcSpan(calcByteArr.data(), calcByteArr.size());

auto calcModule = Module::compile(engine, calcSpan).unwrap();


// 加载toolbox.wasm成为module

auto toolboxByteArr = readFile("toolbox.wasm");

Span<uint8_t> toolboxSpan(toolboxByteArr.data(), toolboxByteArr.size());

auto toolboxModule = Module::compile(engine, toolboxSpan).unwrap();


std::cout << "Initializing..." << std::endl;

Store store(engine);

store.context().set_wasi(WasiConfig()).unwrap();


std::cout << "Linking..." << std::endl;

Linker linker(engine);

linker.define_wasi().unwrap();


// 链接器初始化calc module,实例化成具体的Instance

auto calcInst = linker.instantiate(store, calcModule).unwrap();


// 将上一步的calcInst中的所有export的对象定义到env module名下

linker.define_instance(store, "env", calcInst).unwrap();


// 链接器初始化toolbox module,实例化成具体的Instance

auto toolboxInst = linker.instantiate(store, toolboxModule).unwrap();


// 获取toolboxInst中的foo方法

auto func = std::get<Func>(toolboxInst.get(store, "foo").value());


// 调用foo方法,传入参数7,

auto fooRes = func.call(store, {7}).unwrap();


// 打印结果 FooResult: 8

std::cout << "FooResult: " << fooRes[0].i32() << std::endl;


return 0;

}


就像注释中写的那样,我们将calc.wasm中export的方法add添加到了名称为env的module下,这样上一步中C++编译成的.wasm代码就可以链接到这个add方法。

编译与运行

mkdir build

cd build

cmake ..

make

执行编译后会生成可执行文件demo_run,由于代码还要依赖两个.wasm文件,因此我们这里手动将前面两个项目生成的.wasm文件拷贝到demo_run可执行文件的同级目录下。

运行生成的demo_run可执行文件后可得如下输出

> ./demo_run


Compiling module

Initializing...

Linking...

FooResult: 8

以上就实现了C++和Rust通过wasmtime实现相互调用的过程。

相关推荐

5分钟搭建公网https网页文件服务器,免费权威TLS证书

请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习前言本文主要讲解如何快速搭建一个https网页文件服务器,并免费申请权威机构颁发的tls证...

nginx负载均衡配置(nginx负载均衡配置两个程序副本)

Nginx是什么没有听过Nginx?那么一定听过它的“同行”Apache吧!Nginx同Apache一样都是一种WEB服务器。基于REST架构风格,以统一资源描述符(UniformResources...

19《Nginx 入门教程》Nginx综合实践

今天我们将基于Nginx完成两个比较有用的场景,但是用到的Nginx的配置非常简单。内部Yum源搭建内部Pip源搭建1.实验环境ceph1centos7.6内网ip:172.16....

Nginx性能调优与优化指南(nginx优化配置大全)

Nginx性能调优需要结合服务器硬件资源、业务场景和负载特征进行针对性优化。以下是一些关键优化方向和具体配置示例:一、Nginx配置优化1.进程与连接数优化nginxworker_process...

C++后端开发必须彻底搞懂Nginx,从原理到实战(高级篇)

本文为Nginx实操高级篇。通过配置Nginx配置文件,实现正向代理、反向代理、负载均衡、Nginx缓存、动静分离和高可用Nginx6种功能,并对Nginx的原理作进一步的解析。当需...

【Nginx】史上最全的Nginx配置详解

Nginx服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里,http块又包括http全局块和server块。Nginx是非常重要的负载均衡中间件,被广泛应用于大型...

【Nginx】Nginx 4种常见配置实例(nginx基本配置与参数说明)

本文主要介绍nginx4种常见的配置实例。Nginx实现反向代理;Nginx实现负载均衡;Nginx实现动静分离;Nginx实现高可用集群;Nginx4种常见配置实例如下:一、Nginx反向代理配...

使用nginx+allure管理自动化测试报告

allure在自动化测试中经常用来生成漂亮的报告,但是网上及官网上给出的例子都仅仅是针对单个测试用例文件的形式介绍的,实际使用中,自动化测试往往需要包含不止一个产品或项目,本文介绍如何使用nginx+...

nginx配置文件详解(nginx配置文件详解高清版)

Nginx是一个强大的免费开源的HTTP服务器和反向代理服务器。在Web开发项目中,nginx常用作为静态文件服务器处理静态文件,并负责将动态请求转发至应用服务器(如Django,Flask,et...

SpringCloud Eureka-服务注册与发现

1.Eureka介绍1.1学习Eureka前的说明目前主流的服务注册&发现的组件是Nacos,但是Eureka作为老牌经典的服务注册&发现技术还是有必要学习一下,原因:(1)一些早期的分布式微服...

微服务 Spring Cloud 实战 Eureka+Gateway+Feign+Hystrix

前言我所在项目组刚接到一个微服务改造需求,技术选型为SpringCloud,具体需求是把部分项目使用SpringCloud技术进行重构。本篇文章中介绍了Eureka、Gateway、Fe...

深度剖析 Spring Cloud Eureka 底层实现原理

你作为一名互联网大厂后端技术开发人员,在构建分布式系统时,是不是常常为服务的注册与发现而头疼?你是否好奇,像SpringCloudEureka这样被广泛使用的组件,它的底层实现原理到底是怎样的...

热爱生活,喜欢折腾。(很热爱生活)

原文是stackoverflow的一则高票回答,原文链接可能之前也有人翻译过,但是刚好自己也有疑惑,所以搬运一下,个人水平有限所以可能翻译存在误差,欢迎指正(如侵删)。尽管classmethod和st...

GDB调试的高级技巧(详细描述gdb调试程序的全过程)

GDB是我们平时调试c/c++程序的利器,查起复杂的bug问题,比打印大法要好得多,但是也不得不说,gdb在默认情况下用起来并不是很好用,最近学习到几个高级点的技巧,分享下:一美化打印先上个例子...

Arduino 实例(二十三)Arduino 给Python 编译器发送信息

1首先Python需要安装Pyserial库,在命令提示符中输入pipintallpyserial若是遇到提示‘pip‘不是内部或外部命令,也不是可运行的程序或批处理文件,则需要设置环境变...