简体   繁体   中英

MSR Orleans - How to create a reader-writer grain with parallel reads

I need a reader-writer grain(s?) to hold some values so other parts of the system can reference them frequently and in parallel.

What I'm after is storing some system-wide config values which are accessed frequently, and subject to change, but only extremely rarely (once a month or so at most). The system should be reconfigurable without downtime. What I'm currently considering is to store the data in some database. Then it will be read at silo startup, and there will be a special callback to read the data again after it changes externally. I don't want to read the data from the database every time I need it because:

  • It'll create unnecessary processing overhead inside the silo, as some of the data must be processed and filtered out.
  • It'll increase load on the database, which I cannot guarantee will be as good at handling high load as the silo environment.
  • The data is verified by the silo environment before it is updated. Reading directly from the database means there will be no middle layer to hold the last known valid data while the operator updates and fixes the new data.

I can easily create a reader-writer locked in-memory data store, but Orleans' single-threaded execution policy doesn't allow parallel access to the grain that holds the data. I can think of the following ways to bypass this:

  • Have multiple copies of the data inside multiple grains. This is obviously not optimal.
  • Use static fields to store the data and make the grain a stateless worker. This means every silo has its own copy of the data (which also helps with reducing network load), but there is no means of asking every silo to update its copy of the data (that I know of at least).

Suggestions?

Have you looked at something like the Smart cache pattern ?

Perhaps using a Reentrant grain could help as well, this will allow method calls to interleave.

I found this issue on github asking for the same.

We found a solution that doesn't require timer-based updates over on GitHub . I'll detail the solution here:

  1. There is a master grain, responsible for reading data from the database. This grain also receives external UpdateConfig calls when the config changes. The database is updated 'manually', so I don't care if it doesn't pick updates up automatically.
  2. There are stateless worker cache grains on every silo. These grains store the data in static objects (to help with memory footprint) and use a reader-writer lock to manage access to the data. When the first one wakes up on a silo, it updates the data and the rest just use that data. They also support an external UpdateConfig call which will in turn ask the master grain for new data.
  3. There is a bootstrap provider which does two things. First, it wakes the master grain up at init time so data is available before it is needed and thus we can avoid lazy init hiccups. Second, the provider also supports a control command (see here for an example of controllable providers). Upon receiving this command, it will ask the first available cache grain (guaranteed to be local) to update the static objects. This way, data is updated within each silo. The master grain simply sends this control command whenever it updates its data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM