惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

SecWiki News
SecWiki News
I
InfoQ
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
博客园 - Franky
T
Tailwind CSS Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
博客园_首页
罗磊的独立博客
V
V2EX
李成银的技术随笔
大猫的无限游戏
大猫的无限游戏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
True Tiger Recordings
Vercel News
Vercel News
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
F
Fox-IT International blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
M
Microsoft Research Blog - Microsoft Research
Know Your Adversary
Know Your Adversary
爱范儿
爱范儿
The Register - Security
The Register - Security
G
Google Developers Blog
The Hacker News
The Hacker News
Malwarebytes
Malwarebytes
S
Securelist
博客园 - 三生石上(FineUI控件)
Jina AI
Jina AI
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
S
SegmentFault 最新的问题
博客园 - 叶小钗
F
Fortinet All Blogs
Apple Machine Learning Research
Apple Machine Learning Research
宝玉的分享
宝玉的分享
博客园 - 聂微东
T
Threatpost
博客园 - 【当耐特】
D
Docker
P
Privacy & Cybersecurity Law Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
G
GRAHAM CLULEY
V
Visual Studio Blog
C
Cisco Blogs
IT之家
IT之家
S
Security Archives - TechRepublic
Latest news
Latest news
阮一峰的网络日志
阮一峰的网络日志

元视角

Terraform 极简入门:从 AWS-CLI 到基础设施即代码(IaC) - 元视角 .NET 生态下的 Agent 框架选型:从 ReAct 到原生推理 - 元视角 从「能用」到「好用」:LLM 流式响应实现方式的探索之路 - 元视角 当我用 2000 条聊天记录,让 AI 为我画一幅自画像 - 元视角 基于 Supabase 的 AI 应用开发探索 - 元视角 盛世幻象:从荔枝看盛唐的兴衰 - 元视角 观影 - 元视角 听歌 - 元视角 个人作品 - 元视角 站点统计 - 元视角 读书 - 元视角 微博 × MCP:社交媒体新玩法解锁 - 元视角 四点钟海棠花未眠 - 元视角 留言 - 元视角 Semantic Kernel × MCP:智能体的上下文增强探索 - 元视角 命运、偏见与自由:《魔童之哪吒闹海》的终极抗争 - 元视角 基于 K-Means 聚类分析实现人脸照片的快速分类 - 元视角 容器技术驱动下的代码沙箱实践与思考 - 元视角 温故而知新:后端通用查询方案的再思考 - 元视角 浅议 CancellationToken 在前后端协同取消场景中的应用 - 元视角 Semantic Kernel 视角下的 Text2SQL 实践与思考 - 元视角 走走停停,允许一切发生 - 元视角 关于 ChatGPT 的流式传输,你需要知道的一切 - 元视角 从抖音看见世界的参差 - 元视角 俯仰之间:五一小长假出行记 - 元视角 RAG 的是与非、Rewrite 和 Rerank - 元视角 《你想活出怎样的人生》与宫崎骏的自我和解 - 元视角 使用 EFCore 和 PostgreSQL 实现向量存储及检索 - 元视角 基于 LLaMA 和 LangChain 实践本地 AI 知识库 - 元视角 使用 llama.cpp 在本地部署 AI 大模型的一次尝试 - 元视角 如何为 Git 配置多个 SSH Key - 元视角 C# 使用 LibUsbDotNet 实现 USB 设备检测 - 元视角 基于 C# 实现样式与数据分离的打印方案 - 元视角 基于 SVG 的图形交互方案实践 - 元视角 前端视频播放技术概览 - 元视角 你好,千寻小姐 - 元视角 温故而知新,再话 Python 动态导入 - 元视角 后 GPT 时代,NLP 不存在了? - 元视角 视频是不能 P 的系列:使用 Milvus 实现海量人脸快速检索 - 元视角 GDI+下字体大小自适应方案初探 - 元视角 小爱音箱集成 ChatGPT 的不完全教程 - 元视角 程序员视角下的三体世界随想 - 元视角 关于 Docker 容器配置信息的渐进式思考 - 元视角 在 Docker 容器内集成 Crontab 定时任务 - 元视角 为你的服务器集成 LDAP 认证 - 元视角 似花还似非花 - 元视角 视频是不能 P 的系列:使用 Dlib 实现人脸识别 - 元视角 浅议分布式链路追踪与日志的整合 - 元视角 关于 Git 大文件上传这件小事 - 元视角 .NET 进程内队列 Channel 的入门与应用 - 元视角 使用 Fody 实现 .NET 的静态编织 - 元视角 .NET Core + ELK 搭建可视化日志分析平台(下) - 元视角 聊一聊前端图片懒加载背后的故事 - 元视角 杂感·七月寄望 - 元视角 支持外部链接跳转的 Vue Router 扩展实现 - 元视角 视频是不能 P 的系列:OpenCV 和 Dlib 实现表情包 - 元视角 不得不说的 ASP.NET Core 集成测试 - 元视角 再议 DDD 视角下的 EFCore 与 领域事件 - 元视角 Vue.js 前端项目容器化部署实践极简教程 - 元视角 再见,人间四月天 - 元视角 Python 图像风格化迁移助力画家梦想 - 元视角 在 Vue.js 中使用 Mock.js 实现接口模拟 - 元视角 利用 ASP.NET Core 中的标头传播实现分布式链路追踪 - 元视角 读《一个叫欧维的男人决定去死》 - 元视角 利用 gRPC 实现文件的上传与下载 - 元视角 七种武器:延迟队列的原理和实现总结 - 元视角 gRPC 流式传输极简入门指南 - 元视角 烟波梦影,从天国王朝到刺客信条 - 元视角 关于 - 元视角 Envoy 集成 Jaeger 实现分布式链路追踪 - 元视角 浅议非典型 Web 应用场景下的身份认证 - 元视角 gRPC 借助 Any 类型实现接口的泛化调用 - 元视角 分布式丛林探险系列之 Redis 集群模式 - 元视角 写在冬阳升起以前 - 元视角 分布式丛林探险系列之 Redis 主从复制模式 - 元视角 通过 Python 预测 2021 年双十一交易额 - 元视角 从《失控玩家》中得到的启示 - 元视角 gRPC 搭配 Swagger 实现微服务文档化 - 元视角 SSL/TLS 加密传输与数字证书的前世今生 - 元视角 夕雾花园:从建筑中读出的爱情和美学 - 元视角 使用 Python 自动识别防疫健康码 - 元视角 你不可不知的容器编排进阶技巧 - 元视角 ASP.NET Core 搭载 Envoy 实现 gRPC 服务代理 - 元视角 再话 AOP,从简化缓存操作说起 - 元视角 洗衣随想曲 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务身份认证(JWT) - 元视角 浪客剑心:一曲幕末时代的挽歌 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的监控预警 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的反向代理 - 元视角 ASP.NET Core gRPC 打通前端世界的尝试 - 元视角 EFCore 实体命名约定库:EFCore.NamingConventions - 元视角 ASP.NET Core gRPC 集成 Polly 实现优雅重试 - 元视角 ASP.NET Core gRPC 健康检查的探索与实现 - 元视角 ASP.NET Core gRPC 拦截器的使用技巧分享 - 元视角 SnowNLP 使用自定义语料进行模型训练 - 元视角 假如时间有温度 - 元视角 使用 HttpMessageHandler 实现 HttpClient 请求管道自定义 - 元视角 ABP vNext 的实体与服务扩展技巧分享 - 元视角 ABP vNext 对接 Ant Design Vue 实现分页查询 - 元视角 浅议 EF Core 分库分表及多租户架构的实现 - 元视角
ASP.NET Core 搭载 Envoy 实现微服务的负载均衡 - 元视角
2021-07-05 · via 元视角

如果说,我们一定要找出一个词来形容这纷繁复杂的世界,我希望它会是熵。有人说,熵增定律是宇宙中最绝望的定律,所谓熵,即是指事物混乱或者无序的程度。在一个孤立系统下,熵是不断在增加的,当熵达到最大值时,系统就会出现严重混乱,直至最终走向死亡。从某种意义上来讲,它揭示了事物结构衰退的必然性,甚至于我们的人生,本来就是一场对抗熵增的旅程。熵增的不可逆性,正如时光无法倒流一般,古人说,“覆水难收”正是这个道理。同样地,当我们开始讨论微服务的划分/编写/治理的时候,当我们使用服务网格来定义微服务架构的时候……我们是否有意或者无意的增加了系统中的熵呢?**一个孤立的系统尚且会因为熵增而最终走向死亡,更何况是相互影响和制约的复杂系统呢?**现代互联网企业都在追求4个9(即99.99%)的高可用,这意味着年平均停机时长只有52.56分钟。在此之前。我们介绍过重试和熔断这两种故障转移的策略,而今天我们来介绍一种更朴素的策略:负载均衡。

什么是负载均衡

负载均衡,即Load Banlancing,是一种计算机技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其它资源中分配负载,以达到最优化资源使用、最大化吞吐率、最小化响应时间、避免过载的目的

我们可以注意到,在这个定义中,使用负载均衡技术的直接原因是避免过载,而根本原因则是为了优化资源使用,确保最大吞吐量最小响应时间。所以,这本质上是一个局部最优解的问题,而具体的手段就是"多个"。有人说,技术世界不过是真实世界的一个镜像,联系生活中实际的案例,我们发现负载均衡比比皆是。譬如车站在面对春运高峰时增加售票窗口,银行通过多个业务窗口来为客户办理业务……等等。这样做的好处显而易见,可以大幅度地减少排队时间,增加"窗口"这个行为,在技术领域我们将其称为:水平扩展,因为有多个"窗口",发生单点故障的概率就会大大降低,而这正是现在软件追求的三"高":高性能、高可用、高并发。

银行柜员窗口示意图 银行柜员窗口示意图

每次坐地铁经过小寨,时常听到地铁工作人员举着喇叭引导人们往不同的出口方向走动。此时,工作人员就是一个负载均衡器,它要做的就是避免某一个出口人流量过载。**从熵的角度来看,人流量过载,意味着无序/混乱状态加剧,现代社会通过道德和法律来对抗熵增,人类个体通过自律来对抗熵增。**有时候,我会忍不住去想,大人与小孩儿愈发内卷的恶性竞争,除了给这个世界带来更多的熵以外,还能带来什么?如果参考社会达尔文主义的理论,在这个弱肉强食的世界里,增加熵是人为的选择,而同样的,你亦可以选择"躺平"。

负载均衡器示意图 负载均衡器示意图

OK,将思绪拉回到负载均衡,它所做的事情,本质上就是控制信息或者说流量流动的方向。一个网站,以集群的方式对外提供服务,你只需要输入一个域名,它就可以把请求分发到不同的机器上面去,而这就是所谓的负载均衡。目前,负载均衡器从种类上可以分为:基于DNS、基于MAC地址(二层)、基于IP(三层)、基于IPPort(四层)、基于HTTP(七层)。

OSI七层模型与TCP/IP五层模型 OSI七层模型与TCP/IP五层模型

譬如,博主曾经参与过伊利的项目,它们使用的就是一个四层的负载均衡器:F5。而像更常见NginxHAProxy,基本都是四层和七层的负载均衡器,而Envoy就厉害了,它可以同时支持三/四/七层。负载均衡器需要配合负载均衡算法来使用,典型的算法有:轮询法随机法哈希法最小连接数法等等,而这些算法都可以结合加权算法引出新的变式,这里就不再一一列举啦。

Envoy中的负载均衡

通过上一篇博客,我们已经了解到,Envoy中一个HTTP请求的走向,大致会经历:客户端、侦听器(Listeners)、集群(Clusters)、终结点(Endpoints)、服务(ervices)这样几个阶段。其中,一个集群可以有多个终结点(Endpoints)。所以,这里天然地就存在着负载均衡的设计。因为,负载均衡本质上就是告诉集群,它应该选择哪一个终结点(Endpoints)来提供服务。而之所以我们需要负载均衡,一个核心的原因,其实是因为我们选择了分布式。

Envoy架构图:负载均衡器连接集群和服务 Envoy架构图:负载均衡器连接集群和服务

如果类比RabbitMQKafkaRedis,你就会发现,这些产品中或多或少地都会涉及到主(Leader)、从(Follower)以及推举Leader的实现,我个人更愿意将其看作是更广义的负载均衡。最直观的,它可以分担流量,简称分流,不至于让某一台服务器满负荷做运行。其次,它可以作为故障转移的一种方案,人生在世,多一个B计划,就多一种选择。同样地,多一台服务器,就多一分底气。最后,它可以指导某一个产品或者功能的推广,通过给服务器设置不同的权重,在必要的时候,将流量局部地导入某一个环境,腾讯和阿里这样的大厂,经常利用这种方式来做灰度测试

Envoy中支持常用的负载均衡算法,譬如:ROUND_ROBIN(轮询)、LEAST_REQUEST(最少请求)、RING_HASH(哈希环)、RANDOM(随机)、MAGLEV(磁悬浮)、CLUSTER_PROVIDED等等。因为一个集群下可以有多个终结点,所以,在Envoy中配置负载均衡,本质上就是在集群下面增加终结点,而每个终结点则会对应一个服务,特殊的点在于,这些服务可能是通过同一个Dockerfile或者Docker镜像来构建的。所以,一旦理解了这一点,Envoy的负载均衡就再没有什么神秘的地方。例如,下面的代码片段展示了,如何为WeatherService这个集群应用负载均衡:

  clusters:
  # Weather Service
  - name: weatherservice
    connect_timeout: 0.25s
    type: STRICT_DNS
    # ROUND_ROBIN(轮询)
    # LEAST_REQUEST(最少请求)
    # RING_HASH(哈希环)
    # RANDOM(随机)
    # MAGLEV(磁悬浮)
    # CLUSTER_PROVIDED
    lb_policy: LEAST_REQUEST
    load_assignment:
      cluster_name: weatherservice
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: weatherservice1
                port_value: 80
        - endpoint:
            address:
              socket_address:
                address: weatherservice2
                port_value: 80

