ObjectRepository - .NET kwimemori yokugcina ipatheni yeeprojekthi zakho zasekhaya

Kutheni ukugcina yonke idatha kwimemori?

Ukugcina iwebhusayithi okanye idatha ye-backend, umnqweno wokuqala wabantu abaninzi abanengqondo iya kuba kukhetha isiseko sedatha ye-SQL. 

Kodwa ngamanye amaxesha ingcinga ifika engqondweni yokuba imodeli yedatha ayifanelekanga kwi-SQL: umzekelo, xa usakha uphando okanye igrafu yentlalo, kufuneka ukhangele ubudlelwane obunzima phakathi kwezinto. 

Eyona meko imbi kakhulu kuxa usebenza kwiqela kwaye umntu osebenza naye engayazi indlela yokwenza imibuzo ekhawulezileyo. Lingakanani ixesha olichithile ukusombulula iingxaki ze-N+1 kunye nokwakha izalathisi ezongezelelweyo ukuze KHETHA kwiphepha eliphambili ligqibe ngexesha elifanelekileyo?

Enye indlela ethandwayo yiNoSQL. Kwiminyaka eliqela eyadlulayo bekukho i-hype eninzi malunga nesi sihloko - ngalo naliphi na ithuba elifanelekileyo basebenzise iMongoDB kwaye bonwabile ziimpendulo ngohlobo lwamaxwebhu ejson. (kodwa ke, zingaphi iintonga ekufanele uzifakile ngenxa yekhonkco lesetyhula kumaxwebhu?).

Ndicebisa ukuba uzame enye, enye indlela - kutheni ungazami ukugcina yonke idatha kwimemori yesicelo, uyigcine ngamaxesha athile kwisitoreji esingahleliwe (ifayile, i-database ekude)? 

Imemori iye yancinci, kwaye nayiphi na idatha enokwenzeka kwiiprojekthi ezincinci kunye neziphakathi ziya kungena kwi-1 GB yememori. (Umzekelo, iprojekthi yam yasekhaya endiyithandayo yile umkhondo wezezimali, egcina izibalo zemihla ngemihla kunye nembali yeendleko zam, ibhalansi, kunye neentengiselwano unyaka onesiqingatha, idla kuphela i-45 MB yememori.)

Iinkonzo:

  • Ukufikelela kwidatha kuba lula - awudingi ukuba nexhala malunga nemibuzo, ukulayisha ukonqena, iimpawu zeORM, usebenza ngezinto eziqhelekileyo zeC #;
  • Akukho zingxaki ezinxulumene nokufikelela kwimisonto eyahlukeneyo;
  • Ngokukhawuleza kakhulu - akukho zicelo zenethiwekhi, akukho kuguqulelwa kwekhowudi kulwimi lombuzo, akukho mfuneko (de) ye-serialization yezinto;
  • Kuyamkeleka ukugcina idatha kuyo nayiphi na ifom - ingaba kwi-XML kwidiski, okanye kwi-SQL Server, okanye kwi-Azure Table Storage.

Umgcini:

  • Ukulinganisa okuthe tye kulahlekile, kwaye ngenxa yoko, ukuhanjiswa kwexesha lokunciphisa i-zero akunakwenziwa;
  • Ukuba isicelo siyawa, ungaphulukana nedatha ngokuyinxenye. (Kodwa isicelo sethu asizange sitshatyalaliswe, akunjalo?)

Isebenza njani?

Ialgorithm imi ngolu hlobo lulandelayo:

  • Ekuqaleni, uxhulumaniso lusekwe kunye nokugcinwa kwedatha, kwaye idatha ilayishiwe;
  • Imodeli yento, izalathisi eziphambili, kunye nezalathisi ezizalanayo (1:1, 1:Many) zakhiwe;
  • Umrhumo wenzelwe utshintsho kwiipropati zezinto (INotifyPropertyChanged) kunye nokongeza okanye ukususa izinto kwingqokelela (INotifyCollectionChanged);
  • Xa ukubhaliswa kuqhutywe, into etshintshileyo yongezwa kumgca wokubhala kwisitoreji sedatha;
  • Utshintsho kugcino lugcinwa ngamaxesha athile (kwisibali-xesha) kumsonto ongasemva;
  • Xa uphuma kusetyenziso, utshintsho lukwagcinwa kwindawo yokugcina.

Umzekelo wekhowudi

Ukongeza ukuxhomekeka okufunekayo

// Основная библиотека
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 eya kugcinwa kwindawo yokugcina

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; }
}

Emva koko 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;
}

Kwaye ekugqibeleni, iklasi yokugcina ngokwayo ukufikelela kwidatha:

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();
    }
}

Yenza umzekelo weObjectRepository:

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

Ukuba iprojekthi iya kusebenzisa i-HangFire

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

Kufakwe into entsha:

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

Ngalo mnxeba, into UmzaliUmzekelo yongezwa kwi-cache yendawo kunye nomgca wokubhala kwisiseko sedatha. Ngoko ke, lo msebenzi uthatha i-O(1), kwaye le nto inokusetyenzwa nayo ngoko nangoko.

Umzekelo, ukufumana le nto kwindawo yokugcina kwaye uqinisekise ukuba into ebuyisiweyo ingumzekelo ofanayo:

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

Kwenzekani? Seta () iimbuyekezo Uluhlu lwesichazimagama, equlathe ConcurrentDictionary kwaye ibonelela ngomsebenzi owongezelelweyo wezalathisi eziphambili neziziisekondari. Oku kukuvumela ukuba ube neendlela zokuphendla nge-Id (okanye ezinye izalathisi zomsebenzisi ezingenasizathu) ngaphandle kokuphinda-phinda ngokupheleleyo phezu kwazo zonke izinto.

Xa ukongeza izinto ObjectRepository umrhumo wongezwa ukutshintsha iipropati zabo, ngoko naluphi na utshintsho kwiipropati kwakhona kubangela ukuba le nto yongezwe kumgca wokubhala. 
Ukuhlaziya iipropathi ezivela ngaphandle kujongeka ngokufanayo nokusebenza ngento yePOCO:

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

Ungayicima into ngezi ndlela zilandelayo:

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

Oku kwakhona yongeza into kumgca wocimo.

Kusebenza njani ukonga?

ObjectRepository xa izinto ezibekwe esweni zitshintsha (ukongeza okanye ukucima, okanye ukutshintsha iipropathi), kuphakamisa isiganeko Imodeli etshintshiweyoubhalisele Ugcino. Ukuphunyezwa Ugcino xa isiganeko sisenzeka Imodeli etshintshiweyo Utshintsho lubekwe kwimigca emi-3 - yokudibanisa, ukuhlaziya, kunye nokucima.

Kwakhona ukuphunyezwa Ugcino ekuqaliseni, benza isibali-xesha esibangela ukuba utshintsho lugcinwe rhoqo kwimizuzwana emi-5. 

Ukongeza, kukho i-API yokunyanzela umnxeba wokugcina: ObjectRepository.Gcina().

Phambi kogcino ngalunye, imisebenzi engenantsingiselo iqala isuswe kwimigca (umzekelo, ukuphinda-phinda iziganeko - xa into yatshintshwa kabini okanye ngokukhawuleza idityaniswe/isusiwe izinto), kwaye kuphela emva koko uzigcine. 

Kuzo zonke iimeko, yonke into yangoku igcinwa, ngoko ke kunokwenzeka ukuba izinto zigcinwe ngendlela eyahlukileyo kunokuba zitshintshwe, kubandakanywa neenguqulelo ezintsha zezinto kunokuba zongezwa kumgca.

Yintoni enye ekhoyo?

  • Onke amathala eencwadi asekelwe kwi-NET Standard 2.0. Ingasetyenziswa kuyo nayiphi na iprojekthi yangoku ye-NET.
  • I-API ikhuselekile ngomsonto. Ingqokelela yangaphakathi iphunyezwa ngokusekelwe ConcurrentDictionary, abaphathi beminyhadala banezitshixo okanye abazifuni. 
    Ekuphela kwento ekufanele uyikhumbule kukufowuna ObjectRepository.Gcina();
  • Izalathisi ezingafanelekanga (zifuna ukohluka):

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

Ngubani oyisebenzisayo?

Ngokomntu, ndaqala ukusebenzisa le ndlela kuzo zonke iiprojekthi zokuzilibazisa ngenxa yokuba ilungile kwaye ayifuni iindleko ezinkulu zokubhala uluhlu lokufikelela kwidatha okanye ukuhambisa iziseko ezinzima. Ngokwam, ukugcina idatha kwi-litedb okanye ifayile ihlala yanele kum. 

Kodwa kwixesha elidlulileyo, xa isiqalo esingasebenziyo ngoku i-EscapeTeams (Ndacinga ukuba nantsi imali - kodwa hayi, amava kwakhona) - isetyenziselwa ukugcina idatha kwi-Azure Table Storage.

Izicwangciso zekamva

Ndingathanda ukulungisa enye yeengxaki eziphambili zale ndlela - ukulinganisa okuthe tye. Ukwenza oku, udinga ukuthengiselana okusasazwayo (sic!), Okanye wenze isigqibo esinamandla sokuba idatha efanayo evela kwiimeko ezahlukeneyo ayifanele itshintshe, okanye ubavumele batshintshe ngokomgaqo othi "ngubani wokugqibela ulungile."

Ukusuka kumbono wobugcisa, ndibona esi sikimu silandelayo sinokwenzeka:

  • Gcina i-EventLog kunye ne-Snapshot endaweni yemodeli yento
  • Fumana eminye imizekelo (yongeza isiphelo semizekelo yonke kwiseto?
  • Phinda kwakhona phakathi kweziganeko ze-EventLog ngokusebenzisa nayiphi na i-algorithm yemvumelwano, efana ne-RAFT.

Kukho nenye ingxaki endikhathazayo - ukucinywa kwe-cascade, okanye ukufumanisa iimeko zokucima izinto ezinonxibelelwano olusuka kwezinye izinto. 

Ikhowudi yomthombo

Ukuba ufunde yonke indlela ukuya apha, ke konke okuseleyo kukufunda ikhowudi; inokufumaneka kwiGitHub:
https://github.com/DiverOfDark/ObjectRepository

umthombo: www.habr.com

Yongeza izimvo