久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Google是怎么設(shè)計(jì)Ruby Serverless Runtime的

共計(jì) 6378 個(gè)字符,預(yù)計(jì)需要花費(fèi) 16 分鐘才能閱讀完成。

這篇文章跟大家分析一下“Google 是怎么設(shè)計(jì) Ruby Serverless Runtime 的”。內(nèi)容詳細(xì)易懂,對(duì)“Google 是怎么設(shè)計(jì) Ruby Serverless Runtime 的”感興趣的朋友可以跟著丸趣 TV 小編的思路慢慢深入來(lái)閱讀一下,希望閱讀后能夠?qū)Υ蠹矣兴鶐椭O旅娓枞?TV 小編一起深入學(xué)習(xí)“Google 是怎么設(shè)計(jì) Ruby Serverless Runtime 的”的知識(shí)吧。

一種實(shí)現(xiàn) Ruby Serverless 化的方式

為 Serverless 產(chǎn)品提供 Ruby 支持比您預(yù)期的要復(fù)雜得多。從最基本的角度來(lái)看,語(yǔ)言運(yùn)行時(shí)只是 Ruby 的安裝,并且可以肯定的是,配置 Ruby 鏡像并將其安裝在 VM 上并不難。但是,當(dāng)您將“Serverless”加入其中時(shí),事情會(huì)變得更加復(fù)雜。Severless 不僅僅是自動(dòng)維護(hù)和擴(kuò)容。這是對(duì)計(jì)算資源的完全不同的思考方式,這與過(guò)去 15 年中我們學(xué)到的有關(guān)部署 Ruby 應(yīng)用程序的許多知識(shí)背道而馳。當(dāng) Google Cloud 的 Ruby 團(tuán)隊(duì)承擔(dān)為 Cloud Functions 設(shè)計(jì) Ruby 運(yùn)行時(shí)的任務(wù)時(shí),我們還承擔(dān)了一項(xiàng)艱巨的任務(wù),即提出一種 Ruby 方式來(lái)實(shí)現(xiàn) Serverless。在堅(jiān)持我們社區(qū)所熟悉的 Ruby 習(xí)慣、實(shí)踐和工具的同時(shí),我們還必須重新思考如何在幾乎每個(gè)層次上進(jìn)行 web 應(yīng)用程序開(kāi)發(fā),從代碼到依賴、持久化、測(cè)試等等。

本文將研究我們?cè)谠O(shè)計(jì)的五個(gè)不同方面的方法:函數(shù)語(yǔ)法、并發(fā)性和生命周期、測(cè)試、依賴項(xiàng)和標(biāo)準(zhǔn)。在每種情況下,我們都將在忠于 Ruby 本色的重要性與擁抱新的 Serverless 范式的愿望之間保持一個(gè)平衡。我們非常努力地保持與傳統(tǒng) Ruby 工作方式的連續(xù)性,并且還從 Google Cloud Functions 其他語(yǔ)言運(yùn)行時(shí)中汲取了經(jīng)驗(yàn),并借鑒了其他云提供商的 Serverless 產(chǎn)品所樹立的先例。但是,在少數(shù)情況下,我們選擇另辟蹊徑。我們之所以這么做,是因?yàn)槲覀冇X(jué)得當(dāng)前的方法要么是濫用了語(yǔ)言功能,要么是誤導(dǎo)和鼓勵(lì)了關(guān)于 Serverless 應(yīng)用開(kāi)發(fā)的錯(cuò)誤想法。

某些決策最終有可能被證明是錯(cuò)誤的。這就是我現(xiàn)在提供這篇文章的原因。討論我們已經(jīng)做的事情,并開(kāi)始討論我們作為 Ruby 社區(qū)實(shí)踐 Serverless 應(yīng)用程序開(kāi)發(fā)的方式。好消息是 Ruby 是一種非常靈活的語(yǔ)言,隨著我們的學(xué)習(xí)和需求的發(fā)展,我們將有很多機(jī)會(huì)適應(yīng)它。

因此,讓我們看一下我們做出的一些初始設(shè)計(jì)決策和權(quán)衡以及做出這些決策的原因。

函數(shù)化 Ruby

“函數(shù)即服務(wù)”(FaaS)當(dāng)前是較流行的 Serverless 范式之一。Google Cloud Functions 只是一種實(shí)現(xiàn)。許多其他主要的云提供商都擁有自己的 FaaS 產(chǎn)品,并且也有開(kāi)源實(shí)現(xiàn)。

當(dāng)然,這種想法是使用一種編程模型,該模型不以 Web 服務(wù)器為中心,而是以函數(shù)為中心:無(wú)狀態(tài)的代碼片段,它們接受輸入?yún)?shù)并返回結(jié)果。這似乎是一個(gè)簡(jiǎn)單的、幾乎顯而易見(jiàn)的術(shù)語(yǔ)變化,但實(shí)際上具有深遠(yuǎn)的意義。

對(duì) Ruby 而言,面臨的第一個(gè)挑戰(zhàn)是,與許多其他編程語(yǔ)言不同,在 Ruby 中函數(shù)并不是一等公民。Ruby 首先是一種面向?qū)ο蟮恼Z(yǔ)言。當(dāng)我們編寫代碼并將其封裝在 def 中時(shí),我們正在編寫一個(gè)方法,這是響應(yīng)發(fā)送給對(duì)象的消息而運(yùn)行的代碼。這是一個(gè)重要的區(qū)別,因?yàn)榻M成方法調(diào)用上下文的對(duì)象和類不是 Serverless 抽象的一部分。因此,它們的存在會(huì)使 Serverless 的應(yīng)用程序復(fù)雜化,甚至在我們編寫應(yīng)用程序時(shí)誤導(dǎo)我們。

例如,某些 FaaS 框架使您可以使用 def 在 Ruby 文件的頂層編寫函數(shù):

def handler(event:, context:)
  Hello, world! 
end

雖然這段代碼看起來(lái)很簡(jiǎn)單,但重要的是要記住它實(shí)際上做了什么。它將這個(gè)“函數(shù)”添加為 Object 類的私有方法,Object 類是 Ruby 類層次結(jié)構(gòu)的基類。換句話說(shuō),Ruby 虛擬機(jī)中的幾乎每個(gè)對(duì)象都添加了“函數(shù)”。(當(dāng)然,除非應(yīng)用程序在加載文件時(shí)更改了主對(duì)象和類上下文,這種技術(shù)會(huì)帶來(lái)其他風(fēng)險(xiǎn)。)在最好的情況下,這打破了封裝和單一職責(zé)。在最壞的情況下,它可能會(huì)干擾應(yīng)用程序的功能、依賴關(guān)系,甚至是 Ruby 標(biāo)準(zhǔn)庫(kù)。這就是為什么這種“頂級(jí)”方法在簡(jiǎn)單的單文件 Ruby 腳本和 Rakefiles 中很常見(jiàn),但在大型 Ruby 應(yīng)用程序中不推薦使用。

Google Ruby 團(tuán)隊(duì)認(rèn)為這個(gè)問(wèn)題很嚴(yán)重,所以我們選擇了一種不同的語(yǔ)法,將函數(shù)寫成塊的形式:

require  functions_framework 
FunctionsFramework.http(handler) do |request|
  Hello, world! 
end

這提供了一種類似于 Ruby 的方式來(lái)定義函數(shù)而無(wú)需修改 Object 基類。它還有一些附帶好處:

名稱(在這種情況下為“handler”)只是一個(gè)字符串參數(shù)。它不必是合法的 Ruby 方法名稱,也不必?fù)?dān)心它與 Ruby 關(guān)鍵字沖突。

塊比方法具有更多的傳統(tǒng)詞法作用域,因此其行為與其他語(yǔ)言中的函數(shù)更相似。

塊語(yǔ)法使管理函數(shù)定義更加容易。例如,可以干凈地“undefine”函數(shù),這對(duì)于測(cè)試很重要。

當(dāng)然,需要權(quán)衡取舍。其中:

語(yǔ)法稍微有些冗長(zhǎng)。

它需要一個(gè)庫(kù)來(lái)提供用于將函數(shù)定義為塊的接口。(這里,Ruby 通過(guò)使用 Functions Framework 庫(kù)跟隨了 Cloud Functions 的其他語(yǔ)言運(yùn)行時(shí)。)

我們認(rèn)為,為了實(shí)現(xiàn)正確區(qū)分函數(shù)的目標(biāo),這些權(quán)衡是值得的。

共享或不共享

