Getting started with healthcare data lakes: Using microservices

Các datalake có thể giúp các bệnh viện và cơ sở y tế chuyển dữ liệu thành những thông tin chi tiết về doanh nghiệp và duy trì hoạt động kinh doanh liên tục, đồng thời bảo vệ quyền riêng tư của bệnh nhân. Datalake là một kho lưu trữ tập trung, được quản lý và bảo mật để lưu trữ tất cả dữ liệu của bạn, cả ở dạng ban đầu và đã xử lý để phân tích. Datalake cho phép bạn chia nhỏ các kho chứa dữ liệu và kết hợp các loại phân tích khác nhau để có được thông tin chi tiết và đưa ra các quyết định kinh doanh tốt hơn.

Bài đăng trên blog này là một phần của loạt bài lớn hơn về việc bắt đầu cài đặt datalake dành cho lĩnh vực y tế. Trong bài đăng blog cuối cùng của tôi trong loạt bài, “ Bắt đầu với datalake dành cho lĩnh vực y tế: Đào sâu vào Amazon Cognito”, tôi tập trung vào các chi tiết cụ thể của việc sử dụng Amazon CognitoAttribute Based Access Control (ABAC) để xác thực và ủy quyền người dùng trong giải pháp datalake y tế. Trong blog này, tôi trình bày chi tiết cách giải pháp đã phát triển ở cấp độ cơ bản, bao gồm các quyết định thiết kế mà tôi đã đưa ra và các tính năng bổ sung được sử dụng. Bạn có thể truy cập các code samples cho giải pháp tại Git repo này để tham khảo.

Hướng dẫn kiến trúc

Thay đổi chính kể từ lần trình bày cuối cùng của kiến trúc tổng thể là việc tách dịch vụ đơn lẻ thành một tập hợp các dịch vụ nhỏ để cải thiện khả năng bảo trì và tính linh hoạt. Việc tích hợp một lượng lớn dữ liệu y tế khác nhau thường yêu cầu các trình kết nối chuyên biệt cho từng định dạng; bằng cách giữ chúng được đóng gói riêng biệt với microservices, chúng ta có thể thêm, xóa và sửa đổi từng trình kết nối mà không ảnh hưởng đến những kết nối khác. Các microservices được kết nối rời thông qua tin nhắn publish/subscribe tập trung trong cái mà tôi gọi là “pub/sub hub”.

Giải pháp này đại diện cho những gì tôi sẽ coi là một lần lặp nước rút hợp lý khác từ last post của tôi. Phạm vi vẫn được giới hạn trong việc nhập và phân tích cú pháp đơn giản của các HL7v2 messages được định dạng theo Quy tắc mã hóa 7 (ER7) thông qua giao diện REST.

Kiến trúc giải pháp bây giờ như sau:

Hình 1. Kiến trúc tổng thể; những ô màu thể hiện những dịch vụ riêng biệt.

Mặc dù thuật ngữ microservices có một số sự mơ hồ cố hữu,  một số đặc điểm là chung : chúng nhỏ, tự chủ, kết hợp rời rạc, có thể tái sử dụng, giao tiếp thông qua giao diện được xác định rõ, chuyên biệt để giải quyết một việc và thường được triển khai trong event-driven architecture.

Khi xác định vị trí tạo ranh giới giữa các microservices, cần cân nhắc các yếu tố nội tại như công nghệ được sử dụng và các tính năng như hiệu suất, độ tin cậy và khả năng mở rộng; các yếu tố bên ngoài như chức năng phụ thuộc, tần suất thay đổi và khả năng tái sử dụng; và các yếu tố con người như quyền sở hữu nhóm và quản lý cognitive load.

Khi chọn công nghệ và patterns để xác định microservices và giao diện giữa chúng, bạn có thể tham khảo phạm vi giao tiếp sau để xem xét các sự lựa chọn của mình:

Phạm vi giao tiếpCác công nghệ / mô hình cần xem xét
Trong một microservice Amazon Simple Queue Service (Amazon SQS)AWS Step Functions
Giữa các microservices trong một dịch vụAWS CloudFormation cross-stack referencesAmazon Simple Notification Service (Amazon SNS)
Giữa các dịch vụAmazon EventBridgeAWS Cloud MapAmazon API Gateway
The pub/sub hub

Việc sử dụng kiến trúc kiểu hub-and-spoke (còn được gọi là message broker) hoạt động tốt với một số lượng nhỏ các microservices có liên quan chặt chẽ. Nó giúp giữ cho các chức năng phụ thuộc ở mức tối thiểu vì mỗi microservice chỉ phụ thuộc vào sự tồn tại của trung tâm (hub) và việc kết nối giữa các microservice được giới hạn ở nội dung của message được xuất. Vì pub / sub là kiểu giao tiếp ‘push’ không đồng bộ một chiều nên nó giảm thiểu số lượng synchronous calls.

Tính linh hoạt đi kèm với sự đánh đổi của cấu trúc. Các subscribers của ‘hub’ sử dụng message attributesfiltering để xác định message nào cần xử lý và message nào cần bỏ qua. Do đó, vẫn cần sự phối hợp và giám sát để tránh microservice hoạt động dựa trên một message không dành cho nó. 

Core microservice

Core microservice cung cấp dữ liệu nền tảng và lớp truyền thông. Nó bao gồm các thành phần sau:

  • Bucket dữ liệu của  Amazon Simple Storage Service (Amazon S3)
  • Danh mục dữ liệu dựa trên Amazon DynamoDB , hiện được sử dụng để theo dõi nguồn gốc dữ liệu
  • Một hàm AWS Lambda để viết messages được gửi đến vào datalake và danh mục
  • Amazon SNS topic được sử dụng làm ‘hub’ cho giao tiếp microservice.
  • Một bucket Amazon S3 dành cho các artifacts như mã cho các hàm Lambda

Trong microservice này, tôi đã chọn chỉ cho phép truy cập ghi gián tiếp vào datalake và danh mục thông qua một hàm độc lập. Điều này hỗ trợ tính nhất quán và giảm gánh nặng cho các microservice khác, cho phép họ tập trung vào “cái gì” cần viết chứ không phải “cách” viết nó.

Front door microservice

Front door microservicecung cấp Cổng API để tương tác REST bên ngoài và xác thực và ủy quyền dựa trên OpenID Connect (OIDC) thông qua Amazon Cognito. Front door cung cấp một cơ chế để người dùng và dịch vụ bên ngoài giao tiếp với dịch vụ này và đảm bảo rằng các message đến được xác thực, ủy quyền và độc nhất.

Tôi đã tập trung vào các chi tiết kỹ thuật về cách OIDC sử dụng Amazon Cognito trong một bài đăng trước trong series và giải thích cách giải pháp sử dụng API Gateway trong bài đăng trước nữa; bạn có thể tham khảo các bài đăng đó để biết hướng dẫn về các thành phần tương ứng.

Đối với giải pháp microservice này, tôi đã quyết định sử dụng tính năng deduplication message tự quản lý bằng cách giữ các mã hash của các message đến trong bảng DynamoDB thay vì sử dụng tính năng deduplication của Amazon SNS. Tôi đã sử dụng tính năng tự quản lý vì ba lý do:

  1. Tính năng deduplication của Amazon SNS có thời lượng năm phút; làm việc với HL7v2 thường có thể kỳ quặc, vì vậy tôi muốn xác thực lâu dài hơn;
  2. Tính năng deduplication của Amazon SNS yêu cầu sử dụng các topic First-In-First-Out (FIFO) và phải được chuyển đến hàng đợi FIFO Amazon SQS;
  3. Bằng cách thực hiện trước bước deduplication, người gửi có thể được thông báo rằng message là một bản sao.
Staging ER7 microservice

