ObjectRepository - .NET in-memory repository iphethini yamaphrojekthi akho asekhaya

Kungani ugcina yonke idatha enkumbulweni?

Ukugcina iwebhusayithi noma idatha ye-backend, isifiso sokuqala sabantu abaningi abahlakaniphile kuzoba ukukhetha isizindalwazi se-SQL. 

Kodwa ngezinye izikhathi umcabango ufika engqondweni ukuthi imodeli yedatha ayifanele i-SQL: isibonelo, lapho wakha usesho noma igrafu yomphakathi, udinga ukucinga ubudlelwano obuyinkimbinkimbi phakathi kwezinto. 

Isimo esibi kakhulu kulapho nisebenza neqembu futhi ozakwenu engazi ukwakha imibuzo esheshayo. Singakanani isikhathi osichithe uxazulula izinkinga ze-N+1 futhi wakha izinkomba ezengeziwe ukuze OKUKHETHA ekhasini eliyinhloko kuzoqeda ngenani elifanele lesikhathi?

Enye indlela edumile i-NoSQL. Eminyakeni eminingana edlule bekunokuningi ukushuba ngalesi sihloko - nganoma yisiphi isikhathi esikahle bathumela i-MongoDB futhi bajabule ngezimpendulo ngendlela yemibhalo ye-json. (Kodwa-ke, zingaki izinduku okumelwe uzifake ngenxa yezixhumanisi eziyindilinga kumadokhumenti?).

Ngiphakamisa ukuzama enye, enye indlela - kungani ungazami ukugcina yonke idatha kumemori yohlelo lokusebenza, ukuyigcina ngezikhathi ezithile kwisitoreji esingahleliwe (ifayela, i-database ekude)? 

Imemori isishibhile, futhi noma iyiphi idatha engaba khona yamaphrojekthi amaningi amancane naphakathi izongena kumemori engu-1 GB. (Isibonelo, iphrojekthi yami yasekhaya eyintandokazi yile umkhondo wezezimali, okugcina izibalo zansuku zonke kanye nomlando wezindleko zami, ibhalansi, kanye nokuthengiselana unyaka nesigamu, kudla inkumbulo engu-45 MB kuphela.)

Izinzuzo:

  • Ukufinyelela kudatha kuba lula - awudingi ukukhathazeka ngemibuzo, ukulayisha okuvilaphayo, izici ze-ORM, usebenza ngezinto ezijwayelekile ze-C#;
  • Azikho izinkinga ezihlobene nokufinyelela okuvela emilukweni ehlukene;
  • Ngokushesha kakhulu - azikho izicelo zenethiwekhi, akukho ukuhunyushwa kwekhodi olimini lwemibuzo, asikho isidingo (de) se-serialization yezinto;
  • Kwamukelekile ukugcina idatha nganoma yiluphi uhlobo - kungaba ku-XML kudiski, noma ku-SQL Server, noma ku-Azure Table Storage.

Umthengi:

  • Ukukala okuvundlile kulahleka, futhi ngenxa yalokho, ukuthunyelwa kwe-zero downtime akukwazi ukwenziwa;
  • Uma uhlelo lokusebenza luphahlazeka, ungase ulahlekelwe idatha. (Kodwa uhlelo lwethu lokusebenza alulokothi luphahlazeke, akunjalo?)

Isebenza kanjani?

I-algorithm imi kanjena:

  • Ekuqaleni, uxhumano luyasungulwa nokugcinwa kwedatha, futhi idatha iyalayishwa;
  • Imodeli yento, izinkomba eziyinhloko, nezinkomba ezihlobene (1:1, 1:Many) ziyakhiwa;
  • Ukubhalisa kudalelwa izinguquko ezakhiweni zento (INotifyPropertyChanged) kanye nokwengeza noma ukususa izinto eqoqweni (INotifyCollectionChanged);
  • Uma ukubhalisa kuqaliswa, into eshintshile yengezwa emgqeni ukuze kubhalwe endaweni yokugcina idatha;
  • Izinguquko endaweni yokulondoloza zigcinwa ngezikhathi ezithile (kusibali sikhathi) kuchungechunge lwangemuva;
  • Uma uphuma ohlelweni, izinguquko nazo zigcinwa endaweni yokugcina.

Isibonelo sekhodi

Ukwengeza okuncikile okudingekayo

// Основная библиотека
Install-Package OutCode.EscapeTeams.ObjectRepository
    
// Хранилище данных, в котором будут сохраняться изменения
// Используйте то, которым будете пользоваться.
Install-Package OutCode.EscapeTeams.ObjectRepository.File
Install-Package OutCode.EscapeTeams.ObjectRepository.LiteDb
Install-Package OutCode.EscapeTeams.ObjectRepository.AzureTableStorage
    
