【负载均衡oj】(七)ojserver

一.目的

负责负载均衡,获取网站首页,通过网络罗调用编译并运行并提供结果给用户。根据用户的操作提供不同的功能。采用mvc结构。使用 ctemplate文字模板做数据渲染

m在这里指的是和数据的交互,可以用文件或者sql交互。在使用文件的情况下,就必须要有对应的文件目录存放每一道题。提供题目描述和题头还有测试用例。

二.实现model

负责将文件题库抽象成数据结构,并提供接口给ojcontrol调用。ojcontrol通过model模块获取全部的题目信息和测试用例,用来交给后端服务继续运行

题的数据结构

  typedef struct Question // 每一道题对应的基本信息{string number;    // 题目编号string title;     // 题目名称string diffculty; // 题目难度int cpu_limit;    // 运行时间限制int mem_limit;    // 内存时间限制string desc;      // 题目描述string header;    // 题目提供给用户的首部代码string tailer;    // 题目的测试用例,需要和header拼接,形成完整代码}Question;

获取题信息的数据结构,因为是从文件中读取,所以需要一个字符串格分割函数。

加载所有题库信息到数据结构。

 bool LoadQuestionList(const string question_path)   //根据文件题目列表获取到数据结构内{ifstream in(questionlist_path); // 打开题目列表的文件流if (!in.is_open()) // 打开文件流失败{LOG(FATAL) << "加载题库失败,请检查是否存在题库文件"<< "\n";return false;}string line;while (getline(in, line)){vector<string> tokens;                       // 题的五个信息StringUtil::SplitString(line, &tokens, " "); // 根据空格分隔出不同元素if (tokens.size() != 5) // 每道题有五种基本信息(编号,题目,,难度,mem,cpu){LOG(WARNING) << "加载部分题目失败, 请检查文件格式"<< "\n";continue; // 获取当前题目信息失败直接跳过}Question q; // 创建题目对象填充信息q.number = tokens[0];q.title = tokens[1];q.diffculty = tokens[2];q.cpu_limit = atoi(tokens[3].c_str());q.mem_limit = atoi(tokens[4].c_str());// 获取题目详细信息string path = question_path; // 需要拼出对应的题目路径path += q.number;path += "/";// 从文件内读出内容并填充进题目结构体里FileUtil::ReadFile(path + "desc.txt", &(q.desc), true);FileUtil::ReadFile(path + "header.cpp", &(q.header), true);FileUtil::ReadFile(path + "tail.cpp", &(q.tailer), true);// 形成哈希映射questions.insert({q.number, q});}LOG(INFO) << "题库加载成功"<< "\n";in.close();return true;}

获取一道题给客户

 bool GetOneQuestion(const string &number, Question *ret) // 通过题号获取对应题{const auto &iter = questions.find(number);if (iter == questions.end()){LOG(ERROR) << "用户获取题目失败, 题目编号: " << number << "\n";return false;}*ret = iter->second; // 输出行参数return true;}

获取所有题目给客户

bool GetAllQuestion(vector<Question> *out){if (questions.size() == 0){LOG(ERROR) << "用户获取题库失败"<< "\n";return false;}for (auto &q : questions){out->push_back(q.second); // 遍历哈希映射把题目信息依次录入vector}return true;}

三.control模块

主要实现逻辑控制,从网页上拿来各种信息,提取有用信息后,结合本地数据向后端提交,如判题功能,或者根据要求获取对应本地信息,并通过前段模块返回给用户

 // 核心业务逻辑class Control // 控制ojserver的基础功能,包括修改题库和前端界面交互,整合数据控制和前端交互{private:ns_model::Model _model; // 提供后台数据View _view;             // 提供html渲染功能LoadBalance _load;      // 提供负载均衡模块public:void RecoveryMachine(){_load.OnlineMachine();}// 获取所有题目并生成html文件bool AllQuestions(string *html) // 输出型参数{vector<Question> all;if (_model.GetAllQuestion(&all)) // 获取所有题目到vector内{// 获取信息成功构建htmlsort(all.begin(),all.end(),[](const Question& q1,const Question& q2){ return atoi(q1.number.c_str())<atoi(q2.number.c_str());});_view.AllExpandHtml(all, html);}else{*html = "获取题目失败, 形成题目列表失败";return false;}return true;}// 获取一道题bool OneQuestion(const string &number, string *html){Question q;if (_model.GetOneQuestion(number, &q)){_view.OneExepandHtml(q, html);return true;}else{*html = "指定题目: " + number + " 不存在!";return false;}}// 判断用户代码是否正确void Judge(const string &in_json, string *outj_son, const string &number){// 需要读取上来用户的代码并和测试用例拼接成一份完整代码最后// 0. 根据题目编号,直接拿到对应的题目细节Question q;_model.GetOneQuestion(number, &q);// 1. in_json进行反序列化,得到题目的id,得到用户提交源代码,inputJson::Reader reader;Json::Value usr_val;reader.parse(in_json, usr_val);string code = usr_val["code"].asString(); // 用户写的代码// 2. 重新拼接用户代码+测试用例代码,形成新的代码Json::Value compile_val;compile_val["code"] = code + '\n' + q.tailer;compile_val["input"] = usr_val["input"].asString();compile_val["cpu_limit"] = q.cpu_limit;compile_val["mem_limit"] = q.mem_limit;// 序列化准备传输Json::FastWriter writer;std::string compile_string = writer.write(compile_val);// 3. 选择负载最低的主机(差错处理)// 规则: 一直选择,直到主机可用,否则,就是全部挂掉while (true){int id;Machine *m;// 跟据负载选择服务器if (!_load.SmartChoice(&m, &id)){break; // 选择主机失败}// 4. 选择完主机后发起http请求链接到主机Client cli(m->_ip, m->_port);m->IncLoad();LOG(INFO) << " 选择主机成功, 主机id: " << id << " 详情: " << m->_ip << ":" << m->_port << " 当前主机的负载是: " << m->Load() << "\n";// 5.将数据提交给服务主机并进行编译运行if (auto res = cli.Post("/Compile_and_run", compile_string, "application/json;charset=utf-8")) // 这个请求完成编译运行并返回结果{// 需要判断返回结果,有返回结果不一定成功运行if (res->status == 200) // 200表示成功运行{// 将结果返回给用户*outj_son = res->body;m->DecLoad();LOG(INFO) << "主机执行任务成功"<< "\n";break;}// 若提交失败也需要将负载复原并重新执行该流程m->DecLoad();}else{// 请求失败(当前主机不存在)LOG(ERROR) << " 当前请求的主机id: " << id << " 详情: " << m->_ip << ":" << m->_port << " 可能已经离线"<< "\n";_load.OfflineMachine(id);_load.ShowMachines(); // 仅仅是为了用来调试}}}

四.view模块

在拿到model的题目信息后,结合本地html进行渲染,给用户提供前端展示页面。采用ctemplate渲染。

通过互取到的所有题目信息,使用ctemplate渲染展示给用户。

// 获取所有题目并生成html文件bool AllQuestions(string *html) // 输出型参数{vector<Question> all;if (_model.GetAllQuestion(&all)) // 获取所有题目到vector内{// 获取信息成功构建htmlsort(all.begin(),all.end(),[](const Question& q1,const Question& q2){ return atoi(q1.number.c_str())<atoi(q2.number.c_str());});_view.AllExpandHtml(all, html);}else{*html = "获取题目失败, 形成题目列表失败";return false;}return true;}

一道题

 bool OneQuestion(const string &number, string *html){Question q;if (_model.GetOneQuestion(number, &q)){_view.OneExepandHtml(q, html);return true;}else{*html = "指定题目: " + number + " 不存在!";return false;}}

五.负载均衡

我们需要以一个文件存放所有可用的主机和端口号。作为主机的配置文件。同时主机需要保存自身的负载情况,所以需要加锁。

class Machine // 标识提供服务的主机{public:std::string _ip; // 本机的ip端口号和负载程度int _port;uint64_t _load;std::mutex *_mtx; // 重点必须用指针不能用实例,容器内有拷贝,c++里的mutex是禁止拷贝的,只能用指针取地址绕过Machine(): _ip(""),_port(0),_load(0),_mtx(nullptr){}// 提升负载(有可能多个主机同时运行有竞争问题)void IncLoad(){if (_mtx){_mtx->lock();}_load++;if (_mtx){_mtx->unlock();}}// 降低负载void DecLoad(){if (_mtx){_mtx->lock();}_load--;if (_mtx){_mtx->unlock();}}// 获取主机负载,没有太大的意义,只是为了统一接口uint64_t Load(){uint64_t load = 0;if (_mtx)_mtx->lock();load = _load;if (_mtx)_mtx->unlock();return load;}void ResetLoad(){if (_mtx){_mtx->lock();}_load = 0;if (_mtx){_mtx->unlock();}}};

负载均衡模块负责所有主机的情况,包括是否上线。并提供负载最小的主机,也需要加锁,因为涉及到对所有主机属性的更改。算临界区

class LoadBalance // 负载均衡模块{// 可以给我们提供编译服务的所有的主机// 每一台主机都有自己的下标,充当当前主机的idvector<Machine> machines;// 所有在线的主机idstd::vector<int> online;// 所有离线的主机idstd::vector<int> offline;std::mutex mtx; //需要保证负载均衡的数据安全public:LoadBalance(){assert(LoadConf(service_machine));LOG(INFO) << "加载 " << service_machine << " 成功"<< "\n";}bool LoadConf(const string &machine_conf) // 从conf文件里读取上来所有主机信息{ifstream in(machine_conf); // 打开文件流if (!in.is_open()){LOG(FATAL) << " 加载: " << machine_conf << " 失败"<< "\n";return false;}// 读取数据到linestring line;while (getline(in, line)){vector<string> tokens; // 每一行切分到这里,只有两个元素,ip和端口号StringUtil::SplitString(line, &tokens, ":");if (tokens.size() != 2){LOG(WARNING) << " 切分 " << line << " 失败"<< "\n";continue;}// 读取数据完毕构建对象Machine m;m._ip = tokens[0]; // 填充ip和端口号m._port = atoi(tokens[1].c_str());m._load = 0;m._mtx = new std::mutex();online.push_back(machines.size()); // 先让所有机器数作为下标,在把主机放入主机列表machines.push_back(m);             // 抽象的哈希映射}in.close();return true;}bool SmartChoice(Machine **m, int *id) // 两个输出出行参数,返回选择的主机,或者看情况离线主机{                                      // 因为传参的时候不想通过下标访问,所以通过地址修改// 1. 选择主机(更新该主机的负载)// 2. 我们需要可能离线该主机// 选择主机有安全问题mtx.lock();int online_num = online.size(); // 检查活跃主机数if (online_num == 0){mtx.unlock();LOG(FATAL) << " 所有的后端编译主机已经离线, 请尽快查看"<< "\n";return false;}// 通过遍历的方式,找到所有负载最小的机器*id = online[0];*m = &machines[online[0]];uint64_t min_load = machines[online[0]].Load();for (int i = 0; i < online_num; i++) // 寻找最小负载{uint64_t cur_load = machines[online[i]].Load();if (cur_load < min_load){min_load = cur_load;*id = online[i];*m = &machines[online[i]];}}mtx.unlock();return true;}void OnlineMachine() // 上线服务器(一次直接全部上线){mtx.lock();online.insert(online.end(), offline.begin(), offline.end());offline.erase(offline.begin(), offline.end());LOG(INFO) << "重新登陆主机成功"<< "\n";mtx.unlock();}void ShowMachines() // 查看所有服务器状态{mtx.lock();std::cout << "当前在线主机列表: "<< "\n";for (auto &id : online){std::cout << id << " ";}std::cout << std::endl;std::cout << "当前离线主机列表: "<< "\n";for (auto &id : offline){std::cout << id << " ";}mtx.unlock();}void OfflineMachine(const int &mid) // 下线服务器{mtx.lock();for (auto iter = online.begin(); iter != online.end(); iter++) // 用迭代器遍历好一些,利于删除{if (*iter == mid){machines[mid].ResetLoad(); // 下线前清空负载online.erase(iter);offline.push_back(mid);break; // 因为break所以不用考虑迭代器失效,此时循环已经终止了}}mtx.unlock();}};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/601194.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CISP-DSG和CDGA该如何选择?

同样是数据治理&#xff0c;CDGA证书和CISP-DSG证书&#xff0c;它们之间有什么区别和各自的优势呢❓ 1️⃣CISP-DSG CISP-DSG证书聚焦于信息an全领域&#xff0c;特别guan注数据an全治理。 国际知名zi询机构Gartner用“风暴之眼”比喻“数据an全治理”&#xff0c;&#x1f44…

hyperf 基础合集

目前合计不包括数据库。 hyperf 一、搭建 -CSDN博客hyperf 二、路由 -CSDN博客hyperf 三、中间件 -CSDN博客hyperf 四、控制器 -CSDN博客hypef 五、请求及响应 -CSDN博客hyperf 六、异常处理 -CSDN博客hypef 七、配置文件的使用_-CSDN博客hypef 八、缓存 -CSDN博客hypef 九、日…

【机器学习】线性回归·可运行源码

一&#xff0c;基础函数库 import numpy as np from utils.features import prepare_for_trainingclass LinearRegression:def __init__(self, data, labels, polynomial_degree0, sinusoid_degree0, normalize_dataTrue):"""1.对数据进行预处理操作2.先得到所…

ssm基于java web 的QQ村旅游网站的设计+vue论文

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统旅游信息管理难度大&#xff0c;容错率低&#xff0c;管理…

el-select下拉框 change事件返回该项所有数据

主要代码 value-key <template><div><el-selectv-model"value"value-key"label"placeholder"请选择"change"selectChange"><el-optionv-for"item in options":key"item.label":label"…

云计算历年题整理

第一大题 第一大题计算 给出计算连接到EC2节点的EBS的高可用性(HA)的数学公式&#xff0c;如场景中所述&#xff1b;计算EC2节点上的EBS的高可用性(HA)&#xff1b;场景中80%的AWS EC2节点用于并行处理&#xff0c;总共有100个虚拟中央处理单元(vCPUs)用于处理数据&#xff0…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)在EventLoop的任务队列中添加新任务

任务队列是一个链表&#xff0c;每个节点包含channel类型、文件描述符和操作类型。在添加节点时&#xff0c;需要考虑线程同步&#xff0c;并确保节点被正确地添加到链表中。节点的操作可以写到另一个函数中&#xff0c;以便于程序的维护。在添加任务节点时&#xff0c;需要加互…

迅为RK3588开发板使用 FFMpeg 进行推流

Debian/Ubuntu 系统使用以下命令安装 FFMpeg &#xff0c;如下图所示&#xff1a; apt-get install ffmpeg 使用 ifconfig 查看开发板 ip 为 192.168.1.245 如下图所示&#xff1a; 使用 FFMpeg 推流一个 mp4 视频进行测试&#xff0c;作者将测试视频 test.mp4 放在了根目录下…

轻松入门:Anaconda 在 PyCharm 中的配置与应用指南

1 Anaconda Anaconda 和 Conda 是两个相关但不同的概念。 Anaconda 是一个免费且开源的发行版&#xff0c;包含了 Python 和 R 语言的数据科学和机器学习相关的众多包&#xff0c;它包括 Conda、Python、Jupyter Notebook 等多个科学计算和数据科学中常用的应用。 Anaconda 通过…

2022年山东省职业院校技能大赛高职组信息安全管理与评估—开发测试服务器解析

任务5:开发测试服务器 目录 任务5:开发测试服务器 解题方法:

外包干了4个月,技术退步明显了...

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01; 而我已经在一个企业干了四…

K8S陈述式资源管理(1)

命令行: kubectl命令行工具 优点: 90%以上的场景都可以满足对资源的增&#xff0c;删&#xff0c;查比较方便&#xff0c;对改不是很友好 缺点:命令比较冗长&#xff0c;复杂&#xff0c;难记声明式 声明式&#xff1a;K8S当中的yaml文件来实现资源管理 GUI&#xff1a;图形…

第九节HarmonyOS 常用基础组件7-RichText

1、描述 富文本组件&#xff0c;解析并显示HTML格式文本。 富文本&#xff08;RichText&#xff09;是一种特殊的文本格式&#xff0c;它比普通文本更加丰富多彩。富文本可以包含各种字体、颜色、大小、图像、链接、表格、视频等元素&#xff0c;使文本更加生动、有趣。 2、…

【elastic search】下载安装、使用教程

目录 1.下载安装 1.1.ES&Kibana 1.2.分词器 2.操作 2.1.索引操作 2.1.1.索引的新增、删除、查找 2.1.2.数据类型 2.1.3.结构化 2.2.文档操作 2.2.1.文档的增、删、改 2.2.2.文档的查询 2.2.3.聚合操作 1.下载安装 1.1.ES&Kibana Kibana是一个开源的数据可…

WPF中MVVM手动实现PropertyChanged和RelayCommand

背景&#xff1a;PropertyChanged和Command总是没有记住怎么写 PropertyChanged&#xff1a; public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName null) {PropertyChanged?.In…

vue3中Element Plus全局组件配置中文的两种方案

Element是一款用于制作页面样式&#xff0c;设计页面结构的框架。相比于其他的几个框架&#xff0c;这个框架设计的更为人性化&#xff0c;对企业级框架VUE的集成也很高。 Element Plus 组件 默认 使用英语&#xff0c;如果你希望使用其他语言&#xff0c;你可以参考下面的两种…

OpenHarmony如何隐藏系统状态栏、导航栏

前言 OpenHarmony源码版本&#xff1a;4.0release 开发板&#xff1a;DAYU / rk3568 一、通过setWindowSystemBarEnable方法设置 当我们应用的Alility继承的是UIAbility时&#xff0c;可以onWindowStageCreate(windowStage: window.WindowStage)方法中实现如下操作&#xf…

【AI】搭建Windows Linux子系统(WSL2)CUDA环境

0.准备工作 Windows本机安装CUDA Driver 首先去下载页面下载驱动文件 点击Get CUDA Driver进入下载页面&#xff0c;我看下载页面跟普通驱动下载页面相同&#xff0c;感觉应该不是单独的驱动&#xff0c;只要之前显卡已经安装好了CUDA的驱动&#xff0c;就可以先省略这一步。…

spi_2024.1.2

spi.h #ifndef __SPI_H__ #define __SPI_H__#include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h"#include"uart4.h" #include"key_it.h" // MOSI对应的引脚输出高低电平的信号PE14 #define MOSI_OUTPUT_H() do{GPIOE->O…

Linkage Mapper 工具参数详解——Climate Linkage Mapper

从以下链接中获取内容&#xff08;识别二维码、填写问卷、获取联系方式&#xff09; Linkage Mapper 报错_python error on **line 806** of lm_util.py in link-CSDN博客 此工具涉及参数非常多&#xff0c;后台需调用其他GIS平台&#xff08;并且限定版本&#xff09;&#x…