Fájlok használata megosztott memória IPC-hez, szükséges-e a memória leképezése?

szavazat
19

Van néhány projekt, amelyek a Java FileChannel.map () által visszaadott MappedByteBuffers-t használják arra, hogy megoszthassák az IPC memóriáját az azonos gazdagépen lévő JVM-ek között (lásd a Chronicle Queue, Aeron IPC stb.). Amennyire meg tudom mondani, ez az api csak az mmap hívás tetején ül. A Java végrehajtása azonban nem engedélyezi a névtelen (nem fájl által támogatott) leképezéseket.

A kérdésem az, hogy Java (1.8) és Linux (3.10) esetén a MappedByteBuffers valóban szükségesek-ea megosztott memória IPC megvalósításához, vagy ha egy közös fájlhoz való hozzáférés ugyanazt a funkciót biztosítja? (Ez a kérdés nem vonatkozik a MappedByteBuffer használatának teljesítményével kapcsolatos következményeire.)

Itt van a megértésem:

  1. Amikor a Linux betölti a fájlt a lemeztől, a fájl tartalmát a memóriában lévő oldalakra másolja. Ezt a memória régiót oldal gyorsítótárnak nevezzük. Amennyire meg tudom mondani, akkor ezt teszi, függetlenül attól, hogy melyik Java módszert (FileInputStream.read (), RandomAccessFile.read (), FileChannel.read (), FileChannel.map ()) vagy natív módszert használják a fájl olvasására ( feltöltve "free" -vel és figyelemmel kísérve a "cache" értéket).
  2. Ha egy másik folyamat megkísérli betölteni ugyanazt a fájlt (miközben továbbra is a gyorsítótárban található), a kernel ezt észleli, és nem kell újratöltenie a fájlt. Ha az oldal gyorsítótár megtelik, az oldalakat kilakoltatják - a piszkosokat visszahelyezik a lemezre. (Az oldalak szintén visszakerülnek, ha van egy explicit öblítés a lemezen, és rendszeresen egy kernelszállal).
  3. Ha a (nagy) fájl már a gyorsítótárban van, az jelentős teljesítménynövelést jelent, még inkább, mint a különbségek, amelyek alapján a Java módszereket használjuk a fájl megnyitására / olvasására.
  4. Az mmap rendszerhívást hívó AC program ANONYMOUS leképezést hajthat végre, amely lényegében a gyorsítótárban olyan oldalakat allokál, amelyeket nem egy tényleges fájl támogat (tehát nincs szükség tényleges írások kiadására a lemezre), de a Java nem tűnik ezt ajánlani (egy fájl leképezése a tmpfs fájlban ugyanazt tenné-e?)
  5. Ha egy fájlt az mmap rendszerhívással (C) vagy a FileChannel.map () (Java) keresztül tölt be, lényegében a fájl oldalai (a gyorsítótárban) kerülnek közvetlenül a folyamat címterére. A fájl megnyitásához más módszerekkel a fájlt azokra a lapokra tölti be, amelyek nem szerepelnek a folyamat címében, majd a fájl olvasására / írására szolgáló különféle módszerek másolnak néhány bájtot az ezektől az oldalaktól egy pufferré a folyamat címe területén. . Nyilvánvaló előnye van annak, hogy elkerüljük ezt a példányt, de a kérdésem nem a teljesítményre vonatkozik.

Tehát összefoglalva: ha helyesen értem - miközben a feltérképezés teljesítmény előnyt kínál, nem tűnik úgy, hogy olyan „megosztott memória” funkciókat kínál, amelyeket nem csak a Linux természetéből és az oldal gyorsítótárából származunk.

Szóval, kérlek, tudassa velem, hol van a megértésem.

Köszönöm.

A kérdést 22/05/2020 21:20
a forrás felhasználó
Más nyelveken...                            


2 válasz

szavazat
0

Érdemes megemlíteni három pontot: teljesítmény és egyidejű változások és memóriahasználat.

Helyesen ítéli meg, hogy az MMAP-alapú teljesítmény előnyt kínál általában a fájl alapú IO-hoz képest. Különösen a teljesítmény előnye akkor jelentős, ha a kód sok kis IO-t hajt végre a fájl tetszőleges pontján.

fontolja meg az N-edik bájt megváltoztatását: az mmap segítségével buffer[N] = buffer[N] + 1 , és fájl alapú hozzáféréssel (legalább) 4 rendszerhívás hibaellenőrzésre van szüksége:

   seek() + error check
   read() + error check
   update value
   seek() + error check
   write + error check

Igaz, hogy a tényleges IO (a lemezre) száma valószínűleg megegyezik.

A második pont, amely érdemes megjegyezni az egyidejű hozzáférést. A fájl alapú IO esetén aggódnia kell a lehetséges egyidejű hozzáférések miatt. Ki kell adnia egyértelmű zárolást (az olvasás előtt) és a feloldást (az írás után), hogy megakadályozza, hogy két folyamat egyszerre érje el az értéket. A megosztott memória segítségével az atomműveletek kiküszöbölhetik a további zárolás szükségességét.

A harmadik pont a tényleges memóriafelhasználás. Azokban az esetekben, amikor a megosztott objektumok mérete jelentős, a megosztott memória használata lehetővé teszi számos folyamat számára az adatok elérését további memória kiosztása nélkül. Ha a memóriát korlátozó rendszerek vagy a valósidejű teljesítményt biztosító rendszerek működnek, ez lehet az egyetlen mód az adatok elérésére.

Válaszolt 29/05/2020 10:35
a forrás felhasználó

szavazat
0

A kérdésem az, hogy Java (1.8) és Linux (3.10) esetén a MappedByteBuffers valóban szükségesek-ea megosztott memória IPC megvalósításához, vagy ha egy közös fájlhoz való hozzáférés ugyanazt a funkciót biztosítja?

Attól függ, hogy miért akarja megvalósítani a megosztott memória IPC-jét.

Az IPC egyértelműen megvalósítható megosztott memória nélkül; pl. aljzatok fölött. Tehát, ha nem teljesítmény okokból csinálja, akkor egyáltalán nem szükséges megosztott memória IPC-t csinálni!

Tehát a teljesítménynek minden beszélgetés gyökerének kell lennie.

A fájlokkal való hozzáférés a Java klasszikus io vagy nio API-n keresztül nem biztosítja a megosztott memória funkcióit vagy teljesítményét.

A fő különbség a normál fájl I / O vagy a Socket I / O és a megosztott memória IPC között az, hogy az előbbi megköveteli az alkalmazásoktól, hogy kifejezetten read és write syscalls üzenetek küldésére és fogadására. Ez további rendszerhívásokat és a rendszermag adatainak másolását vonja maga után. Ezen túlmenően, ha több szál van, akkor külön szálra van szüksége az egyes szálpárok között, vagy valami a több "beszélgetés" multiplexeléséhez egy megosztott csatornán. Ez utóbbi azt eredményezheti, hogy a megosztott csatorna párhuzamos szűk keresztmetszetté válik.

Vegye figyelembe, hogy ezek a általános költségek merőlegesek a Linux oldal gyorsítótárához.

Ezzel szemben a megosztott memória használatával megvalósított IPC-vel nincs read és write syscalls, és nincs külön példány. Minden "csatorna" egyszerűen külön felhasználhatja a leképezett puffer külön területét. Az egyik folyamat szála az adatokat írja a megosztott memóriába, és szinte azonnal látható a második folyamatban.

Az a figyelmeztetés, hogy a folyamatoknak 1) szinkronizálniuk kell és 2) memóriakorlátokat kell végrehajtaniuk annak biztosítása érdekében, hogy az olvasó ne jelenjen meg elavult adatok. De ezek mindkettő végrehajtható rendszerhívások nélkül.

A mosás során a megosztott memória IPC memórialeképezett fájlokat használva >> gyorsabb, mint a hagyományos fájlok vagy foglalatok használata, ezért az emberek ezt teszik.


Azt is hallgatólagosan megkérdezte, hogy a megosztott memória IPC megvalósítható-e memórialeképezett fájlok nélkül.

  • Gyakorlati módszer egy memórialeképezéssel ellátott fájl létrehozása egy olyan fájl számára, amely csak memória fájlrendszerben él; pl. egy "tmpfs" Linuxon.

    Technikai szempontból ez még mindig egy memóriával leképezett fájl. Ugyanakkor nem merül fel az adat lemezre történő átmosásának általános költsége, és elkerüli a lemezen lévő magán IPC-adatokkal kapcsolatos lehetséges biztonsági aggályokat.

  • Elméletileg meg lehet valósítani a két folyamat közötti megosztott szegmenst az alábbiak szerint:

    • A szülő folyamatban az mmap használatával hozhat létre szegmenst a MAP_ANONYMOUS | MAP_SHARED .
    • Villás gyermek folyamatok. Ezek végül megosztják a szegmenst egymással és a szülő folyamatot.

    Ennek megvalósítása egy Java folyamatnál azonban ... kihívást jelent. AFAIK, a Java nem támogatja ezt.

Referencia:

Válaszolt 31/05/2020 06:17
a forrás felhasználó

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more