// Опционально - если нужно хранить модель данных для Hangfire
// Install-Package OutCode.EscapeTeams.ObjectRepository.Hangfire

Sichaza imodeli yedatha ezogcinwa kusitoreji

public class ParentEntity : BaseEntity
{
    public ParentEntity(Guid id) => Id = id;
}
    
public class ChildEntity : BaseEntity
{
    public ChildEntity(Guid id) => Id = id;
    public Guid ParentId { get; set; }
    public string Value { get; set; }
}

Bese imodeli yento:

public class ParentModel : ModelBase
{
    public ParentModel(ParentEntity entity)
    {
        Entity = entity;
    }
    
    public ParentModel()
    {
        Entity = new ParentEntity(Guid.NewGuid());
    }
    
    public Guid? NullableId => null;
    
    // Пример связи 1:Many
    public IEnumerable<ChildModel> Children => Multiple<ChildModel>(x => x.ParentId);
    
    protected override BaseEntity Entity { get; }
}
    
public class ChildModel : ModelBase
{
    private ChildEntity _childEntity;
    
    public ChildModel(ChildEntity entity)
    {
        _childEntity = entity;
    }
    
    public ChildModel() 
    {
        _childEntity = new ChildEntity(Guid.NewGuid());
    }
    
    public Guid ParentId
    {
        get => _childEntity.ParentId;
        set => UpdateProperty(() => _childEntity.ParentId, value);
    }
    
    public string Value
    {
        get => _childEntity.Value;
        set => UpdateProperty(() => _childEntity.Value, value
    }
    
    // Доступ с поиском по индексу
    public ParentModel Parent => Single<ParentModel>(ParentId);
    
    protected override BaseEntity Entity => _childEntity;
}

Futhi ekugcineni, isigaba senqolobane ngokwaso sokufinyelela idatha:

public class MyObjectRepository : ObjectRepositoryBase
{
    public MyObjectRepository(IStorage storage) : base(storage, NullLogger.Instance)
    {
        IsReadOnly = true; // Для тестов, позволяет не сохранять изменения в базу
    
        AddType((ParentEntity x) => new ParentModel(x));
        AddType((ChildEntity x) => new ChildModel(x));
    
        // Если используется Hangfire и необходимо хранить модель данных для Hangfire в ObjectRepository
        // this.RegisterHangfireScheme(); 
    
        Initialize();
    }
}

Dala isibonelo se-ObjectRepository:

var memory = new MemoryStream();
var db = new LiteDatabase(memory);
var dbStorage = new LiteDbStorage(db);
    
var repository = new MyObjectRepository(dbStorage);
await repository.WaitForInitialize();

Uma iphrojekthi izosebenzisa i-HangFire

public void ConfigureServices(IServiceCollection services, ObjectRepository objectRepository)
{
    services.AddHangfire(s => s.UseHangfireStorage(objectRepository));
}

Ukufaka into entsha:

var newParent = new ParentModel()
repository.Add(newParent);

Ngale kholi, into Imodeli Yomzali yengezwa kukho kokubili inqolobane yendawo kanye nomugqa wokubhala kusizindalwazi. Ngakho-ke, lokhu kusebenza kuthatha u-O(1), futhi le nto ingasetshenzwa nayo ngokushesha.

Isibonelo, ukuthola le nto endaweni yokugcina nokuqinisekisa ukuthi into ebuyisiwe iyisibonelo esifanayo:

var parents = repository.Set<ParentModel>();
var myParent = parents.Find(newParent.Id);
Assert.IsTrue(ReferenceEquals(myParent, newParent));

Kwenzekani? Setha () izimbuyiselo TableDictionary, equkethe ConcurrentDictionary futhi ihlinzeka ngokusebenza okwengeziwe kwezinkomba eziyisisekelo nesesibili. Lokhu kukuvumela ukuthi ube nezindlela zokusesha nge-Id (noma ezinye izinkomba zabasebenzisi ezingafanele) ngaphandle kokuphindaphinda ngokuphelele kuzo zonke izinto.

Lapho wengeza izinto ObjectRepository okubhaliselwe kuyengezwa ukuze kushintshwe izici zazo, ngakho-ke noma yiluphi ushintsho kuzakhiwo luphinde lubangele ukuthi le nto yengezwe kulayini wokubhala. 
Ukubuyekeza izakhiwo kusuka ngaphandle kubukeka kufana nokusebenza ngento ye-POCO:

myParent.Children.First().Property = "Updated value";

Ungasusa into ngezindlela ezilandelayo:

repository.Remove(myParent);
repository.RemoveRange(otherParents);
repository.Remove<ParentModel>(x => !x.Children.Any());

Lokhu kuphinda kwengeze into kumugqa wokususa.

Kusebenza kanjani ukonga?

ObjectRepository lapho izinto ezigadwayo zishintsha (ukwengeza noma ukususa, noma ukushintsha izakhiwo), kuphakamisa umcimbi Imodeli Ishintshiweubhalisele Isitoreji. Ukwenziwa Isitoreji uma kwenzeka isigameko Imodeli Ishintshiwe izinguquko zifakwa emigqeni emi-3 - yokwengeza, yokubuyekeza, kanye nokususa.

Futhi ukusetshenziswa Isitoreji ekuqaliseni, bakha isibali sikhathi esibangela ukuthi izinguquko zilondolozwe njalo ngemizuzwana emi-5. 

Ngaphezu kwalokho, kukhona i-API yokuphoqelela ikholi yokulondoloza: ObjectRepository.Londoloza().

Ngaphambi kokulondoloza ngakunye, imisebenzi engasho lutho iqala ikhishwe kulayini (isibonelo, izenzakalo eziyimpinda - lapho into ishintshwe kabili noma izinto zengezwa/zisuswa ngokushesha), bese kuba kuphela lapho kuzigcina khona. 

Kuzo zonke izimo, yonke into yamanje igcinwa, ngakho-ke kungenzeka ukuthi izinto zigcinwa ngendlela ehlukile kunaleyo ezishintshile ngayo, okuhlanganisa izinguqulo ezintsha zezinto kunangesikhathi zengezwa kulayini.

Yini enye ekhona?

