\n \n
正如我们在上一篇博客文章所述,Pingora 是一个 Rust 异步多线程框架,用于帮助我们构建 HTTP 代理服务。自我们上一篇博客文章以来,Pingora 已经在我们的全球网络中处理了近千万亿次互联网请求。
我们将 Pingora 开源,旨在帮助在我们自己的基础设施之外构建更好、更安全的互联网。我们希望为我们的客户、用户和其他人提供工具、想法和灵感,使用一个内存安全框架来构建自己的互联网基础设施。鉴于整个行业和美国政府日益意识到内存安全的重要性,拥有这样一个框架尤其重要。在这个共同目标下,我们与互联网安全研究组织 ISRG 的 Prossimo 项目合作,帮助推动 Pingora 在互联网最关键的基础设施中得到采用。
在上一篇博客文章中,我们讨论了构建 Pingora 的原因和方式。本期我们将讨论为什么以及如何使用 Pingora。
Pingora 不仅为代理、还为客户端和服务器提供构建块。除了这些组件,我们还提供一些实用库用于实现事件计数、错误处理和缓存等常见逻辑。
\nPingora 提供在 HTTP/1 和 HTTP/2、 TLS 或仅 TCP / UDP 之上构建服务的库和 API。作为代理,它支持 HTTP/1 和 HTTP/2 端到端、gRPC 和 websocket 代理。(HTTP/3 支持在路线图上)。它还提供可自定义的负载平衡和故障转移策略。在合规性和安全性方面,它同时支持常用的 OpenSSL 和 BoringSSL 库,两者均符合 FIPS 要求并支持后量子加密。
除了提供以上功能,Pingora 还提供过滤器和回调函数,让用户完全自定义服务应该如何处理、转换和转发请求。这些 API 对于 OpenResty 和 NGINX 用户来说应该很熟悉,因为许多 API 直观地映射到 OpenResty 的 “*_by_lua” 回调函数上。
在运行方面,Pingora 提供零停机优雅重启,以便在不丢失任何传入请求的情况下进行自身升级。Syslog、Prometheus、Sentry、OpenTelemetry 和其他必备的可观察性工具也可以轻松与 Pingora 集成。
\n对于如下情况,您应该考虑 Pingora:
**安全是您的首要考虑因素:**对于用 C/C++ 编写的服务而言,Pingora 是一种内存安全性更高的替代方案。虽然有些人可能会争论编程语言之间的内存安全问题,但根据我们的实践经验,我们发现自己犯下导致内存安全问题的编码错误的可能性要小得多。此外由于我们花在解决这些问题上的时间更少,我们在实施新功能时更有成效。
**您的服务对性能敏感:**Pingora 快速高效。正如我们在上一篇博客文章中所述,由于 Pingora 的多线程架构,我们节省了大量 CPU 和内存资源。就对系统成本和/或速度敏感的工作负载而言,时间和资源的节省可能非常引人注目。
**您的服务需要广泛的定制:**Pingora 代理框架提供的 API 是高度可编程的。对于希望构建自定义高级网关或负载平衡器的用户,Pingora 提供了强大但简单的实施方法。我们将在下一节中提供示例。
\n让我们通过构建一个简单的负载均衡器来探索 Pingora 的可编程 API。该负载均衡器将以轮询的方式在 https://1.1.1.1/ 和 https://1.0.0.1/ 之间选择上游。
首先让我们创建一个空白的 HTTP 代理。
任何实现 ProxyHttp
特征(类似于 C++ 或 Java 中接口的概念)的对象都是 HTTP 代理。那里唯一需要的方法是 upstream_peer()
,对于每个请求都会调用这个方法。这个函数应该返回一个 HttpPeer
,包含要连接的源 IP 以及连接方式。
pub struct LB();\n\n#[async_trait]\nimpl ProxyHttp for LB {\n async fn upstream_peer(...) -> Result<Box<HttpPeer>> {\n todo!()\n }\n}
\n 接下来让我们实现轮询选择。Pingora 框架已经提供了 LoadBalancer
,其中包含常见的选择算法,例如轮询和哈希,所以让我们直接使用它。如果用例需要更复杂或定制化的服务器选择逻辑,用户可以在这个函数中自行实现。
由于我们要连接到 HTTPS 服务器,还需要设置 SNI。如果需要,证书、超时和其他连接选项也可以在 HttpPeer 对象中设置。
\npub struct LB(Arc<LoadBalancer<RoundRobin>>);\n\n#[async_trait]\nimpl ProxyHttp for LB {\n async fn upstream_peer(...) -> Result<Box<HttpPeer>> {\n let upstream = self.0\n .select(b"", 256) // hash doesn't matter for round robin\n .unwrap();\n\n // Set SNI to one.one.one.one\n let peer = Box::new(HttpPeer::new(upstream, true, "one.one.one.one".to_string()));\n Ok(peer)\n }\n}
\n 最后,让我们将服务投入运行。在这个示例中,我们硬编码了源服务器的 IP 地址。在实际工作负载中,当调用 upstream_peer()
时或在后台中,也可以动态发现源服务器的 IP 地址。创建服务后,我们只需告诉 LB 服务监听 127.0.0.1:6188。最后,我们创建了一个 Pingora 服务器,该服务器将是运行负载平衡服务的进程。
让我们尝试一下:
\nfn main() {\n let mut upstreams = LoadBalancer::try_from_iter(["1.1.1.1:443", "1.0.0.1:443"]).unwrap();\n\n let mut lb = pingora_proxy::http_proxy_service(&my_server.configuration, LB(upstreams));\n lb.add_tcp("127.0.0.1:6188");\n\n let mut my_server = Server::new(None).unwrap();\n my_server.add_service(lb);\n my_server.run_forever();\n}
\n 我们可以看到代理正在工作,但源服务器以 403 拒绝我们。这是因为我们的服务只是简单地代理了 curl 设置的 Host 头部 127.0.0.1:6188,这让源服务器感到不悦。我们如何使代理修正这个问题?这可以简单地通过添加另一个名为 upstream_request_filter
的过滤器来完成。在连接到源服务器之后,发送任何 HTTP 请求之前,过滤器在每个请求上运行。我们可以在这个过滤器中添加、删除或更改 HTTP 请求头。
curl 127.0.0.1:6188 -svo /dev/null\n> GET / HTTP/1.1\n> Host: 127.0.0.1:6188\n> User-Agent: curl/7.88.1\n> Accept: */*\n> \n< HTTP/1.1 403 Forbidden
\n 我们再试一次:
\nasync fn upstream_request_filter(…, upstream_request: &mut RequestHeader, …) -> Result<()> {\n upstream_request.insert_header("Host", "one.one.one.one")\n}
\n 这次成功了!完整示例请参见此处。
\ncurl 127.0.0.1:6188 -svo /dev/null\n< HTTP/1.1 200 OK
\n 下面是一个非常简单的图示,展示在本示例中请求如何通过回调和过滤器流动。Pingora 代理框架目前提供了更多的过滤器和回调,可以在请求的不同阶段允许用户修改、拒绝、路由和/或记录请求(和响应)。
在幕后,Pingora 代理框架负责连接池、TLS 握手、读取、写入、解析请求和其他常见代理任务,以便用户可以专注于对他们重要的逻辑。
\nPingora 是一个库和工具集,而不是可执行二进制文件。换句话说,Pingora 是驱动汽车的引擎,而不是汽车本身。虽然 Pingora 已经生产就绪,可供业界使用,但我们理解很多人希望有一种一揽子、即插即用的 Web 服务,具备低代码或无代码配置选项。我们与 ISRG 合作的重点将是在 Pingora 之上构建这样的应用,以扩大 Pingora 的影响力。请继续关注该项目的后续公告。
其他需要牢记的注意事项:
**目前,API 的稳定性不能保证。**尽管我们会尽量减少进行破坏性更改的频率,但在库的演变过程中,特别是在 1.0 版本前,我们仍保留添加、删除或更改请求和响应过滤器等组件的权利。
**对非 Unix 操作系统的支持目前不在路线图中。**尽管我们目前没有支持这些系统的计划,但未来情况可能会发生变化。
欢迎在我们的 GitHub 问题跟踪器中提出错误报告、文档问题或功能请求。在提交拉取请求之前,我们强烈建议您先阅读我们的贡献指南 。
\n本篇博客文章中,我们宣布了 Pingora 框架的开源。我们展示了互联网实体和基础设施可受益于 Pingora 的安全性、性能和可定制性。我们还展示了 Pingora 的易用性和可定制性。
无论您是在构建生产 Web 服务,还是试验网络技术,我们都希望您能在 Pingora 中找到价值。这是一段漫长的旅程,但与开源社区分享这个项目从一开始就是一个目标。我们希望感谢 Rust 社区,因为 Pingora 是使用许多优秀的开源 Rust 包构建的。迁移到内存安全的互联网似乎是一个不可能的旅程,但我们希望您加入我们的行列。
"],"published_at":[0,"2024-02-28T15:00:11.000+00:00"],"updated_at":[0,"2024-10-10T00:22:15.287Z"],"feature_image":[0,"https://cf-assets.www.cloudflare.com/zkvhlag99gkb/f24aeLVQUjlbXRxDzdWm9/dc66227c33b56143feba15c9f3da26c9/pingora-open-source.png"],"tags":[1,[[0,{"id":[0,"3JAY3z7p7An94s6ScuSQPf"],"name":[0,"开发人员平台"],"slug":[0,"developer-platform"]}],[0,{"id":[0,"4HIPcb68qM0e26fIxyfzwQ"],"name":[0,"开发人员"],"slug":[0,"developers"]}],[0,{"id":[0,"w4e8pkoz9c8xNDVhy9eNe"],"name":[0,"Rust"],"slug":[0,"rust"]}],[0,{"id":[0,"3txfsA7N73yBL9g3VPBLL0"],"name":[0,"Open Source"],"slug":[0,"open-source"]}],[0,{"id":[0,"4gN0ARax0fHxjtZL07THOe"],"name":[0,"性能"],"slug":[0,"performance"]}]]],"relatedTags":[0],"authors":[1,[[0,{"name":[0,"Yuchen Wu"],"slug":[0,"yuchen"],"bio":[0,null],"profile_image":[0,"https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5Ku4RmxaCrMYgBRauBkpSY/6053cf7e36a88fa5f0ca956780a12863/yuchen.jpg"],"location":[0,null],"website":[0,null],"twitter":[0,null],"facebook":[0,null]}],[0,{"name":[0,"Edward Wang"],"slug":[0,"edward-h-wang"],"bio":[0,null],"profile_image":[0,"https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3SR2WJJhMUA6NjeEtB1Z2A/7bf4f81bf09f441fbccc5cfb19c39710/edward-h-wang.jpg"],"location":[0,null],"website":[0,null],"twitter":[0,null],"facebook":[0,null]}],[0,{"name":[0,"Andrew Hauck"],"slug":[0,"andrew-hauck"],"bio":[0,null],"profile_image":[0,"https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1crH945j3ZNGgaRazYIlca/4df0c031df672eed876bbe3e167b4597/andrew-hauck.jpg"],"location":[0,null],"website":[0,null],"twitter":[0,null],"facebook":[0,null]}]]],"meta_description":[0,null],"primary_author":[0,{}],"localeList":[0,{"name":[0,"Open sourcing Pingora: our Rust framework for building programmable network services Config"],"enUS":[0,"English for Locale"],"zhCN":[0,"Translated for Locale"],"zhHansCN":[0,"No Page for Locale"],"zhTW":[0,"Translated for Locale"],"frFR":[0,"Translated for Locale"],"deDE":[0,"Translated for Locale"],"itIT":[0,"No Page for Locale"],"jaJP":[0,"Translated for Locale"],"koKR":[0,"Translated for Locale"],"ptBR":[0,"Translated for Locale"],"esLA":[0,"No Page for Locale"],"esES":[0,"Translated for Locale"],"enAU":[0,"No Page for Locale"],"enCA":[0,"No Page for Locale"],"enIN":[0,"No Page for Locale"],"enGB":[0,"No Page for Locale"],"idID":[0,"No Page for Locale"],"ruRU":[0,"No Page for Locale"],"svSE":[0,"No Page for Locale"],"viVN":[0,"No Page for Locale"],"plPL":[0,"No Page for Locale"],"arAR":[0,"No Page for Locale"],"nlNL":[0,"No Page for Locale"],"thTH":[0,"No Page for Locale"],"trTR":[0,"No Page for Locale"],"heIL":[0,"No Page for Locale"],"lvLV":[0,"No Page for Locale"],"etEE":[0,"No Page for Locale"],"ltLT":[0,"No Page for Locale"]}],"url":[0,"https://blog.cloudflare.com/pingora-open-source"],"metadata":[0,{"title":[0,"开源 Pingora ——我们用于构建可编程网络服务的 Rust 框架"],"description":[0,null],"imgPreview":[0,"https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7gb9sRwlJjetA6l01T4XgO/0f49172d6d83749d6c45e729d05d95e3/pingora-open-source-H9vTzf.png"]}]}],"locale":[0,"zh-cn"],"translations":[0,{"posts.by":[0,"作者"],"footer.gdpr":[0,"GDPR"],"lang_blurb1":[0,"这篇博文也有 {lang1} 版本。"],"lang_blurb2":[0,"这篇博文也有 {lang1} 和{lang2}版本。"],"lang_blurb3":[0,"这篇博文也有 {lang1}、{lang2} 和{lang3}版本。"],"footer.press":[0,"新闻"],"header.title":[0,"Cloudflare 博客"],"search.clear":[0,"清除"],"search.filter":[0,"过滤"],"search.source":[0,"来源"],"footer.careers":[0,"招聘"],"footer.company":[0,"公司"],"footer.support":[0,"支持"],"footer.the_net":[0,"theNet"],"search.filters":[0,"过滤器"],"footer.our_team":[0,"我们的团队"],"footer.webinars":[0,"网络研讨会"],"page.more_posts":[0,"更多帖子"],"posts.time_read":[0,"{time} 分钟阅读时间"],"search.language":[0,"语言"],"footer.community":[0,"社区"],"footer.resources":[0,"资源"],"footer.solutions":[0,"解决方案"],"footer.trademark":[0,"商标"],"header.subscribe":[0,"订阅"],"footer.compliance":[0,"合规性"],"footer.free_plans":[0,"Free 计划"],"footer.impact_ESG":[0,"影响/ESG"],"posts.follow_on_X":[0,"在 X 上关注"],"footer.help_center":[0,"帮助中心"],"footer.network_map":[0,"网络地图"],"header.please_wait":[0,"请稍候"],"page.related_posts":[0,"相关帖子"],"search.result_stat":[0,"针对 {search_keyword} 的第 {search_range} 个搜索结果(共 {search_total} 个结果)"],"footer.case_studies":[0,"案例研究"],"footer.connect_2024":[0,"Connect 2024"],"footer.terms_of_use":[0,"服务条款"],"footer.white_papers":[0,"白皮书"],"footer.cloudflare_tv":[0,"Cloudflare TV"],"footer.community_hub":[0,"社区中心"],"footer.compare_plans":[0,"比较各项计划"],"footer.contact_sales":[0,"联系销售"],"header.contact_sales":[0,"联系销售团队"],"header.email_address":[0,"电子邮件地址"],"page.error.not_found":[0,"未找到页面"],"footer.developer_docs":[0,"开发人员文档"],"footer.privacy_policy":[0,"隐私政策"],"footer.request_a_demo":[0,"请求演示"],"page.continue_reading":[0,"继续阅读"],"footer.analysts_report":[0,"分析报告"],"footer.for_enterprises":[0,"企业级服务"],"footer.getting_started":[0,"开始使用"],"footer.learning_center":[0,"学习中心"],"footer.project_galileo":[0,"Project Galileo"],"pagination.newer_posts":[0,"较新的帖子"],"pagination.older_posts":[0,"较旧的帖子"],"posts.social_buttons.x":[0,"在 X 上讨论"],"search.icon_aria_label":[0,"搜索"],"search.source_location":[0,"来源/位置"],"footer.about_cloudflare":[0,"关于 Cloudflare"],"footer.athenian_project":[0,"Athenian Project"],"footer.become_a_partner":[0,"成为合作伙伴"],"footer.cloudflare_radar":[0,"Cloudflare Radar"],"footer.network_services":[0,"网络服务"],"footer.trust_and_safety":[0,"信任与安全"],"header.get_started_free":[0,"免费开始使用"],"page.search.placeholder":[0,"搜索 Cloudflare"],"footer.cloudflare_status":[0,"Cloudflare 状态"],"footer.cookie_preference":[0,"Cookie 首选项"],"header.valid_email_error":[0,"必须是有效的电子邮件地址。"],"search.result_stat_empty":[0,"显示第 {search_range} 个结果(共 {search_total} 个结果)"],"footer.connectivity_cloud":[0,"全球连通云"],"footer.developer_services":[0,"开发人员服务"],"footer.investor_relations":[0,"投资者关系"],"page.not_found.error_code":[0,"错误代码:404"],"search.autocomplete_title":[0,"请输入查询内容。按回车键发送"],"footer.logos_and_press_kit":[0,"标识与媒体资料包"],"footer.application_services":[0,"应用程序服务"],"footer.get_a_recommendation":[0,"获得推荐"],"posts.social_buttons.reddit":[0,"在 Reddit 上讨论"],"footer.sse_and_sase_services":[0,"SSE 和 SASE 服务"],"page.not_found.outdated_link":[0,"您可能使用了过期的链接,或者输入了错误的地址。"],"footer.report_security_issues":[0,"报告安全问题"],"page.error.error_message_page":[0,"抱歉,我们找不到您要打开的页面。"],"header.subscribe_notifications":[0,"订阅以接收新文章的通知:"],"footer.cloudflare_for_campaigns":[0,"Cloudflare for Campaigns"],"header.subscription_confimation":[0,"订阅已确认。感谢订阅!"],"posts.social_buttons.hackernews":[0,"在 Hacker News 上讨论"],"footer.diversity_equity_inclusion":[0,"多元、公平与包容"],"footer.critical_infrastructure_defense_project":[0,"关键基础设施防护项目"]}]}" ssr="" client="load" opts="{"name":"PostCard","value":true}" await-children="">