C++(week17): C++提高:(七)workflow

发布于:2024-08-21 ⋅ 阅读:(30) ⋅ 点赞:(0)

文章目录

一、Http协议

http复习链接:https://blog.csdn.net/Edward1027/article/details/141124939



二、Nginx

1.概念

Nginx最重要的特征包括高性能、高并发和低资源占用。除此之外,Nginx还有其他功能,比如反向代理负载均衡缓存、访问控制等等,Nginx也可以作为复杂的Web应用的基础架构。

Nginx采用了事件驱动模型,每个连接不再会占据一个进程/线程的资源,一般来说只会消耗文件句柄和一些其他必要的资源。


架构:
在这里插入图片描述


2.nginx的安装和部署

(1)安装nginx

1.安装nginx

sudo apt install nginx

切换到root用户

sudo su

2.查看nginx

netstat -ntlp
ps -elLf | grep nginx
kill -9 进程号

在这里插入图片描述
在这里插入图片描述


3.安装nignx的效果,多出来的东西
(1)可执行程序
在这里插入图片描述
(2)默认的配置文件路径

/etc/nginx/nginx.conf

(3)nginx进程的默认当前工作目录 (当前工作目录:相对路径的起点)

/usr/share/nginx

(2)使用nginx服务器部署静态资源

4.nginx配置文件
①location的作用:路由匹配。让不同的path 执行不同的业务。
②root指令的效果:静态资源服务器将服务端的磁盘文件作为响应内容回复给客户端。

worker_processes  1;  
user root;            
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;     #nginx默认端口号为80
        server_name  localhost;
        location / {
            #root   html;       #相对路径
            root   reference;  #相对路径
            #root /home/edward/cpp58/workflow/workflowday1;  #绝对路径
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

在这里插入图片描述


5.启动和停止nginx
①退出残留的nginx进程 (强制杀死,暴力退出):

//root下杀死master
ps -elLf | grep nginx
kill -9 master进程号

②启动nginx

nginx -c /etc/nginx/nginx.conf

③退出nginx (优雅退出)

nginx -s quit -c /etc/nginx/nginx.conf

6.测试:访问nginx服务器部署的静态资源
(1)相对路径与绝对路径:部署网页

#配置文件中用相对路径
root html  				   #结果是拼接, /usr/share/nginx/html

#配置文件中用绝对路径
root /home/edward/reference  #结果就是把绝对路径作为前缀

(2)在root用户下 (sudo su),使用curl命令请求服务器的静态资源

sudo apt update
sudo apt install curl     #安装curl
curl localhost:80/index.html
curl localhost:80/en/cpp.html

curl localhost:80/help.txt

(3)用windows浏览器访问linux:

192.168.49.131/index.html
192.168.49.131/en/cpp/container/map/begin.html

192.168.49.131/help.txt

3.HTTP服务器架构

成熟的HTTP服务端产品:Nginx、Apache

在这里插入图片描述
在这里插入图片描述

(1)基于进程、基于线程:APache

多进程/多线程服务器(进程驱动/线程驱动):每一个线程/进程 负责一个业务的处理。

优点:代码好写,开发效率高。业务逻辑可以一口气写到底。
缺点:性能差。
①每一个事务要分配一个进程/线程,占用内存大,并发量低。
②进行业务切换要进行进程/线程切换,CPU要从用户态切换到内核态再切换回用户态,CPU耗时高。

在这里插入图片描述


(2)事件驱动模型:Nginx

事件驱动模型:1个线程用IO多路复用 (select/epoll) 管理多个连接。

优点:调用是用户态的,CPU耗时低。
缺点:代码不好写。要把完整的业务,拆分成事件碎片。

在这里插入图片描述


并发量:
APache单核并发量为2000-3000。(并大低,代码好写,一口气写到底)
nginx单核并发量为2w~4w QPS,深度优化可达10w。 (并大量大,代码不好写)

QPS:Queries Per Second,每秒查询数
TPS:Transactions Per Second,每秒事务数

搭配使用:最合理的方式是一起用,各司其职:
(1)Nginx:简单,大流量。如:访问静态资源(主页),缓存。Nginx作为网关。
(2)Apache:复杂业务。作为后端。


(3)反向代理

反向代理:靠近服务端。对复杂业务进行转发。对重复的请求进行缓存。

反向代理:
在Web应用的设计过程,有的时候并不适合直接让客户端和服务端之间相连,而是增加一些中间服务器用于转发请求和响应。如果代理服务器的设计是为了将某个客户端的请求按需从多个服务器当中分配一个的话,那么这个代理服务器就是反向代理服务器。


(4)负载均衡

1.定义
负载均衡:合理地分配流量,对多个Apache进行任务分配。

在这里插入图片描述


2.负载均衡的策略:
(1)轮询 / 随机:不能充分利用缓存
(2)哈希:能充分利用缓存,但加入新服务器时,会存在大量缓存失效。
(3)环形哈希 (一致性哈希):大幅度减少缓存失效的数量。
环形哈希在服务器节点的增减时能够最大限度地减少缓存的失效和重新分配的成本。

在这里插入图片描述
在这里插入图片描述


3.事件驱动模型 要充分利用多核:
(1)单reactor + 线程池:连接数不多,但每个链接的业务复杂,耗时
(2)每个线程一个reactor:连接数非常大,但业务简单。

Nginx的策略:每个进程一个Reactor,提高可靠性。


4.线程数是CPU核心数的1-2倍
①IO密集型:2倍。
②CPU密集型:1倍。
③都密集:1-2倍,压力测试取最佳值。


5.压力测试(性能测试/跑分)工具:(本质上是一个客户端,发很多个请求,长短不一定。统计响应的回复时间。每秒处理的响应数称为QPS)
(1)apache bench:测http服务端,只能测http协议

sudo apt install apache2-utils  #安装
ab -n 10000 -c 100 http://192.168.49.131:12345/
ab -n 100000 (任务量) -c 10 (线程数) http://192.168.49.131:12345/

(2)wrk



三、workflow异步事件引擎 (异步回调模型)

复习思维导图:https://www.kdocs.cn/view/l/ciK8WuFRfrgv


任务:完成某一个目标的代码片段
在这里插入图片描述


1.服务器底层架构分类

1.实现http服务端:
①自己从零写:代码量大,但灵活,可随时添加功能
②成熟的产品:Apache、Nginx,不用写代码,但无法添加自定义功能
③使用框架 / 库:可自定义添加功能


2.底层架构:
(1)基于进程/线程:性能低
(2)事件驱动:select/epoll
“就绪”就通知,然后进行任务处理。用户写read/recv
在这里插入图片描述

(3)异步回调:iocp、io_uring
完成才通知,异步。框架调用回调函数。
理论上性能会好一点,实测没有区别。
在这里插入图片描述
在这里插入图片描述

(4)协程:coroutine
可以恢复和暂停的函数。
优点:写起来很方便。有阻塞点就会自动切换任务。
缺点:所有接口要重新实现。只适用于IO密集型。

腾讯重写的协程库:libco
https://github.com/Tencent/libco

在这里插入图片描述


2.安装workflow

安装一个第三方库的完整步骤:

0.linux系统里要有cmake工具,用来生成Makefile

sudo apt install cmake

1.下载源码,并解压

tar zxvf workflow-0.11.3.tar.gz

2.创建build,cmake,make

cd workflow-0.11.3
mkdir build
cd build
cmake ..            #生成Makefile文件到build目录中。有可能报错,缺乏依赖。
make                #编译和连接
sudo make install   #拷贝头文件和库文件到系统目录
sudo ldconfig       #更新链接器缓存

在这里插入图片描述

3.可以看到,头文件和库文件已经生成在build的上级目录。_include和_lib中。并且已经被拷贝到系统路径/usr/include和/usr/library下。

4.在tutorial文件下测试,库有没有装好

cd tutorial                  #build的上级目录中的tutorial
g++ tutorial-00-helloworld.cc -o tutorial-00-helloworld -g -lworkflow
./tutorial-00-helloworld     #若没有报错,则说明安装成功

3.让主线程等待:WaitGroup

异步回调:Pasue,WaitGroup
①等待n件事都完成:wait
②完成一件事:done


企业内部帮助文档很少,要自己看头文件。
在这里插入图片描述

#include <workflow/WFFacilities.h>

static WFFacilities::WaitGroup waitGroup(1);

int main()
{
	waitGroup.done();  //n--
	waitGroup.wait();  //n>0阻塞, n==0返回
}

在这里插入图片描述


4.任务

任务:基本工作,回调函数(用户设计,框架调用)

用户:负责创建任务,设置任务的属性
框架:执行任务。先执行任务的基本工作,再执行任务的回调函数。

#include <workflow/WFTaskFactory.h>

在这里插入图片描述

(0)使用工厂函数去构造对象

工厂模式:把类对象的构造延后

工厂函数:框架写的,可以更好地控制对象的生命周期。让对象的生命周期由框架管理。

class WFTaskFactory
{
public:
	static WFHttpTask *create_http_task(const std::string& url, //要连接的服务端的url
										int redirect_max, //最大重定向次数
										int retry_max,    //连接失败的时候的重试次数
										http_callback_t callback);  //回调函数
};

任务的接口:类模板
在这里插入图片描述

在这里插入图片描述


(1)http任务

在这里插入图片描述

WFHttpTask *httpTask = WFTaskFactory::create_http_task(
        "http://www.baidu.com", 
        10, 10, nullptr); //给任务对象申请内存并初始化

代码链接:https://github.com/WangEdward1027/workflow/blob/main/httpTask.cpp

#include <workflow/WFFacilities.h>
#include <workflow/WFTaskFactory.h>
#include <signal.h>
#include <iostream>
using std::cout;

static WFFacilities::WaitGroup waitGroup(1);

void sighandler(int signum)
{
    cout << "done!\n";
    waitGroup.done();
}

int main()
{
    signal(SIGINT, sighandler);
    
    WFHttpTask *httpTask = WFTaskFactory::create_http_task(
            "http://www.baidu.com", 
            10, 10, nullptr); //给任务对象申请内存并初始化
    protocol::HttpRequest *req = httpTask->get_req();  //找到请求的地址
    req->add_header_pair("Agent", "Workflow"); //给请求添加一个首部字段
    req->add_header_pair("name", "Edward"); //给请求添加一个首部字段
    httpTask->start(); //异步启动任务,把任务交给框架,由框架调度资源运行
    
    waitGroup.wait();
    cout << "finished!\n";
    return 0;
}

在这里插入图片描述


①阅读代码的流程

②函数参数使用指针的场景

在这里插入图片描述


③http任务的执行过程

在这里插入图片描述


④一些函数接口

append_output_body:将数据追加到HTTP响应报文的主体部分 (body)


(2)redis任务

1.req:set_request
任务开始前

2.resp:get_result
回调函数,获取执行结果

在这里插入图片描述


(3)mysql任务

在这里插入图片描述
在这里插入图片描述

1.执行多个指令 do while
在这里插入图片描述

2.写类型
在这里插入图片描述

3.读类型 表的结构(列)
在这里插入图片描述
在这里插入图片描述

4.表的内容(行)
在这里插入图片描述



5.序列:让多个任务先后顺序执行

序列:由任务组成的一个队列。
序列交给框架后,可以顺序执行。
序列是workflow的核心机制之一,SeriesWork

在这里插入图片描述
在这里插入图片描述


(1)静态方案:提前创建好所有的任务 create_series_work

task的start方法底层也是用到了序列

不同序列是并发执行。同一个序列中的任务是顺序执行。
在这里插入图片描述


(2)动态方案:在程序运行过程中,动态添加任务

series_of():找到一个正在运行的任务所在的序列,即只能写在个前一个任务的回调函数中。
push_back():往序列末尾插

在这里插入图片描述
在这里插入图片描述


(3)使用序列context机制在多个任务之间共享数据

context是一个void *类型,是用于一个序列内部共享数据的。

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述


内存释放
在这里插入图片描述


6.并行任务

(1)workflow的第二个核心机制:并行任务

在这里插入图片描述


(2)并行任务的特点

(1)并行任务是一个任务,所以并行任务本身可以放入一个大序列中。
(2)并行任务的内部有很多个小序列
(3)并行任务的基本工作是复杂的 ,是执行所有小序列并等待其完成,等待最后一个序列做完
(4)并行任务的基本工作做完后,可以执行并行任务的回调函数。


(3)并行任务的使用步骤 (如何使用并行任务)

(1)创建一个空的并行任务;
(2)往并行任务内部加序列:
①先创建一个任务
②根据任务创建序列
③若有必要申请内存context,保存额外的数据
(3)设计并行任务的回调函数
①在内部序列都执行完以后才会调用并行任务的回调
②在回调中可以访问小序列的context,但不能修改
(4)并行任务本身就是一个任务,可以放入一个大序列当中去运行。


在这里插入图片描述
在这里插入图片描述


在这里插入图片描述


(4)并行任务示例

第一步:同时发送请求
第二步:保存一些信息
第三步:改并行任务的回调函数
第四步:将结果写入redis


示意图
在这里插入图片描述


(5)在Linux中调试网络问题

1.使用命令分析网络状态
netstat
ifconfig
ps -elLf
route

2.tcpdump -i any port 80 -w
/home/edward/test.cap

3.使用wireshark进行分析操作


7.workflow作为服务端

(1)服务端与客户端的不同

①服务端是被动的,客户端是主动的。服务端需要一个server对象,监听客户端的连入和发消息,由server去创建任务和序列
②数据方向不一致:任务对象已经创建好了

在这里插入图片描述


(2)设计一个特殊的http任务

(1)存在个server对象。server对象会在客户端连入时创建一个序列和任务。
(2)这个任务的基本工作是用户写的代码,称为process。用户根据业务逻辑生成响应。
(3)process执行过程中,可以将其他的任务加入到序列中。这个任务的基本工作和回调是分开的,不是连在一起的。该序列插入新任务会在process和回调之间。
(4)回复响应的时机:所有任务执行完毕,回调执行之前的时刻。
在这里插入图片描述


(3)Echo业务服务器

//0_server.cc


(4)登录业务服务器

//1_login_server.cc

在这里插入图片描述
在这里插入图片描述

process()
在这里插入图片描述

在这里插入图片描述


(5)其他类型的业务

在这里插入图片描述


8.序列化方案:json

1.序列化方案:xml、json
在这里插入图片描述

2.JSON比XML更轻量级。
json既可以是object (键值对的集合),也可以是array (值的有序集合)。

3.值的7种数据类型 (键必须是字符串)
object:对象 { },键值对的集合
array:数组 [ ],值的有序集合
string:字符串 " "
number:数字
“true”
“false”
“null”

在这里插入图片描述
在这里插入图片描述


4.C++ json库:
github搜json:nlohman/json
header-only形式:只用加头文件,不需要加链接选项

在这里插入图片描述


5.json对象
代码链接:https://github.com/WangEdward1027/workflow/blob/main/json/json.cpp

(1)json对象是object:下标填字符串
dump()是序列化

#include <iostream>
#include "nlohmann/json.hpp"
int main(){
    nlohmann::json json_object;//创建空的json对象
    json_object["key"] = "value"; // json对象是一个object "key":"value"
    std::cout << json_object.dump() << "\n"; // dump方法 序列化
    return 0;
}

(2)json对象是array:下标填数字
数组可用push_back方法
在这里插入图片描述


(3)序列化:dump()方法
反序列化/解码/解析:parse()方法


9.wfrest

(1)提出原因

workflow的缺点:手动写proces,process里内容很多
①若workflow作为服务端如果要写多个业务,process里需要多个if、else if。
②workflow没有提供解析的功能:process中需要手动解析请求,查询参数query 或 报文体body。

wfrest的提出原因:
wfrest框架是对wokflow服务端的简化,不用自己写proces,wfrest框架会自动生成process。


(2)wfrest安装

wfrest是一个基于workflow的C++服务端框架,它简化了workflow服务端的使用方法,并且还提供了很
多辅助函数,包括URI路由、查询参数获取、表单数据获取等等。

unzip wfrest-0.9.5.zip
cd wfrest-0.9.5

mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig

(3)wfrest的使用

1.process已经写好了。

2.每调用一次GET POST PUT,就相当于在process中加了一个分支。

3.简化了操作:
①String -> append_out_of_body
②File-> 不用open文件了

4.提供了很多解析的功能:
①查询参数:query_list
②报文体:ulencoded_form_kv (小数据)
③报文体:form-data form (大数据)

5.在wfrest中如何使用序列:
①希望在序列中u的其他任务,去修改客户端响应内容
handler写成三个参数的版本:(请求,响应,序列)

server.POST("/login",[](const wfrest::HttpReq *req, wfrest::HttpResp *resp, SeriesWork * series){

在这里插入图片描述

在这里插入图片描述


(4)底层原理

1.process自动生成。
2.用户每调用一次GET、POST,process自动加if、else if
3.用户GET方法传入的handler会被包装成一个go_task类型的任务,当需要被调用的时候,会把任务加入到序列中,会变为序列中的一个任务。
在这里插入图片描述

4.headers:派生类功能更多,更方便
在这里插入图片描述

5.解析查询参数
在这里插入图片描述

6.解析urlencodeed类型的报文体
在这里插入图片描述

7.wfrest的handler:三参数的版本(请求,响应,序列)
在这里插入图片描述

8.用wfrest重写登录服务器
在这里插入图片描述



四、微服务相关技术

1.云存储:阿里云 OSS

1.购买服务
(1)网址:https://www.aliyun.com/product/oss

在这里插入图片描述

在这里插入图片描述


(2)生成AccessKey,保存AccessKey和ID
(3)创建Bucket
在这里插入图片描述


2.OSS的使用
(1)用起来就像一个网盘一样,作为备份。
(2)OSS本质上是一个服务器,它暴露了http接口。作为工具库,遵循REST风格。


3.API:应用程序接口,如http接口
SDK:将(http)接口用不同语言的代码进行封装,封装(http)操作。


4.安装阿里云的cpp SDK
(1)下载:https://github.com/aliyun/aliyun-oss-cpp-sdk/releases

(2)安装curl依赖

sudo apt install libcurl4-gnutls-dev

(3)cmake

tar xf aliyun-oss-cpp-sdk-1.10.0.tar.gz
cd aliyun-oss-cpp-sdk-1.10.0
mkdir build
cd build
cmake ..            #生成Makefile文件到build目录中。有可能报错,缺乏依赖。
make                #编译和连接
sudo make install   #拷贝头文件和库文件到系统目录
sudo ldconfig       #更新链接器缓存

(4)编译

g++ aliyun_OSS_put.cpp -fno-rtti -lalibabacloud-oss-cpp-sdk -lcurl -lcrypto -lpthread
g++ aliyun_OSS_get.cpp -o aliyun_OSS_get -g -std=c++11 -fno-rtti -lalibabacloud-oss-cpp-sdk -lcurl -lcrypto -lpthread

5.写代码使用OSS
(1)上传文件
代码链接:https://github.com/WangEdward1027/workflow/blob/main/OSS/aliyun_OSS_put.cpp


(2)下载文件:生成文件的下载链接
代码链接:https://github.com/WangEdward1027/workflow/blob/main/OSS/aliyun_OSS_get.cpp

在这里插入图片描述
在这里插入图片描述


(3)将OSS接入项目
上传,备份,回复响应。
后两步从同步改为异步。解除备份和回复响应之间的耦合性。
用消息队列:rabbitMQ
在这里插入图片描述



2.容器 docker

容器是轻量级的虚拟机。

(1)docker安装

1.首先先确认一下自己的Ubuntu版本:

# 查看Ubuntu版本
cat /etc/issue	

2.按照顺序执行下列指令(Ubuntu22的同学不执行2.1 ):

# 1 更新软件源和依赖
sudo apt update
# 2 安装前置依赖
sudo apt install ca-certificates curl gnupg lsb-release

# 2.1 如果是Ubuntu20和Ubuntu18的同学执行
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

# 3 新增软件源,并下载docker (如果提示密钥有风险的警告,可以无视)
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# 3.1 如果3报错提示没有公钥,执行下列命令,再重新执行3
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 7EA0A9C3F273FCD8

# 4 安装docker
sudo apt install docker-ce docker-ce-cli containerd.io

# 5 检查docker是否安装完成,先切换到root用户
sudo su
docker ps -a 

在这里插入图片描述


3.配置阿里云镜像源

#按顺序执行下面的命令
sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF'
# 在stdin中输入下面的内容, 配置镜像加速
{
    "registry-mirrors": [
    	"https://rrvyoa7a.mirror.aliyuncs.com",
        "https://hub.uuuadc.top",
        "https://docker.anyhub.us.kg",
        "https://dockerhub.jobcher.com",
        "https://dockerhub.icu",
        "https://docker.ckyl.me",
        "https://docker.awsl9527.cn"
    ]
}
EOF

#重新加载
sudo systemctl daemon-reload
sudo systemctl restart docker

修改镜像加速:/etc/docker/daemon.json
在这里插入图片描述

4.测试镜像的拉取

# 切换到root 并测试镜像的拉取功能
sudo su
docker run hello-world

5.拉取Rabbitmq镜像

sudo su
docker pull rabbitmq:management

(2)docker的概念

1.docker是轻量级的虚拟机。

2.为什么需要虚拟机?
简化环境配置工作、简化混合部署工作、独立更新
在这里插入图片描述


3.一个完整的虚拟机
两种虚拟机:https://blog.csdn.net/Edward1027/article/details/131837146

(1)第一种虚拟机
优点:虚拟化程度高
缺点:性能差:内存占用大、CPU指令
在这里插入图片描述


4.为了提升虚拟机的性能:提出了第二种虚拟机,即轻量级虚拟机docker
(1)共享内存和硬件,来降低
(2)底层原理:
CGroup:限制资源使用量
NameSpace:提供隔离性

图来自官网的官方文档:https:docker.com
在这里插入图片描述

在这里插入图片描述


(3)容器和镜像

镜像是静态的,运行起来的镜像就叫容器。
将容器打包成的文件就叫镜像。


(4)docker命令

docker命令只能在root用户下执行。要么直接sudo su 状态,要么每次docker命令前都要加sudo。

①镜像命令

1.查看所有的镜像:

docker images

2.用于标识某个镜像:
①REPOSITORY:TAG
②IMAGE ID

这两种方式在效果上没有区别
REPOSITORY:TAG 是对人类更友好的表示方法,便于识别和操作。
IMAGE ID 是机器更友好的标识符,通常用于内部处理和命令中当唯一标识符使用。

3.拉取镜像

docker pull nginx:1.26  #会默认从 https://hub.docker.com/_/nginx上拉取镜像

docker pull 命令是用来从 Docker 镜像仓库(通常是 https://hub.docker.com/)中拉取镜像的。

4.删除某个镜像:docker rmi

docker rmi nginx:58niqiu
docker rmi IMAGE ID

②容器命令

1.启动容器 / 进入容器
(1)启动容器,运行某个镜像

docker run nginx:Tag

(2)以守护进程方式启动容器

docker run -d 容器名 

(3)启动并进入容器,并启动一个命令行解释器shell

docker run -it nginx:lateset /bin/bash

(4)在容器外,进入正在运行的容器

docker exec -it 容器名或id /bin/bash 

(5)端口映射:让容器当作服务器

docker run -d -p 宿主机端号:容器端号 镜像名
docker run -d -p 8888:80 nginx:latest 

在这里插入图片描述


2.退出容器
(1)退出容器,但不停止容器

crtl+ p + q

(2)退出并停止容器

ctrl + c    

3.查看容器

docker ps     #查看运行中的容器
docker ps -a  #查看所有的(包括已停止)的容器

4.停止容器

docker stop id

5.恢复容器运行

docker start 容器名

6.删除停止的容器: docker rm

docker rm 仓库名 Tag  #删除某一个容器
docker ps -a -q | xargs docker rm  #删除所有的容器

7.将容器的内容打包成镜像
先退出容器

docker commit 

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


9.打包镜像的脚本:Dockerfile
在这里插入图片描述


10.持久化

docker run -d -p 8890:80 -v 宿主机路径:容器路径 

在这里插入图片描述

在这里插入图片描述



3.消息队列 和 RabbitMQ

(1)虚拟机技术

我们没学过Erlang和Java,只会C++,用虚拟机技术来使用别人配好的环境,来避免自己配置环境,通过网络进行连接。

但虚拟机占用的资源很多,很卡,考虑轻量级的虚拟机,那就是容器docker
在这里插入图片描述


(2)消息队列

1.消息队列的用途:
①存储和转发
②同步改异步
③消息持久化
④排队:削峰。解决瞬时大流量问题。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


2.常见的消息队列
(1)RabbitMQ:性能差,不会丢失消息。
(2)Kafka:性能好,但占用资源多,有概率丢消息
(3)RocketMQ:阿里巴巴防Kafka

在这里插入图片描述


3.支持的协议:AMQP (Advanced Message Queuing Protocol)
(1)队列:Queue
(2)交换器:exchange。有4种交换器,这里介绍直连交换器direct
(3)绑定规则:binding
在这里插入图片描述

4.直连交换器 direct
一个消息只能带一个key
在这里插入图片描述


5.安装AMQP的C++SDK
(1)rabbitmq-c:rabbitmq-c-0.11.0.tar.gz,先装c
(2)SimpleAmqpClient:SimpleAmqpClient-2.5.1.tar.gz,再装C++

(1)rabbitmq-c

tar xf rabbitmq-c-0.11.0.tar.gz
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig

(2)SimpleAmqpClient
先装 依赖库 Boost

sudo apt install libboost-dev
sudo apt install libboost-system-dev
sudo apt install libboost-chrono-dev
tar xf SimpleAmqpClient-2.5.1.tar.gz
mkdir build; cd build; cmake ..; make; sudo make install; sudo ldconfig

(3)rabbitmq

1.rabbitmq占用三个端口:
①5672:AMQP (代码)
②15672:HTTP (网页)
③25672:集群通信

2.使用Docker启动rabbitmq服务端:

sudo docker run -d --hostname rabbitsvr --name rabbit -p 5672:5672 -p 15672:15672 -p 25672:25672 -v /data/rabbitmq/:/var/lib/rabbitmq rabbitmq:management

启动后,在浏览器输入:192.168.49.132:15672
账户密码均为guest

在这里插入图片描述


(4)消息队列的代码

1.Channel BasicMessage
在这里插入图片描述
在这里插入图片描述

2.生产者 发布消息
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.两种消费模式
阻塞式 比 非阻塞式 效率更高,因为网络通信慢
在这里插入图片描述

4.消费者
(1)BasicConsume
在这里插入图片描述
在这里插入图片描述

(2)消费者
在这里插入图片描述

5.将消息队列接入网盘项目
在这里插入图片描述

6.消息队列的优点:
(1)性能上的好处 响应时间变短了
(2)业务开发上的好处 ————解除 上传和备份之间的耦合

7.消息队列的缺点:
①改造需要异步接口
②代码的改动很大

考虑用函数调用来代替消息传递



4.RPC 和 微服务

(1)RPC:远程过程调用

1.RPC:远程过程调用

2.功能:让函数的主调方和被调方可以在不同的机器上
在这里插入图片描述

3.RPC和REST有什么区别
(1)相同点:
目标是一致 让网络通信像函数调用一样
(2)不同点:
①RPC是一个技术
REST是一个规范
②RPC一般是应用层和传输层之间,基于私有协议
REST是在应用层或者更上面,基于HTTP协议
③一般REST接口服务器作为API网关,rpc服务器执行微服务。
在这里插入图片描述


(2)常见的rpc框架

①thrift:Facebook
②grpc:google;序列化方案 protobuf
③brpc:百度
④trpc/tars:腾讯
⑤srpc:搜狗。workflow(服务端) + protobuf (序列化和反序列化)

①grpc

1.grpc 代理模式:
在这里插入图片描述


protobuf框架:序列化和反序列化

1.序列化方案protobuf
(1)应用领域:
①RPC框架
②游戏
(2)特点:
①二进制方式:小且快
②兼容性强:跨语言,不同语言可通过protobuf相互使用

2.安装protobuf :

sudo apt-get install autoconf automake libtool curl make g++ unzip
./autogen.sh  #这两条合起来 相当于cmake ..
./configure	  #这两条合起来 相当于cmake ..
make; sudo make install; sudo ldconfig    #protobuf的安装比较慢,大约20分钟

3.判断安装成功:

protoc

在这里插入图片描述

4.先写一个proto文件:IDL(接口定义语言)
①定义结构体
②定义函数
在这里插入图片描述

通过编译指令,可以生成不同语言的代码
在这里插入图片描述

protoc --proto_path=.  --cpp_out=.  signup.proto

在这里插入图片描述


srpc框架:网络通信和代理模式

先执行protobuf操作,再执行srpc的操作

1.安装srpc
(1)安装依赖

sudo apt install liblz4-dev
sudo apt install libsnappy-dev

(2)解压安装

tar xf srpc-0.10.2.tar.gz
mkdir build; cd build; cmake ..; make; sudo make install; sudo ldconfig

(3)验证安装是否成功

srpc_generator

在这里插入图片描述


2.生成客户端和服务端
(1)客户端和服务端放在相同的目录
在这里插入图片描述
在这里插入图片描述

(2)若想客户端和服务端放在不同的目录
在这里插入图片描述

Makefile:
增量编译:编译很慢,链接很快。
链接错误:看报错缺的第一个库,开始解决

在这里插入图片描述


在这里插入图片描述

3.先执行protobuf操作,再执行srpc的操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.如何使用srpc
(1)先写 proto/IDL文件 参数、返回值、函数名
(2)用protoc 从 proto文件 转成C++代码 (*.pb.cc *.pb.h)
(3)用srpc_generator 从 proto文件 转成样例的客户
端和服务端代码 (*.srpc.h client代码 server代码 )

在这里插入图片描述

5.服务端的代码怎么样写?
在这里插入图片描述
在这里插入图片描述

6.客户端代码
在这里插入图片描述

7.接入web网盘项目以后的情况
在这里插入图片描述



五、项目实战:基于http协议的简易web网盘

读写分离 (长短命令分离):
将下载和其他业务(注册、登录、上传)分离。90%的流量都集中在下载。
nginx专门作为下载服务器,分压。
在这里插入图片描述


1.上传功能

1.哈希值:md5码、sha1值

解决碰撞问题的方法:面试官提问,若文件特别多,md5码重复了怎么办?
概率非常低:几亿分之一,目前还未碰到过
md5值换sha1值:碰撞概率会再下降几十万倍
存储额外信息:如文件的前5-10个字节,拼接在md5码或sha1值之后。


2.下载功能

下载是流量最大的业务,考虑将下载功能与注册、登录、上传 分离开。
让实际下载的功能不由CloudiskServer完成。
只做下载功能的服务器,就是一个静态资源服务器。

在这里插入图片描述

实现重定向(301,302)到nginx。nginx作为下载的静态资源服务器。


3.给网盘加上备份功能

CAP定理:可用性,一致性,分区容错性
在这里插入图片描述

1.分布式系统:多个节点组成的系统

2.①IaaS (Infrastructure as a Service):基础设施即服务。指把IT基础设施作为一种服务通过网络对外提供,并根据用户对资源的实际使用量或占用量进行计费的一种服务模式。基础设施是买的。
②PaaS:平台即服务。买平台。
③SaaS:软件即服务。整个软件都是买的。

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到