  • Yonke imitapo yolwazi isekelwe ku-.NET Standard 2.0. Ingasetshenziswa kunoma iyiphi iphrojekthi yesimanje ye-.NET.
  • I-API iphephile ngochungechunge. Amaqoqo angaphakathi asetshenziswa ngokusekelwe kulokho ConcurrentDictionary, abaphathi bemicimbi bangaba nezingidi noma abazidingi. 
    Okuwukuphela kwento okufanele uyikhumbule ukufona ObjectRepository.Londoloza();
  • Izinkomba ezingafanele (zidinga okuhlukile):

repository.Set<ChildModel>().AddIndex(x => x.Value);
repository.Set<ChildModel>().Find(x => x.Value, "myValue");

Ubani oyisebenzisayo?

Ngokwami, ngaqala ukusebenzisa le ndlela kuwo wonke amaphrojekthi wokuzilibazisa ngoba ilula futhi ayidingi izindleko ezinkulu zokubhala isendlalelo sokufinyelela idatha noma ukuthumela ingqalasizinda esindayo. Ngokwami, ukugcina idatha ku-litedb noma ifayela kuvamise ukunginele. 

Kepha esikhathini esedlule, lapho i-EscapeTeams engasebenzi manje (Ngacabanga ukuthi nansi imali - kodwa cha, isipiliyoni futhi) - esetshenziselwa ukugcina idatha ku-Azure Table Storage.

Izinhlelo zekusasa

Ngingathanda ukulungisa enye yezinto ezimbi eziyinhloko zale ndlela - ukukala okuvundlile. Ukuze wenze lokhu, udinga ukuthengiselana okusabalalisiwe (sic!), noma wenze isinqumo esiqinile sokuthi idatha efanayo evela ezimeni ezihlukene akufanele ishintshe, noma uyivumele ishintshe ngokuvumelana nesimiso esithi "owokugcina olungile."

Ngokombono wezobuchwepheshe, ngibona isikimu esilandelayo ngangokunokwenzeka:

  • Gcina i-EventLog ne-Snapshot esikhundleni semodeli yento
  • Thola ezinye izimo (engeza iziphetho zazo zonke izimo kuzilungiselelo? ukutholakala kwe-udp? master/slave?)
  • Phinda futhi phakathi kwezenzakalo ze-EventLog usebenzisa noma iyiphi i-algorithm yokuvumelana, njenge-RAFT.

Kukhona futhi enye inkinga engikhathazayo - ukususwa kwe-cascade, noma ukutholwa kwamacala okususwa kwezinto ezinezixhumanisi ezivela kwezinye izinto. 

Umthombo

Uma ufunde yonke indlela eya lapha, okusele ukufunda ikhodi; ingatholakala ku-GitHub:
https://github.com/DiverOfDark/ObjectRepository

Source: www.habr.com

Engeza amazwana