并發(fā)性是很難的。這是 Serverless 設(shè)計(jì) (特別是函數(shù)即服務(wù)) 的一個(gè)關(guān)鍵觀察點(diǎn):我們生活在一個(gè)并發(fā)的世界中,我們需要各種方法來(lái)應(yīng)對(duì)。函數(shù)范式通過(guò)堅(jiān)持函數(shù)不共享狀態(tài) (除非通過(guò)外部持久化系統(tǒng),如隊(duì)列或數(shù)據(jù)庫(kù)) 來(lái)解決并發(fā)性問(wèn)題。這實(shí)際上是我們選擇使用塊語(yǔ)法而不是方法語(yǔ)法的另一個(gè)原因。方法隱含對(duì)象,對(duì)象以實(shí)例變量的形式攜帶狀態(tài),這些狀態(tài)在無(wú)狀態(tài) FaaS 環(huán)境中可能無(wú)法正常工作。回避方法是一種微妙但有效的語(yǔ)法方法,可以阻止我們知道的存在問(wèn)題的實(shí)踐。

也就是說(shuō),如果需要共享資源,比如數(shù)據(jù)庫(kù)連接池,該怎么辦? 何時(shí)初始化這些資源,如何訪問(wèn)它們?

為此,Ruby 運(yùn)行時(shí)支持啟動(dòng)函數(shù),這些函數(shù)可以初始化資源并將它們傳遞給函數(shù)調(diào)用方。重要的是,啟動(dòng)函數(shù)可以創(chuàng)建資源,而普通函數(shù)只能讀取它們。

require  functions_framework 

# Use an on_startup block to initialize a shared client and store it in # the global shared data. FunctionsFramework.on_startup do  require  google/cloud/storage  set_global :storage_client, Google::Cloud::Storage.new # The shared storage_client can be accessed by all function invocations # via the global shared data. FunctionsFramework.http  storage_example

注意,我們選擇了定義特殊方法 global 和 set_global 來(lái)與全局資源交互。順便說(shuō)一下,這些不是 Object 上的方法,而是作為函數(shù)上下文使用的特定類上的方法。同樣,我們可以使用更傳統(tǒng)的習(xí)慣用法,如 Ruby 全局變量,甚至構(gòu)造函數(shù)和實(shí)例變量,將信息從啟動(dòng)代碼傳遞給函數(shù)調(diào)用方。然而,這些語(yǔ)法可能傳遞了錯(cuò)誤的東西。我們不是在普通的 Ruby 類和方法中編寫共享數(shù)據(jù)是正常的,而是在 Serverless 的函數(shù)中編寫共享數(shù)據(jù)是危險(xiǎn)的(即使可能的話),我們認(rèn)為語(yǔ)法上強(qiáng)調(diào)區(qū)別是很重要的。這些特殊方法是經(jīng)過(guò)深思熟慮的設(shè)計(jì)決策,以防止在并發(fā)存在時(shí)出現(xiàn)危險(xiǎn)的實(shí)踐。

測(cè)試為首

強(qiáng)大的測(cè)試文化是 Ruby 社區(qū)的核心。流行的框架,如 Rails,承認(rèn)了這一點(diǎn),并通過(guò)提供測(cè)試工具和腳手架作為框架的一部分來(lái)鼓勵(lì)主動(dòng)測(cè)試,Google Cloud Functions 的 Ruby 運(yùn)行時(shí)也遵循了這一點(diǎn),為 Serverless 的函數(shù)提供了測(cè)試工具。

FaaS 范式實(shí)際上非常適合測(cè)試。函數(shù)本質(zhì)上是容易測(cè)試的,只需傳入?yún)?shù)并對(duì)結(jié)果進(jìn)行斷言即可。特別是,您不需要啟動(dòng) web 服務(wù)器來(lái)運(yùn)行測(cè)試,因?yàn)?web 服務(wù)器不是抽象的一部分。Ruby 運(yùn)行時(shí)提供了一個(gè) helper 方 法模塊,用于創(chuàng)建作為輸入使用的 HTTP 請(qǐng)求和云事件對(duì)象,除此之外,大多數(shù)測(cè)試都非常容易編寫。

然而,我們遇到的主要測(cè)試挑戰(zhàn)之一與測(cè)試初始化代碼有關(guān)。確實(shí),這是 Google Ruby 團(tuán)隊(duì)成員在使用其他框架 (包括 Rails) 時(shí)遇到的一個(gè)問(wèn)題:很難測(cè)試應(yīng)用程序的初始化過(guò)程,因?yàn)榭蚣艿某跏蓟ǔ0l(fā)生在測(cè)試之外,在它們運(yùn)行之前。因此,我們?cè)O(shè)計(jì)了一種測(cè)試方法來(lái)隔離函數(shù)的整個(gè)生命周期,包括初始化。這允許我們?cè)跍y(cè)試中運(yùn)行初始化,甚至重復(fù)它多次,允許不同方面的測(cè)試:

require  minitest/autorun 
require  functions_framework/testing 

class MyTest   Minitest::Test  # Include testing helper methods  include FunctionsFramework::Testing
 def test_startup_tasks  # Run the lifecycle, and test the startup tasks in isolation.  load_temporary  app.rb  do  globals = run_startup_tasks  storage_example  assert_kind_of Google::Cloud::Storage, globals[:storage_client]  end  end
 def test_storage_request  # Rerun the entire lifecycle, including the startup tasks, and  # test a function call.  load_temporary  app.rb  do  request = make_get_request  https://example.com/foo  response = call_http  storage_example , request  assert_equal 200, response.status  end  end end

load_temporary 方法在沙箱中加載函數(shù)定義,將它們及其初始化與其他測(cè)試運(yùn)行隔離開(kāi)來(lái)。該方法和其他 helper 方法定義在 FunctionsFramework::Testing 模塊中,可以包含在 minitest 或 rspec 測(cè)試中。

到目前為止,我們只為 Ruby 運(yùn)行時(shí)提供了基本的測(cè)試工具,我希望隨著用戶開(kāi)發(fā)更多的應(yīng)用程序和識(shí)別出更多常見(jiàn)的測(cè)試模式,我們會(huì)在工具集中大量增加這些工具。但我堅(jiān)信測(cè)試工具是任何庫(kù)的重要組成部分,特別是那些聲稱是框架或運(yùn)行時(shí)的庫(kù),所以它是我們?cè)O(shè)計(jì)的核心部分。

可依賴的運(yùn)行時(shí)

大多數(shù)重要的 Ruby 應(yīng)用程序都需要第三方 gems。對(duì)于使用 Google Cloud Functions 的 Ruby 應(yīng)用程序,我們至少需要一個(gè) gem,即 functions_framework,它提供了編寫函數(shù)的 Ruby 接口。您可能還需要其他 gems 來(lái)處理數(shù)據(jù)、進(jìn)行身份驗(yàn)證并與其他服務(wù)集成等等。依賴項(xiàng)管理是任何運(yùn)行時(shí)框架的關(guān)鍵部分。

我們圍繞依賴項(xiàng)管理做出了幾個(gè)設(shè)計(jì)決策。而第一個(gè)也是最重要的就是擁抱 Bundler。

我知道這聽(tīng)起來(lái)有點(diǎn)無(wú)聊。現(xiàn)在大多數(shù) Ruby 應(yīng)用程序都在使用 Bundler,而且很少有替代方案,很少有廣泛使用的。但我們實(shí)際上更進(jìn)一步,將 Bundler 深入到我們的基礎(chǔ)架構(gòu)中,要求應(yīng)用程序使用它來(lái)處理云函數(shù)。我們這么做是因?yàn)椋_切地知道應(yīng)用將如何管理它的依賴關(guān)系將允許我們實(shí)現(xiàn)一些重要的優(yōu)化。

對(duì)于一個(gè)好的 FaaS 系統(tǒng)來(lái)說(shuō),部署和冷啟動(dòng)的速度至關(guān)重要。在 serverless 的世界中,您的代碼可能會(huì)快速連續(xù)地更新、部署和拆除許多次,因此消除瓶頸 (如解析和安裝依賴項(xiàng)) 是至關(guān)重要的。因?yàn)槲覀優(yōu)橐蕾図?xiàng)管理標(biāo)準(zhǔn)化了一個(gè)系統(tǒng),所以我們能夠主動(dòng)地緩存依賴項(xiàng)。我們認(rèn)為,實(shí)現(xiàn)這樣的緩存所帶來(lái)的性能提升,以及 Rubygems.org 基礎(chǔ)架構(gòu)所減少的負(fù)載,遠(yuǎn)遠(yuǎn)超過(guò)了不能使用 Bundler 的替代方案所帶來(lái)的靈活性降低。

Google Cloud Functions 的 Ruby 運(yùn)行時(shí)的另一個(gè)特性,或者可能是怪癖,是如果 gem lockfile 丟失或不一致,部署將失敗。我們需要這個(gè) Gemfile.lock 在部署時(shí)存在。這是執(zhí)行最佳實(shí)踐的另一個(gè)決策。如果在部署期間重新解析了鎖文件,那么您的構(gòu)建可能是不可重復(fù)的,并且您可能沒(méi)有針對(duì)測(cè)試時(shí)使用的相同依賴項(xiàng)運(yùn)行。我們通過(guò)要求一個(gè)最新的 Gemfile.lock 來(lái)避免這個(gè)問(wèn)題。同樣,我們能夠強(qiáng)制執(zhí)行這一點(diǎn),因?yàn)槲覀冃枰褂?Bundler。

