【微服務架構 】微服務簡介,第3部分:服務註冊表

  • 2019 年 10 月 4 日
  • 筆記

在微服務系列的這篇文章中,我們將討論服務註冊表。在第2部分中,我們討論了API網關,其中我們提到服務已在資料庫中註冊。網關根據該資料庫中包含的資訊調度請求。下面我們將探討如何填充資料庫以及服務,客戶端和網關與之交互的方式。

服務註冊表

服務註冊表是一個資料庫,其中包含有關如何將請求分派給微服務實例的資訊。註冊表和其他組件之間的交互可以分為兩組,每組有兩個子組:

微服務和註冊表之間的交互(註冊)

  • 自註冊
  • 第三方註冊

客戶端與註冊表之間的交互(發現)

  • 客戶端發現
  • 伺服器端發現

註冊

大多數基於微服務的架構都在不斷發展。隨著開發團隊分離,改進,棄用和完成工作,服務會上下波動。每當服務端點發生更改時,註冊表都需要了解更改。這就是註冊的全部內容:誰發布或更新有關如何聯繫每項服務的資訊。

自註冊迫使微服務自己與註冊表進行交互。當服務上升時,它會通知註冊表。服務中斷時會發生同樣的事情。無論註冊表需要哪些其他數據,都必須由服務本身提供。如果你一直關注這個系列,你就會知道微服務都是關於處理一個問題,所以自我註冊可能看起來像一個反模式。但是,對於簡單的體系結構,自註冊可能是正確的選擇。

第三方註冊通常在行業中使用。 在這種情況下,有一個管理所有其他服務的進程或服務。 此過程以某種方式輪詢或檢查哪些微服務實例正在運行,並自動更新服務註冊表。 可以以每服務配置文件(或策略)的形式提供附加數據,註冊過程使用該文件來更新資料庫。 在使用Apache ZooKeeper或Netflix Eureka等工具以及其他服務管理器的架構中,第三方註冊很常見。

第三方註冊還提供其他好處。例如,當服務出現故障時會發生什麼?可以將第三方註冊服務配置為為失敗的服務提供安全回退。其他案例可能會實施其他政策。例如,服務註冊表進程可能會收到高負載情況的通知,並通過請求實例化新的微服務進程或VM來自動添加新端點。可以想像,這些可能性對於大型架構至關重要。

發現

可以想像,從客戶的角度來看,發現是註冊的對應物。當客戶想要訪問服務時,它必須找出服務所在的位置(以及執行請求的其他相關資訊)。

客戶端發現強制客戶端在執行實際請求之前查詢發現服務。正如自我註冊所發生的那樣,這要求客戶處理除主要目標之外的其他問題。發現服務可能位於API網關後面,也可能不位於API網關後面。如果它不在網關後面,則可能需要為發現服務重新實現平衡,身份驗證和其他橫切關注點。此外,每個客戶端都需要知道要聯繫發現服務的固定端點(或端點)。這些都是缺點。一個很大的優點是不必在網關係統中編寫必要的邏輯。選擇發現方法時,請仔細研究。

伺服器端發現使API網關處理髮現請求的正確端點(或端點)。 這通常用於更大的架構。 由於所有請求都直接發送到網關,所以與之相關的所有好處都適用(參見第2部分)。 網關還可以實現發現快取,以便許多請求可以具有較低的延遲。 高速快取失效背後的邏輯特定於實現。

「伺服器端發現使API網關能夠處理髮現請求的正確端點。」

伺服器端發現

示例:註冊表服務

在第2部分中,我們研究了一個簡單的API網關實現。在該示例中,我們通過查詢到服務資料庫來實現動態調度請求。換句話說,我們實現了伺服器端發現。對於此示例,我們將通過處理註冊方面來擴展我們的微服務架構。我們將以兩種方式這樣做:

  1. 通過提供一個簡單的註冊庫,任何開發團隊都可以將其集成到他們的微服務中以執行自我註冊。
  2. 通過提供在啟動或關閉期間註冊服務的示例systemd單元(使用systemd作為服務管理器的第三方註冊)。

為什麼要系統?它已成為大多數Linux安裝中的事實上的服務管理器。管理服務還有其他選擇,但都需要安裝和配置。為簡單起見,我們選擇了大多數發行版中預裝的那個,這是systemd。