是不是觉得特别简单?我想说,也许是Envoy更符合人的直观感受一些,理解起来本身没有太大的心智负担。最近看到一个缓存设计,居然还要依赖Kafka,使用者为了使用缓存这个功能,就必须先实现三个丑陋的委托,这就是所谓的心智负担,违背人类的直觉,使用缓存为什么要了解Kafka?到这里,你大概就能了解利用Envoy实现负载均衡的思路,首先是用同一个Dockerfile或者Docker镜像启动多个不同容器(服务),然后将指定集群下面的终结点指定不同的服务,再告诉集群要用哪一种负载均衡策略即可。

邂逅 ASP.NET Core

OK,说了这么多,这里我们还是用ASP.NET Core写一个例子。可以预见到的是,我们需要一个Envoy网关,一个ASP.NET Core的服务。这里,我们还是用Docker-Compose来编排这些服务,下面是对应的docker-compose.yaml文件:

version: '3'
services:
  envoygateway:
    build: Envoy/
    ports:
      - "9090:9090"
      - "9091:9091"
    volumes:
      - ./Envoy/envoy.yaml:/etc/envoy/envoy.yaml
  weatherservice1:
    build: WeatherService/
    ports:
      - "8082:80"
    environment:
      ASPNETCORE_URLS: "http://+"
      ASPNETCORE_ENVIRONMENT: "Development"
  weatherservice2:
    build: WeatherService/
    ports:
      - "8084:80"
    environment:
      ASPNETCORE_URLS: "http://+"
      ASPNETCORE_ENVIRONMENT: "Development"  

而对于Envoy来说,主要的工作是维护集群下的终结点信息这块儿。其实,这段配置在本文的上一节就出现过啦,你有多少个服务实例,就配置多少个终结点,请求落在哪一个实例上,就交给Envoy来决定好啦。故而,这里我们不再做更多的解释:

static_resources:
  listeners:
  - address:
      socket_address:
        address: 0.0.0.0
        port_value: 9090
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          codec_type: AUTO
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/api/w"
                route:
                  auto_host_rewrite: true
                  prefix_rewrite: /Weather
                  cluster: weatherservice
          http_filters:
          - name: envoy.filters.http.router

  clusters:
  # Weather Service
  - name: weatherservice
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: LEAST_REQUEST
    load_assignment:
      cluster_name: weatherservice
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: weatherservice1
                port_value: 80
        - endpoint:
            address:
              socket_address:
                address: weatherservice2
                port_value: 80

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9091 }

使用docker compose up启动容器,我们可以注意到熟悉的ASP.NET Core的身影,这意味着,我们需要的服务都成功地跑起来了。简单调用下API看看,果然,可以正确地返回结果呢(逃……果然,我是一个喜新厌旧的人,自打用了Encoy以后,再不想用Nginx来做类似的事情(逃……

通过管理接口查看集群的请求情况 通过管理接口查看集群的请求情况

好了,如何验证我们选择的负载均衡策略呢?这是一个问题。不知道大家还记不记得Envoy的管理接口,它里面可以统计请求的次数,所以,我们只要看看两个服务各自请求了多少次里有好啦!这里以RANDON这个策略为例:

两个实例拥有不同的请求次数 两个实例拥有不同的请求次数

可以注意到,两个的请求次数果然是随机的呢?而如果我们换成是ROUND_ROBIN,你就会发现这两个数值一前一后相互追赶。选择哪一种负载均衡策略,这个按大家实际的场景去决定就好。我倒觉得,按最少请求数的策略会好一点。虽然计算机永远不知疲倦地接收人们的指令,可考虑能者多劳这种人类世界里的策略,本身充满道德绑架的意味,使用负载均衡,站在计算机的角度来看,这是避免计算机内卷的一种方案。所以啊,老板们,请不要逮着一个老实人就拼了命的剥削,多学学负载均衡算法,卓别林心目中的摩登时代,我一点都不期待,技术世界总告诉我们要严谨、冷静,可充满人情味的世界,同样值得你去热爱啊。

本文小结

本文结合物理学中的熵增定律引出了负载均衡这个话题,而**负载均衡的本质,就是在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其它资源中分配负载,以达到最优化资源使用、最大化吞吐率、最小化响应时间、避免过载的目的。**对于这一点,我们可以结合现实生活中的"窗口"排队来理解。负载均衡可以和水平扩展完美结合,通过降低单点的故障率,来达到提升整个系统可用性的目的。接下来,我们介绍了常见的负载均衡器分类及其算法,Envoy中的负载均衡配置,并结合ASP.NET Core编写了一个实际的案例。好了,以上就是这篇博客的全部内容啦,如果大家对于熵增定律或者负载均衡器有任何的看法,欢迎大家在评论区留言,谢谢大家!