ЕСОЗ - публічна документація

Medical events Technical Documentation

Architecture

Performance requirements

Indicative Volumes that might be reached some day. System is not sized based on these volumes.

Objectvolume
Patients50.000.000
Visitup to 40.000.000.000
Episodeup to 10.000.000.000
Encounterup to 40.000.000.000
Observationup to 500.000.000.000
Conditionup to 500.000.000.000
Allergy intolerance1.000.000.000
Immunization1.000.000.000

Volumes prediction and HW-sizing calculation based on it -  refer to the medical events sizing, sheet "Prod - Model4"

Async job processing Sequence diagram

Submit encounter job is processed in stages:

  1. Validation
    1. json validation
    2. create job in MongoDB
    3. package_create_job message type is created in Kafka medical_events topic
  2. package_create_job processing
    1. check that there is no jobs processing for the patient_id
      1. if not - put patient_id to processing queue (required to guarantee that new request of one patient will not be processed until the previous one has been completed)
      2. else -
    2. decode signed_content
    3. validation
    4. validation failed:
      1. update job.status == failed
      2.  error code == 4xx
    5. save signed_content
    6. If error -
      1. update job.status == failed_with_error
      2. error_code == 500
    7. else create package_save_patient type in Kafka first_medical_events topic
  3. package_save_patient processing
    1. save patient data to medical_data MongoDB collection
    2. If error -
      1. update job.status == failed_with_error
      2. error_code == 500
    3. else - create package_save_conditions type in Kafka second_medical_events topic
  4. package_save_conditions processing
    1. save conditions to conditions MongoDB collection
    2. If error - consumer fails and after restart should process the same message
    3. else - create package_save_observations type in Kafka second_medical_events topic
  5. package_save_observations processing
    1. save observations to conditions MongoDB collection
    2. If error - consumer fails and after restart should process the same message
    3. else - update_job_status message is created
  6. Update job status processing
    1. remove patient_id from processing queue
    2. update job status to processed
    3. If error - consumer fails and after restart should process the same message
    4. else - done

Decisions

#StatementComment
1.All the medical event POST/PUT operations should be async

Duration to process new records creation is not so critical for the medical service providers. They do have already all the data.

Anyway it still should be processed in seconds/minutes, not hours/days.

2.

GET operations will be sync 
3. Kafka will be used as a queue manager for the async operations
  • high performance,
  • it is scalable horizontally. 
  • open source
4.MongoDB will be used as a storage of the medical events data
  • data model is not stable, still changing and might be significantly changed in future
  • it is capable to store TBytes of data and provides possibility to quick read the data
  • It easily scales horizontally to achieve required read RPS and availability 
  • Only one master node can write at a single point of time, but write RPS is not so critical as it happens in async way.
  • open source
  • transactions and data consistency should be guaranteed by application
5.Data validation and consistancy should be guaranteed on the application levelApplication should ensure that operations will not be performed partially.
6.Medical events - new repository
  • new almost independent functionality.
  • ehealth.api becomes too huge and complex. 
7.Medical data can be accessed via API only by patient. There is no way to get the medical data of multiple patients via single call
  1. Medical data is probably the most sensitive data. It should be maximum protected. 
    1. Medical service providing process use cases suppose consuming the data of one patient at a time.
8.

We do split the medical data into three collections:

  • patient_medical_data
    • encounters - 100x
    • visits - 100x
    • episodes - 100x
  • observations - 100.000x
  • conditions - 10.000x
  • Number of observations and conditions per patients might be dozens of thousands. 
  • Number of encounters - hundreds.
  • It is recommended to keep one document size less than few Mbytes in average.
9.We do split the storing data structure and presentation views (requests/responses)
  • it allows to be HL7 compliance from the API perspective
  • application logic is not dependent on the database
10.We do guarantee jobs processing sequence for one patient_id. Not for all the jobs
  • multi partitions should be created on Kafka
  • System guarantees that all the requests related to the specific patient_id should be routed to the same partition
  • Number of consumers = number of partitions.
11.

ME database shouldn't store MPI_ID.

Patient_id in ME will be encrypted using secret key.

  • There should be no possibility to back-track record from ME to MPI without the key
  • key should be securely stored and used only by application.
  • All the records are encrypted with the same key. If key is compromised, the whole DB should be migrated.

Limitations

  1. Medical data profile of one patient (encounters, visits, episodes, allergy intolerance, immunizations) shouldn't exceed 16 Mbytes (~700-1000 encounters)
  2. Medical data can be accessed via API only by patient_id and via patient context. There is no way to get the medical data of multiple patients via single call
  3. System's architecture provides possibility to operate in the 24/7 mode. But in case if the master MongoDB node is down, there might be a downtime (up to minutes). We still do need the system maintenance time slots.
  4. MongoDB limitations. The most important ones:
    1. The maximum BSON document size is 16 megabytes.
    2. MongoDB supports no more than 100 levels of nesting for BSON documents.
    3. The total size of an index entry, which can include structural overhead depending on the BSON type, must be less than 1024 bytes.
    4. A single collection can have no more than 64 indexes.
    5. There can be no more than 31 fields in a compound index.
    6. Multikey indexes cannot cover queries over array field(s).
    7. Database size: The MMAPv1 storage engine limits each database to no more than 16000 data files. This means that a single MMAPv1 database has a maximum size of 32TB. Setting the storage.mmapv1.smallFiles option reduces this limit to 8TB.

    8. Data Size: Using the MMAPv1 storage engine, a single mongod instance cannot manage a data set that exceeds maximum virtual memory address space provided by the underlying operating system. For Linux journaled data size of 64 TB
    9. Replica sets can have up to 50 members.
    10. Covered Queries in Sharded ClustersStarting in MongoDB 3.0, an index cannot cover a query on a sharded collection when run against a mongosif the index does not contain the shard key, with the following exception for the _id index: If a query on a sharded collection only specifies a condition on the _id field and returns only the _id field, the _id index can cover the query when run against a mongos even if the _id field is not the shard key.
    11. MongoDB does not support unique indexes across shards, except when the unique index contains the full shard key as a prefix of the index. In these situations MongoDB will enforce uniqueness across the full key, not a single field.
    12. A shard key cannot exceed 512 bytes.

    13. Shard Key Index Type

      A shard key index can be an ascending index on the shard key, a compound index that start with the shard key and specify ascending order for the shard key, or a hashed index.

      A shard key index cannot be an index that specifies a multikey index, a text index or a geospatial index on the shard key fields.

    14. Shard Key is Immutable

Open questions

#QuestionAnswer
1.Failed jobs processing

there are only two possible results of job processing: processed, error.

Both of them mean that job has been successfully processed.

2.

Jobs are processed FIFO. But it means that next job will not be processed until the current one is completed. 

It means that the whole system might block itself in case of problems of processing a single record.

in case if internal server or service error happens (50x), it will be forwarded to client.

Option to be considered: put message back to the queue or move it to error queue. But in this case order processing cannot be guaranteed.

ЕСОЗ - публічна документація