Microservice này cung cấp những điều sau:

  1. Một hàm Lambda “trigger” được đăng ký vào pub / sub hub và lọc các messages đáp ứng các attribute  đã được định nghĩa.
  2. Một Step Functions Express Workflow được gọi để chuyển đổi các thông báo từ ER7 sang JSON.
  3. Bản thân Step Function bao gồm hai hàm Lambda: hàm đầu tiên áp dụng các sửa đổi định dạng ER7 phổ biến xung quanh newlines and carriage returns, và hàm thứ hai chứa logic parsing hầu như không thay đổi kể từ bài đầu tiên trong series.
  4. Nếu thành công, kết quả JSON được trả về “trigger”; nếu không, thông báo lỗi được trả về.
  5. Cả thành công và lỗi đều được đẩy đến hub pub / sub với việc xác định các message attributes.

Trong kiến ​​trúc mà tôi đã trình bày trong một bài đăng trước,“Adding an ingress point and data management to your healthcare data lake”, tôi đã bao gồm chức năng parsing trong một hàm Lambda và trong bài đăng đó, tôi lưu ý rằng độc giả nên xem xét việc refractor hàm. Điều này là do nó tuân thủ tốt hơn nguyên tắc microservice là chuyên môn hóa cao; đóng gói logic phức tạp khỏi phần còn lại của ứng dụng; cho phép sử dụng lại trong dịch vụ (và có thể với các dịch vụ khác); và cho phép cập nhật độc lập khi các trường hợp góc bổ sung phát sinh hoặc các thư viện parsing mới hơn.

Ở quy mô lớn hơn — chẳng hạn như nhập hàng loạt, nhiều nguồn và / hoặc custom field mapping — logic cleaning và parsing có thể tự phát triển thành một dịch vụ đầy đủ. Bạn có thể cải thiện nó vào thời điểm đó bằng cách thêm private HTTP API integration.

Các tính năng mới được sử dụng trong giải pháp datalake

Quản lý sự phụ thuộc bằng AWS CloudFormation cross-stack references

Mỗi microservice được xác định trong stack CloudFormation của riêng nó và các mối quan hệ phụ thuộc giữa chúng, cụ thể là với microservice ‘core’, được triển khai thông qua cross-stack references.

Ví dụ: trong mẫu CloudFormation cho core microservice, các outputs  được bao gồm như sau:

Outputs:

  Bucket:

    Value: !Ref Bucket

    Export:

      Name: !Sub ${AWS::StackName}-Bucket

  ArtifactBucket:

    Value: !Ref ArtifactBucket

    Export:

      Name: !Sub ${AWS::StackName}-ArtifactBucket

  Topic:

    Value: !Ref Topic

    Export:

      Name: !Sub ${AWS::StackName}-Topic

  Catalog:

    Value: !Ref Catalog

    Export:

      Name: !Sub ${AWS::StackName}-Catalog

  CatalogArn:

    Value: !GetAtt Catalog.Arn

    Export:

      Name: !Sub ${AWS::StackName}-CatalogArn

Trong một microservice phụ thuộc,  CloudFormation có thể nhập các outputs khi cần reference. Ví dụ: trong mẫu front door microservice , tên của core stack  được chuyển vào dưới dạng parameter khi tạo hoặc cập nhật stack:

Parameters:

  CoreStack:

    Description: The foundational stack

    Type: String

…

  # Ingest the ER7 message 

  LambdaFunction:

    Type: AWS::Lambda::Function

    Properties: 

      FunctionName: !Sub "${AWS::StackName}_ingest"

      Code:

        S3Bucket:

          Fn::ImportValue: !Sub "${CoreStack}-ArtifactBucket"

        S3Key: !Ref FunctionKey

        S3ObjectVersion: !Ref FunctionVersion

      Description: Ingests ER7 messages

      Handler: !Ref FunctionHandler

      Role: !GetAtt LambdaRole.Arn

      Environment:

        Variables:

          topic: 

            Fn::ImportValue: !Sub "${CoreStack}-Topic"

          table: !Ref Table

      Runtime: python3.9

Tôi nhận thấy hiện nay, như thế này là sự cân bằng phù hợp giữa quyền tự chủ và tính đơn giản, vì hầu hết các sửa đổi có thể được thực hiện mà không ảnh hưởng đến các dịch vụ nhỏ khác.

Lọc message Amazon SNS

Giải pháp đang sử dụng một topic Amazon SNS duy nhất cho “pub/sub hub”, nơi mỗi microservice gửi đến một topic trung tâm và các microservices khác subscribe dựa trên  message filtering policy của chúng.

Ví dụ về việc filter của staging microservice như sau:

 # Subscription to SNS topic

  Subscription:

    Type: AWS::SNS::Subscription

    Properties:

      TopicArn:

        Fn::ImportValue: !Sub "${CoreStack}-Topic"

      Endpoint: !GetAtt TriggerLambdaFunction.Arn

      FilterPolicy:

        protocol: [hl7v2]

        format: [er7]

      Protocol: lambda

Triển khai và thử nghiệm

Điều kiện tiên quyết

Để triển khai dự án này, bạn cần:

  • Tài khoản AWS có đủ quyền. Nếu bạn chưa có tài khoản AWS, hãy tạo và kích hoạt tài khoản
  • AWS Command Line Interface (CLI)
  • Kiến thức cơ bản về kịch bản Python. Các tập lệnh được sử dụng cho cả mã hóa và triển khai đều bằng Python và chúng tôi sử dụng “boto3“, AWS SDK cho Python.

Thiết lập môi trường

Sử dụng AWS Cloud9 làm môi trường phát triển:

1. Thiết lập Cloud9 theo hướng dẫn “Creating an EC2 Environment”.

2. Sao chép  Git repository:

git clone -b blog_4 https://github.com/aws-samples/hcls-data-lake.git

3. Chuyển sang thư mục ‘hcls-data-lake’ mới và sau đó định cấu hình môi trường Cloud9:

sh cloud9_init.sh

4. Triển khai các dịch vụ. Thay thế “$ MY_STACK_NAME” bằng tên bạn chọn. Quá trình này mất vài phút để hoàn thành.

python deploy_services.py -s $MY_STACK_NAME

Các cải tiến đã được thực hiện đối với tập lệnh triển khai để sau khi core microservice được triển khai, front door microservice và staging microservice  được triển khai song song thay vì theo một series. Bởi vì hoạt động này là không đồng bộ, cách đơn giản nhất để kiểm tra trạng thái triển khai là kiểm tra dịch vụ CloudFormation trong console.

Testing

Bên trong mã được sao chép từ  Git repo là một tập lệnh chứa mã để tạo một vài người dùng mẫu có quyền truy cập khác nhau và thử  gửi một số thông báo HL7v2 tới front door microservice .

python test_services.py -s $MY_STACK_NAME

Sau khi chạy client script này, dịch vụ trả về kết quả cho biết messages  nào đã được nhập và lưu trữ thành công, messages  nào bị từ chối do không đủ quyền và bị từ chối do trùng lặp.

Là một asynchronous call, để tìm kết quả của staging microservice, hãy vào console và xem các objects đã được tạo trong Amazon S3 bucket .

Clean up

Khi triển khai dự án này tạo ra nhiều CloudFormation stack, các scripts  cũng bao gồm chức năng tiện lợi để xóa chúng. Lưu ý rằng objects  nào được đặt trong các buckets  đã được tạo như một phần của stack cũng sẽ bị xoá.

python deploy_services.py -s $MY_STACK_NAME -d

Giống như cách triển khai ban đầu, việc xóa cũng tận dụng tính năng song song. Các front door microservice và staging microservice  được triển khai song song trước khi core microservice bị xóa.

Tóm tắt và các bước tiếp theo

Trong blog này, tôi đã đi qua kiến trúc của datalake, đề cập đến một số công nghệ được sử dụng để cung cấp khả năng decoupling tốt hơn và cung cấp cơ sở lý luận của tôi cho các quyết định thiết kế đã được thực hiện.

Bạn có bất kỳ câu hỏi nào về cách thiết lập hồ dữ liệu chăm sóc sức khỏe không?  Reach out to the AWS Public Sector Team for help.

Đọc thêm về AWS cho lĩnh vực y tế:

Bài được dịch từ bài viết trên AWS Blogs, bạn có thể xem bài viết gốc tại đây.