528.按权重随机选择(前缀和二分法)加权负载均衡

发布时间:2026/9/10 22:59:38

528.按权重随机选择(前缀和二分法)加权负载均衡 链接528. 按权重随机选择 - 力扣LeetCode题解1、把权重累加构建前缀和数组2、random()%权重sum3、二分查找在前缀和数组class Solution { public: Solution(vectorint w) { if (w.size() 0) { _w_prefix_sum.resize(w.size()); _w_prefix_sum[0] w[0]; _sum w[0]; for (int i 1; i w.size(); i) { _w_prefix_sum[i] w[i] _w_prefix_sum[i-1]; _sum w[i]; } } } int pickIndex() { int val random() % _sum; //if (val _w_prefix_sum[0]) return 0; int left 0; int right _w_prefix_sum.size(); while (left 1 right) { int mid left (right-left) /2; // 如果相等的化应该查找第一个大于 val 的前缀和位置 if (_w_prefix_sum[mid] val) { left mid; } else if (_w_prefix_sum[mid] val) { right mid; } else { left mid; } } if (val _w_prefix_sum[left]) { return left; } return right; } int _sum; vectorint _w_prefix_sum; }; /** * Your Solution object will be instantiated and called as such: * Solution* obj new Solution(w); * int param_1 obj-pickIndex(); */加权负载均衡算法include algorithm #include butil/fast_rand.h #include brpc/socket.h #include brpc/policy/weighted_round_robin_load_balancer.h #include butil/strings/string_number_conversions.h namespace { const std::vectoruint64_t prime_stride { 2,3,5,11,17,29,47,71,107,137,163,251,307,379,569,683,857,1289,1543,1949,2617, 2927,3407,4391,6599,9901,14867,22303,33457,50207,75323,112997,169501,254257, 381389,572087,849083,1273637,1910471,2865727,4298629,6447943,9671923,14507903, 21761863,32642861,48964297,73446469,110169743,165254623,247881989,371822987, 557734537,836601847,1254902827,1882354259,2823531397,4235297173,6352945771, 9529418671}; bool IsCoprime(uint64_t num1, uint64_t num2) { uint64_t temp; if (num1 num2) { temp num1; num1 num2; num2 temp; } while (true) { temp num1 % num2; if (temp 0) { break; } else { num1 num2; num2 temp; } } return num2 1; } // Get a reasonable stride according to weights configured of servers. uint64_t GetStride(const uint64_t weight_sum, const size_t num) { if (weight_sum 1) { return 1; } uint32_t average_weight weight_sum / num; auto iter std::lower_bound( prime_stride.begin(), prime_stride.end(), average_weight); while (iter ! prime_stride.end() !IsCoprime(weight_sum, *iter)) { iter; } CHECK(iter ! prime_stride.end()) Failed to get stride; return *iter weight_sum ? *iter % weight_sum : *iter; } } // namespace namespace brpc { namespace policy { bool WeightedRoundRobinLoadBalancer::Add(Servers bg, const ServerId id) { if (bg.server_list.capacity() 128) { bg.server_list.reserve(128); } uint32_t weight 0; if (!butil::StringToUint(id.tag, weight) || weight 0) { if (FLAGS_default_weight_of_wlb 0) { LOG(WARNING) Invalid weight is set: id.tag . Now, weight has been set to FLAGS_default_weight_of_wlb by default.; weight FLAGS_default_weight_of_wlb; } else { LOG(ERROR) Invalid weight is set: id.tag; return false; } } bool insert_server bg.server_map.emplace(id.id, bg.server_list.size()).second; if (insert_server) { bg.server_list.emplace_back(id.id, weight); bg.weight_sum weight; return true; } return false; } bool WeightedRoundRobinLoadBalancer::Remove(Servers bg, const ServerId id) { auto iter bg.server_map.find(id.id); if (iter ! bg.server_map.end()) { const size_t index iter-second; bg.weight_sum - bg.server_list[index].weight; bg.server_list[index] bg.server_list.back(); bg.server_map[bg.server_list[index].id] index; bg.server_list.pop_back(); bg.server_map.erase(iter); return true; } return false; } size_t WeightedRoundRobinLoadBalancer::BatchAdd( Servers bg, const std::vectorServerId servers) { size_t count 0; for (size_t i 0; i servers.size(); i) { count !!Add(bg, servers[i]); } return count; } size_t WeightedRoundRobinLoadBalancer::BatchRemove( Servers bg, const std::vectorServerId servers) { size_t count 0; for (size_t i 0; i servers.size(); i) { count !!Remove(bg, servers[i]); } return count; } bool WeightedRoundRobinLoadBalancer::AddServer(const ServerId id) { return _db_servers.Modify(Add, id); } bool WeightedRoundRobinLoadBalancer::RemoveServer(const ServerId id) { return _db_servers.Modify(Remove, id); } size_t WeightedRoundRobinLoadBalancer::AddServersInBatch( const std::vectorServerId servers) { const size_t n _db_servers.Modify(BatchAdd, servers); LOG_IF(ERROR, n ! servers.size()) Fail to AddServersInBatch, expected servers.size() actually n; return n; } size_t WeightedRoundRobinLoadBalancer::RemoveServersInBatch( const std::vectorServerId servers) { const size_t n _db_servers.Modify(BatchRemove, servers); return n; } int WeightedRoundRobinLoadBalancer::SelectServer(const SelectIn in, SelectOut* out) { butil::DoublyBufferedDataServers, TLS::ScopedPtr s; if (_db_servers.Read(s) ! 0) { return ENOMEM; } if (s-server_list.empty()) { return ENODATA; } TLS tls s.tls(); if (tls.IsNeededCalculateNewStride(s-weight_sum, s-server_list.size())) { if (tls.stride 0) { tls.position butil::fast_rand_less_than(s-server_list.size()); } tls.stride GetStride(s-weight_sum, s-server_list.size()); } // If server list changed, the position may be out of range. tls.position % s-server_list.size(); // Check whether remain server was removed from server list. if (tls.remain_server.weight 0 tls.remain_server.id ! s-server_list[tls.position].id) { tls.remain_server.weight 0; } // The servers that can not be chosen. std::unordered_setSocketId filter; TLS tls_temp tls; uint64_t remain_weight s-weight_sum; size_t remain_servers s-server_list.size(); while (remain_servers 0) { SocketId server_id GetServerInNextStride(s-server_list, filter, tls_temp); if ((remain_servers 1 // always take last chance || !ExcludedServers::IsExcluded(in.excluded, server_id)) Socket::Address(server_id, out-ptr) 0 (*out-ptr)-IsAvailable()) { // update tls. tls.remain_server tls_temp.remain_server; tls.position tls_temp.position; return 0; } else { // Skip this invalid server. We need calculate a new stride for server selection. if (--remain_servers 0) { break; } filter.emplace(server_id); remain_weight - (s-server_list[s-server_map.at(server_id)]).weight; // Select from beginning status. tls_temp.stride GetStride(remain_weight, remain_servers); tls_temp.position tls.position; tls_temp.remain_server tls.remain_server; } } return EHOSTDOWN; } SocketId WeightedRoundRobinLoadBalancer::GetServerInNextStride( const std::vectorServer server_list, const std::unordered_setSocketId filter, TLS tls) { SocketId final_server INVALID_SOCKET_ID; uint64_t stride tls.stride; Server remain tls.remain_server; if (remain.weight 0) { if (filter.count(remain.id) 0) { final_server remain.id; if (remain.weight stride) { remain.weight - stride; return final_server; } else { stride - remain.weight; } } remain.weight 0; tls.position; tls.position % server_list.size(); } while (stride 0) { final_server server_list[tls.position].id; if (filter.count(final_server) 0) { uint32_t configured_weight server_list[tls.position].weight; if (configured_weight stride) { remain.id final_server; remain.weight configured_weight - stride; return final_server; } stride - configured_weight; } tls.position; tls.position % server_list.size(); } return final_server; } LoadBalancer* WeightedRoundRobinLoadBalancer::New( const butil::StringPiece) const { return new (std::nothrow) WeightedRoundRobinLoadBalancer; } void WeightedRoundRobinLoadBalancer::Destroy() { delete this; } void WeightedRoundRobinLoadBalancer::Describe( std::ostream os, const DescribeOptions options) { if (!options.verbose) { os wrr; return; } os WeightedRoundRobin{; butil::DoublyBufferedDataServers, TLS::ScopedPtr s; if (_db_servers.Read(s) ! 0) { os fail to read _db_servers; } else { os n s-server_list.size() :; for (const auto server : s-server_list) { os server.id ( server.weight ); } } os }; } } // namespace policy } // namespace brpc#ifndef BRPC_POLICY_WEIGHTED_ROUND_ROBIN_LOAD_BALANCER_H #define BRPC_POLICY_WEIGHTED_ROUND_ROBIN_LOAD_BALANCER_H #include map #include vector #include unordered_set #include butil/containers/doubly_buffered_data.h #include brpc/load_balancer.h namespace brpc { namespace policy { // This LoadBalancer selects server as the assigned weight. // Weight is got from tag of ServerId. class WeightedRoundRobinLoadBalancer : public LoadBalancer { public: bool AddServer(const ServerId id) override; bool RemoveServer(const ServerId id) override; size_t AddServersInBatch(const std::vectorServerId servers) override; size_t RemoveServersInBatch(const std::vectorServerId servers) override; int SelectServer(const SelectIn in, SelectOut* out) override; LoadBalancer* New(const butil::StringPiece) const override; void Destroy() override; void Describe(std::ostream, const DescribeOptions options) override; private: struct Server { Server(SocketId s_id 0, uint32_t s_w 0): id(s_id), weight(s_w) {} SocketId id; uint32_t weight; }; struct Servers { // The value is configured weight for each server. std::vectorServer server_list; // The value is the index of the server in server_list. std::mapSocketId, size_t server_map; uint64_t weight_sum 0; }; struct TLS { size_t position 0; uint64_t stride 0; Server remain_server; // If server list changed, we need calculate a new stride. bool IsNeededCalculateNewStride(const uint64_t curr_weight_sum, const size_t curr_servers_num) { if (curr_weight_sum ! weight_sum || curr_servers_num ! servers_num) { weight_sum curr_weight_sum; servers_num curr_servers_num; return true; } return false; } private: uint64_t weight_sum 0; size_t servers_num 0; }; static bool Add(Servers bg, const ServerId id); static bool Remove(Servers bg, const ServerId id); static size_t BatchAdd(Servers bg, const std::vectorServerId servers); static size_t BatchRemove(Servers bg, const std::vectorServerId servers); static SocketId GetServerInNextStride(const std::vectorServer server_list, const std::unordered_setSocketId filter, TLS tls); butil::DoublyBufferedDataServers, TLS _db_servers; }; } // namespace policy } // namespace brpc
延伸阅读

更多相关文章

2026/9/10 22:54:37

基于 GB/T 3836 标准的油气站防爆对讲机选型与通信安全方案

文章定位:技术方案类,面向油气站安全管理人员、通信运维人员,梳理油气站防爆通信的标准要求、设备选型要点、组网方案、施工验收与运维保障。 核心内容:防爆标准要求 选型技术参数 组网方案 施工验收 运维培训 应用案例 4 个…

2026/9/10 23:49:43

Tracy Profiler 快速上手实战指南:4步定位游戏掉帧元凶

Tracy Profiler 快速上手实战指南:4步定位游戏掉帧元凶 【免费下载链接】tracy Frame profiler 项目地址: https://gitcode.com/GitHub_Trending/tr/tracy 你正在跑一个游戏,画面突然卡了一瞬,重跑一遍问题又消失了,日志里…

2026/9/10 23:49:42

SeaTunnel与Gravitino集成实现元数据自动化管理

1. 项目概述:当数据管道遇上元数据自动化在数据工程领域,手动维护Schema一直是ETL开发中最繁琐的环节之一。最近SeaTunnel与Gravitino的深度集成,通过RestAPI实现了元数据的自动化管理,这个看似简单的技术组合实际上解决了数据管道…

2026/9/10 23:44:42

H指数解析:学术影响力计算与应用指南

1. H指数:学术影响力的量化标尺作为一名长期跟踪学术评价指标的科研工作者,我经常需要向同行解释H指数的精妙之处。这个看似简单的数字背后,蕴含着对学者研究质量的立体化评估逻辑。2005年由物理学家Jorge Hirsch提出的H指数,如今…

2026/9/10 16:39:38

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/10 11:16:38

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/10 0:00:55

目录对比去重实战:用哈希算法精准清理重复文件

我电脑里现在还有一块换了三次机的“数据墓地”硬盘,里面存着2016年以前所有旧笔记本的完整备份。平时不觉得有什么,直到前阵子想把它整理归档,发现同一个安装包、同一批照片、同一份论文草稿,在几个不同的备份目录里反复出现。更…

2026/9/10 0:00:55

Leaflet离线地图完整Demo合集:内网部署与坐标纠偏实战

简介:这是一份面向Web GIS开发者的LeafLet离线地图示例合集,帮助开发者快速掌握离线地图从搭建到交互的完整流程。压缩包共723个文件,大小14.06MB,以319个js脚本、175个html页面和29个css样式文件为主体,配合png/svg图…

2026/9/10 0:00:55

MATLAB读取Rinex 3.02观测文件:多系统GNSS数据解析实战

简介:基于MATLAB开发的Rinex3.02版观测文件(o文件)读取代码包,面向卫星定位导航方向的学习者与研究人员,用于解决新版观测文件的数据解析、历元提取与时间转换问题。压缩包共4个文件,包含两个m脚本、一个19…

2026/9/10 12:32:02

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/10 15:49:53

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码