Is het gebruik van bestanden voor IPC met gedeeld geheugen een vereiste?

stemmen
19

Er zijn een paar projecten die gebruik maken van de MappedByteBuffers die door Java's FileChannel.map() worden geretourneerd als een manier om gedeelde geheugen-IPC's tussen JVM's op dezelfde host te hebben (zie Chronicle Queue, Aeron IPC, etc.). Voor zover ik kan zien, zit deze api gewoon bovenop de mmap-oproep. Echter, Java's implementatie staat geen anonieme (niet-bestandsondersteunde) mappings toe.

Mijn vraag is, op Java (1.8) en Linux (3.10), zijn MappedByteBuffers echt nodig voor het implementeren van shared memory IPC, of zou elke toegang tot een gemeenschappelijk bestand dezelfde functionaliteit bieden? (Deze vraag heeft geen betrekking op de prestatie-implicatie van het gebruik van een MappedByteBuffer of niet)

Hier is mijn begrip:

  1. Wanneer Linux een bestand van schijf laadt, kopieert het de inhoud van dat bestand naar pagina's in het geheugen. Dat gedeelte van het geheugen wordt de pagina-cache genoemd. Voor zover ik kan zien, doet het dit ongeacht welke Java methode (FileInputStream.read(), RandomAccessFile.read(), FileChannel.read(), FileChannel.map()) of native methode wordt gebruikt om het bestand te lezen (obseved met free en het monitoren van de cache waarde).
  2. Als een ander proces probeert hetzelfde bestand te laden (terwijl het nog in de cache staat), dan detecteert de kernel dit en hoeft het bestand niet opnieuw te worden geladen. Als de paginacache vol raakt, worden pagina's verwijderd - vuile pagina's worden terug naar de schijf geschreven. (Pagina's worden ook weer uitgeschreven als er een expliciete flush naar de schijf is, en periodiek, met een kernel-draad).
  3. Het feit dat er al een (groot) bestand in de cache staat is een belangrijke prestatieboost, veel meer dan de verschillen op basis van welke Java-methoden we gebruiken om dat bestand te openen/lezen.
  4. Een C-programma dat de mmap system call aanroept kan een ANONYMOUS mapping doen, die in wezen pagina's in de cache toewijst die niet door een echt bestand worden ondersteund (dus er is geen noodzaak om echt te schrijven naar de schijf), maar Java lijkt dat niet te bieden (zou het mappen van een bestand in tmpfs hetzelfde bereiken?)
  5. Als een bestand wordt geladen met behulp van de mmap system call (C) of via FileChannel.map() (Java), worden de pagina's van het bestand (in de cache) direct in de adresruimte van het proces geladen. Met behulp van andere methoden om een bestand te openen, wordt het bestand geladen in pagina's die zich niet in de adresruimte van het proces bevinden, en vervolgens worden door de verschillende methoden om dat bestand te lezen/schrijven enkele bytes van/naar die pagina's gekopieerd in een buffer in de adresruimte van het proces. Er is een duidelijk prestatievoordeel om die kopie te vermijden, maar mijn vraag gaat niet over de prestatie.

Dus samengevat, als ik het goed begrijp - terwijl het in kaart brengen een prestatievoordeel biedt, lijkt het niet alsof het enige gedeeld geheugen functionaliteit biedt die we niet alleen van de aard van de Linux en de pagina-cache krijgen.

Dus, laat me alsjeblieft weten waar mijn begrip vandaan komt.

Bedankt.

De vraag is gesteld op 22/05/2020 om 21:20
bron van user
In andere talen...                            


2 antwoorden

stemmen
0

Drie punten zijn het vermelden waard: prestaties, en gelijktijdige veranderingen, en geheugengebruik.

U heeft gelijk in de beoordeling dat MMAP-gebaseerd meestal een prestatievoordeel biedt ten opzichte van bestandsgebaseerde IO. In het bijzonder, de prestaties voordeel is significant als de code uit te voeren veel kleine IO op artbitraire punt van het bestand.

overweeg het veranderen van de N-de byte: met mmap buffer[N] = buffer[N] + 1, en met file based access heeft u (tenminste) 4 systeemoproepen nodig om fouten te controleren:

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

Het is waar dat het aantal werkelijke IO (naar de schijf) waarschijnlijk hetzelfde is.

Het tweede punt is de gelijktijdige toegang. Bij bestandsgebaseerde IO moet je je zorgen maken over mogelijke gelijktijdige toegang. U moet expliciet vergrendelen (voor het lezen), en ontgrendelen (na het schrijven), om te voorkomen dat twee processen voor onjuiste toegang tot de waarde op hetzelfde moment. Met gedeeld geheugen kunnen atoombewerkingen de noodzaak voor extra vergrendeling elimineren.

Het derde punt is het daadwerkelijke geheugengebruik. Voor gevallen waarin de grootte van de gedeelde objecten significant is, kan het gebruik van gedeeld geheugen een groot aantal processen toelaten om toegang te krijgen tot de gegevens zonder extra geheugen toe te wijzen. Als systemen beperkt zijn door het geheugen, of systemen die real-time prestaties moeten leveren, kan dit de enige manier zijn om toegang te krijgen tot de gegevens.

antwoordde op 29/05/2020 om 10:35
bron van user

stemmen
0

Mijn vraag is, op Java (1.8) en Linux (3.10), zijn MappedByteBuffers echt nodig voor het implementeren van shared memory IPC, of zou elke toegang tot een gemeenschappelijk bestand dezelfde functionaliteit bieden?

Het hangt af van de reden waarom u een IPC met gedeeld geheugen wilt implementeren.

U kunt IPC duidelijk implementeren zonder gedeeld geheugen; bijvoorbeeld via sockets. Dus, als u het niet doet om prestatieredenen, is het helemaal niet nodig om shared memory IPC te doen!

Dus prestaties moeten aan de basis liggen van elke discussie.

Toegang met behulp van bestanden via de Java-klassieker io of nio-API's biedt geen gedeelde geheugenfunctionaliteit of prestaties.

Het belangrijkste verschil tussen gewone bestands-I/O of Socket-I/O versus gedeeld geheugen-IPC is dat het eerste vereist dat de applicaties expliciet berichten maken readen writesynchroniseren om deze te verzenden en te ontvangen. Dit brengt extra syscalls met zich mee en houdt in dat de kernel gegevens moet kopiëren. Bovendien, als er meerdere threads zijn, heb je ofwel een apart "kanaal" nodig tussen elk threadpaar, ofwel iets om meerdere "gesprekken" over een gedeeld kanaal te multiplexen. Dit laatste kan ertoe leiden dat het gedeelde kanaal een bottleneck wordt.

Merk op dat deze overheadkosten loodrecht staan op de Linux-pagina cache.

Daarentegen zijn er bij IPC geïmplementeerd met behulp van gedeeld geheugen geen readen writesyscalls, en geen extra kopieerstap. Elk "kanaal" kan eenvoudigweg een apart gebied van de gemapte buffer gebruiken. Een thread in het ene proces schrijft data naar het gedeelde geheugen en deze is vrijwel direct zichtbaar voor het tweede proces.

Het voorbehoud is dat de processen 1) moeten worden gesynchroniseerd, en 2) geheugenbarrières moeten implementeren om ervoor te zorgen dat de lezer geen muffe gegevens ziet. Maar deze kunnen beide worden geïmplementeerd zonder synchronisatie.

In de wash-up, gedeeld geheugen IPC met behulp van memory mapped bestanden >>is<< sneller dan het gebruik van conventionele bestanden of sockets, en dat is de reden waarom mensen het doen.


U vraagt ook impliciet of shared memory IPC geïmplementeerd kan worden zonder geheugenmapped bestanden.

  • Een praktische manier zou zijn om een bestand met een geheugentoewijzing te maken voor een bestand dat in een alleen-lezen-geheugen-bestandssysteem leeft; bijvoorbeeld een "tmpfs" in Linux.

    Technisch gezien, is dat nog steeds een geheugen-mapped file. Echter, je maakt geen overheadkosten voor het doorspoelen van gegevens naar de schijf, en je vermijdt de potentiële veiligheidskwestie van privé IPC-gegevens die op de schijf terechtkomen.

  • Je zou in theorie een gedeeld segment tussen twee processen kunnen implementeren door het volgende te doen:

    • Gebruik in het bovenliggende proces mmap om een segment te creëren met MAP_ANONYMOUS | MAP_SHARED.
    • Vorkind processen. Deze zullen uiteindelijk alle delen van het segment met elkaar en het ouderproces.

    Echter, het implementeren van dat voor een Java-proces zou ... uitdagend zijn. AFAIK, Java ondersteunt dit niet.

Referentie:

antwoordde op 31/05/2020 om 06:17
bron van user

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