新舊標(biāo)準(zhǔn)

最后,好的設(shè)計(jì)依賴于標(biāo)準(zhǔn)和現(xiàn)有技術(shù)。為了在 Ruby 中定義健壯的函數(shù),我們不得不進(jìn)行一些創(chuàng)新,但在表示函數(shù)參數(shù)時(shí),已經(jīng)有現(xiàn)成的庫(kù)或新興標(biāo)準(zhǔn)可供遵循。

例如,在近期內(nèi),許多函數(shù)將響應(yīng) web hook,并需要關(guān)于傳入 HTTP 請(qǐng)求的信息。設(shè)計(jì)一個(gè)表示 HTTP 請(qǐng)求的類并不困難,但是 Ruby 社區(qū)已經(jīng)有了用于這類事情的標(biāo)準(zhǔn) API: Rack。我們采用 Rack 請(qǐng)求類作為事件參數(shù),并支持標(biāo)準(zhǔn)的 Rack 響應(yīng)作為返回值。require“functions_framework”

FunctionsFramework.http  http_example

這不僅提供了一個(gè)熟悉的 API,而且還使它易于與其他基于 Rack 的庫(kù)集成。例如,很容易將 Sinatra 應(yīng)用程序置于云函數(shù)之上,因?yàn)樗鼈兌寄苤С?Rack。

從長(zhǎng)遠(yuǎn)來(lái)看,我們?cè)絹?lái)越希望函數(shù)即服務(wù)(Faas)能夠作為事件系統(tǒng)中的一個(gè)組件。基于事件的架構(gòu)正在迅速普及,經(jīng)常圍繞事件隊(duì)列,如 Apache Kafka。事件體系結(jié)構(gòu)的一個(gè)關(guān)鍵元素是描述事件本身的標(biāo)準(zhǔn)方法,事件發(fā)送方、代理、傳輸和使用者都理解這種標(biāo)準(zhǔn)。

Google Cloud Functions 支持 CNCF CloudEvents,這是一個(gè)描述和交付事件的新興標(biāo)準(zhǔn)。除了 HTTP 請(qǐng)求之外,云函數(shù)還可以接收 CloudEvent 形式的數(shù)據(jù),運(yùn)行時(shí)甚至?xí)谡{(diào)用函數(shù)時(shí)將一些遺留事件類型轉(zhuǎn)換為 CloudEvent。

require  functions_framework 

FunctionsFramework.cloud_event  my_handler  do |event|  # event is a CloudEvent object defined by the cloud_events gem  logger.info  I received a CloudEvent of type #{event.type}! end

為了在 Ruby 中支持 CloudEvent,Google Ruby 團(tuán)隊(duì)與 CNCF Serverless 工作組密切合作,甚至自愿接管了用于 CloudEvent 的 Ruby SDK 的開(kāi)發(fā)。這是一項(xiàng)繁重的工作,但我們認(rèn)為能夠使用官方的、標(biāo)準(zhǔn)的 Ruby 接口至關(guān)重要,即使我們必須自己實(shí)現(xiàn)它。

關(guān)于 Google 是怎么設(shè)計(jì) Ruby Serverless Runtime 的就分享到這里啦,希望上述內(nèi)容能夠讓大家有所提升。如果想要學(xué)習(xí)更多知識(shí),請(qǐng)大家多多留意丸趣 TV 小編的更新。謝謝大家關(guān)注一下丸趣 TV 網(wǎng)站!

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-08-04發(fā)表,共計(jì)6378字。
轉(zhuǎn)載說(shuō)明:除特殊說(shuō)明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請(qǐng)注明出處。
評(píng)論(沒(méi)有評(píng)論)
主站蜘蛛池模板: 古蔺县| 邯郸市| 清丰县| 汉寿县| 葵青区| 绥宁县| 岳池县| 富顺县| 贞丰县| 偃师市| 邢台县| 淳化县| 瑞丽市| 东莞市| 孟连| 隆昌县| 扬中市| 伊吾县| 宁津县| 海晏县| 池州市| 武山县| 灵丘县| 永修县| 新丰县| 林芝县| 佳木斯市| 惠水县| 黄大仙区| 承德县| 齐齐哈尔市| 鲜城| 凤阳县| 黄梅县| 民权县| 永康市| 汾阳市| 碌曲县| 定南县| 五峰| 仙桃市|