註冊庫

我們之前發布的微服務示例是為node.js開發的,所以我們的庫也適用於它。這是我們庫的主要邏輯:

module.exports.register = function(service, callback) {  if(!validateService(service)) {  callback(new Error("Invalid service"));  }  findExisting(service.name, function(err, found) { if(found) {  callback(new Error("Existing service")); return;  } var dbService = new Service({ name: service.name, url: service.url, endpoints: service.endpoints, authorizedRoles: service.authorizedRoles  });  dbService.save(function(err) {  callback(err);  });  });  }module.exports.unregister = function(name, callback) {  findExisting(name, function(err, found) { if(!found) {  callback(new Error("Service not found")); return;  }  found.remove(function(err) {  callback(err);  });  });  }

執行自註冊的微服務需要在啟動或關閉期間調用這些功能(包括異常關閉)。 我們已通過以下方式將此庫集成到現有的微服務示例中(將SELF_REGISTRY變數設置為任何值以啟用此功能)。 啟動程式碼:

// Standalone server setup  var port = process.env.PORT || 3001;  http.createServer(app).listen(port, function (err) { if (err) {  logger.error(err);  } else {  logger.info('Listening on http://localhost:' + port); if(process.env.SELF_REGISTRY) {  registry.register({  name: serviceName,  url: '/tickets',  endpoints: [ {  type: 'http',  url: 'http://127.0.0.1:' + port + '/tickets'  } ],  authorizedRoles: ['tickets-query']  }, function(err) { if(err) {  logger.error(err);  process.exit();  }  });  }  }  });

和關機程式碼:

function exitHandler() { if(process.env.SELF_REGISTRY) {  registry.unregister(serviceName, function(err) { if(err) {  logger.error(err);  }  process.exit();  });  } else {  process.exit();  }  }  process.on('exit', exitHandler);  process.on('SIGINT', exitHandler);  process.on('SIGTERM', exitHandler);  process.on('uncaughtException', exitHandler);

使用systemd進行第三方註冊

我們的網關示例從Mongo資料庫中讀取服務資訊。 Mongo提供了一個命令行介面,我們可以在啟動或關閉期間使用它來註冊服務。 這是一個示例systemd單元(如果您使用此帖子中的示例微服務,請記住禁用SELF_REGISTRY環境變數):

[Unit]  Description=Sample tickets query microservice#Uncomment the following line when not running systemd in user mode#After=network.target[Service]#Uncomment the following line to run the service as a specific user#User=sebaEnvironment="MONGO_URL=mongodb://127.0.0.1:27018/test"ExecStart=/usr/bin/node /home/seba/Projects/Ingadv/Auth0/blog-code/microservices/server.js  ExecStartPost=/usr/bin/mongo --eval 'db.services.insert({"name": "Tickets Query Service", "url": "/tickets", "endpoints": [{"type": "http", "url": "http://127.0.0.1:3001/tickets"}], "authorizedRoles": ["tickets-query"] });' 127.0.0.1:27017/test  ExecStopPost=/usr/bin/mongo --eval 'db.services.remove({"name": "Tickets Query Service"});' 127.0.0.1:27017/test  [Install]  WantedBy=default.target

註冊由ExecStartPost和ExecStopPost指令通過調用命令行Mongo客戶端(包含在所有標準MongoDB安裝中)來處理。

獲取程式碼https://github.com/auth0/blog-microservices-part3。

另外:使用Auth0作為您的微服務

由於JWT的神奇之處,Auth0和微服務齊頭並進。 看看這個:

var express = require('express');var app = express();var jwt = require('express-jwt');var jwtCheck = jwt({  secret: new Buffer('your-auth0-client-secret', 'base64'),  audience: 'your-auth0-client-id'});  app.use('/api/path-you-want-to-protect', jwtCheck);// (...)

您可以通過Auth0儀錶板獲取客戶端ID和客戶端密鑰。 創建一個新帳戶並開始黑客攻擊!

結論

服務註冊表是基於微服務的體系結構的重要組成部分。 有不同的處理註冊和發現的方法,適合不同的架構複雜性。 在承諾之前考慮上述每種替代方案的優缺點。 在第4部分中,我們將詳細研究服務依賴性以及如何有效地管理它們。

Tags: