Results 1 to 9 of 9

Thread: Backup agent in Windows Service, met zipper en login

  1. #1

    Smile Backup agent in Windows Service, met zipper en login

    Hoi,

    Dit is geen vraag, maar een verslag van mijn ervaringen. Misschien bespaart het anderen wat tijd.

    Als je een Windows Service wilt schrijven, dan kan dat prima in Delphi, met de .NET library en een geschikt workframe.
    Voor tips D7-XE, zie http://stackoverflow.com/questions/5...e-using-delphi

    De applicatie die ik wilde maken heeft de volgende taak:

    - Op een non-Domain Windows 7 machine PROD verschijnen met regelmaat grote aantallen zeer kleine files, die moeten worden gebackupt
    - De service moet dit materiaal naar onze Domain-bedrijfsserver SERVER schrijven en de gebruikte diskruimte op de non-Domain machine beperkt houden

    PROTOTYPE FASE 1: Backup met CopyFile naar een share

    Deze taak had ik in eerste instantie geschreven in Delphi-7 met behulp van CopyFile.

    Dit bleek niet levensvatbaar. Er worden zeer grote hoeveelheden (>30000) kleine files geproduceerd en het gebruik van CopyFile
    naar een share bleek zeer traag te worden bij meer dan 8000 files op de share. Een third party zipper was geen optie, die bleek te traag.

    PROTOTYPE FASE 2: Eigen protocol, client en server

    Na enige vergeefse omzwervingen met zippers (Abbrevia gaf teveel belasting..) had ik besloten om de CopyFile methode los te laten. De tweede versie van mijn programma bestond uit een Delphi-7 client en server en een eigen TCP/IP protocol. De files werden door de serverkant in een NON-share weggeschreven en dat werkte dus wel voor grote aantallen bestanden. Deze setup heeft een tijdje gefunctioneerd, alleen het nadeel was, dat mijn Clientserver zeer kwetsbaar was voor timeouts en netwerkstoringen.. ook kortstondige storingen. Als gevolg hiervan moest ik regelmatig opnieuw opstarten en waren de files aan de kant van de bedrijfsserver soms niet op tijd beschikbaar.

    PROTOTYPE FASE 3: .NET met Ionic zipper

    Op een bepaald punt is door het management besloten, om deze taak in Visual Studio en .NET te implementeren.

    Het opzetten van een backup-programma met .NET zoals in fase 1 verliep gladjes.. maar ook met .NET had ik schalingsproblemen: grote hoeveelheden kleine files gaven slechte performance. Toen is onderzocht, of er een geschikte zipper was in .NET. Het bijbehorende zipper-platform (.NET Ionic) bleek zeer snel en geschikt voor mijn toepassing. Het zou kunnen, dat het native Delphi XE zipper (TZipFile) ook snel genoeg is hiervoor, maar ik heb geen beschikking over een Delphi-XE om dat te testen.

    Download link voor Ionic: https://dotnetzip.codeplex.com/releases/view/68268

    DEPLOYMENT: .NET, password protectie op de server, Windows service

    Om het zaakje gladjes en veilig te laten verlopen, is het belangrijk om een password te hebben op de server-kant share. Dat had ik tot nu toe niet gedaan omdat e.e.a. in ontwikkeling was. De deployment nadert en daarvoor is het óók noodzakelijk, dat de applicatie voor de gebruiker verborgen is, d.w.z. geen icons, het mag niet worden afgesloten en het moet zich herstellen na een boot van de client. Een mogelijkheid hiervoor is, om een executable vanuit registry Windows/run met een tray-icon te gebruiken, maar de "officieele" weg (Windows Service) is netter.

    Hier kwamen wat struikelpunten boven water:

    1. Mijn service had geen toegang tot de registry.

    2. Het lukte om de service te maken en daar de backup-procedure met zipper aan te koppelen. Maar toen ik een password op de share zette.. boem !

    Oplossing ad. 1

    Na enig googlen kwam ik er achter, dat de Service context gebruik maakt van registry LOCALMACHINE en niet van CURRENTUSER. De oplossing was dus, om mijn registratie in LOCALMACHINE/Software onder te brengen.

    Oplossing ad. 2.

    Deze was ingewikkelder ! Er is dus een login nodig, vanuit de Service OnStart procedure. Ga je googlen op wnetaddconnection2() en Windows Service.. een oerwoud van onopgeloste problemen. Er circuleren nogal wat oplossingen die niet werken. En broodje-aap verhalen. Een vaak gehoorde bewering is bijvoorbeeld, dat de Service-user te weinig permissies zou hebben voor externe bronnen. Dat is natuurlijk zo voor de Service-user zelf, maar in dit geval wilde ik inloggen met de eigen naam ("peter") en password en het mag niet uitmaken, wie dat doet. Op de server was de share correct ingesteld. Dus: wnetaddconnection2(NT, 'password', 'peter',1)

    Zie diagram 1 hieronder. De login verloopt de eerste keer correct, maarrrr.. een service moet je kunnen starten, stoppen en weer opnieuw starten. Nu bleek, dat het uitloggen met de methode in diagram 1 niet werkt binnen een service. De volgende aanroep van wnetaddconnection2() resulteert in een 1312, óók als het uitloggen daarvoor met resultaat 0 terugkwam. De enige oplossing is om de server te rebooten. Waarom dat precies zo werkt.. het moet een fout zijn in de wnetcancelconnection2() uitlog-procedure. Diverse bronnen bevestigen dit bange vermoeden.

    De tweede oplossing die ik heb geprobeerd, was het mounten van een network drive. Dat bleek wel te werken vanuit mijn testprogramma. Zie deze link voor aanwijzingen. De aanroep is weer wnetaddconnection2(), maar de voorbereiding van het Net Resource record is anders. Ik heb de aanwijzingen precies opgevolgd in mijn testprogramma. Het werkte prachtig buiten de Services-context en Explorer liet de aangemaakte drive zelfs zien en de drive verdween weer bij uitloggen. Mooi mooi..

    Maar helaas.. vanuit de service geeft het maken van een network drive precies dezelfde problemen. Geen logout, dus de volgende keer resulteert de aanroep in een result=1312. De network-drive werd in Explorer ook niet correct weergegeven, wanneer ik hem aanmaakte vanuit de service.

    Een network drive disconnect dus wel, maar was geen optie vanuit de Windows Service context..

    De oplossing bleek uiteindelijk vrij simpel. Zie diagram 2. Wanneer "peter" een user is op de server, dan werkt het wel !!

    Bottom line: wanneer je een backup-service maakt die naar een Domein-server moet copieeren, dan moet op de domein server daarvoor een gebruiker worden aangemaakt. De aanroep is dan wnetaddconnection2(NT, 'password', 'server\peter',1)

    Met dank aan Walt op SO, die met deze tip kwam:

    http://stackoverflow.com/questions/2...indows-service

    Hopelijk heeft men hier iets aan,

    Lex
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	ROSIPlaatje1.jpg 
Views:	270 
Size:	33.4 KB 
ID:	6841   Click image for larger version. 

Name:	ROSIPlaatje2.jpg 
Views:	274 
Size:	32.7 KB 
ID:	6842  
    Last edited by LxGoodies; 16-Nov-14 at 22:38.
    Minstens ?®?®n hobby naast programmeerwerk is echt noodzakelijk

  2. #2
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Ik heb zoiets ook aan de hand gehad, voor de synchronizatie van meetgegevens. Snelheid was niet zo belangrijk.

    Ik gebruik movefileex voor het kopieren, die is doorgaans atomisch:
    Delphi Code:
    1. moveFileEx(pwidechar(src),pwidechar(dest),MOVEFILE_COPY_ALLOWED+MOVEFILE_REPLACE_EXISTING+MOVEFILE_WRITE_THROUGH)

    mijn waddnetconnection code ziet er zo uit: (deze runned eens per 5 minuten of zo, om de link zoveel mogelijk op te laten zijn)

    Delphi Code:
    1. function MakeDriveMapping(DriveLetter: string; DirectoryPath: string;
    2.   Username: string; Password: string; RestoreAtLogon: Boolean): DWORD;
    3. var
    4.   NetResource: TNetResource;
    5.   dwFlags: DWORD;
    6. begin
    7.   with NetResource do
    8.   begin
    9.     dwType := RESOURCETYPE_DISK;
    10.     lpLocalName := PChar(DriveLetter);
    11.     lpRemoteName := PChar(DirectoryPath);
    12.   lpProvider := nil;
    13.   end;
    14.  
    15.   if (RestoreAtLogon) then
    16.     dwFlags := CONNECT_UPDATE_PROFILE
    17.   else
    18.     dwFlags := 0;
    19.  
    20.   Result := WNetAddConnection2(NetResource, PChar(Password),
    21.     PChar(Username), dwFlags);
    22. end;
    23.  
    24. procedure createmapping;
    25. var res : dword;
    26. begin
    27.    res:= MakeDriveMapping(mountdrive,sharepath,account,password,false);
    28.    mappingsucceeded :=res=0;
    29.    if res<>0 then
    30.      log.logline(srcsystem,'Mapping '+sharepath +' to '+mountdrive +' as '+account +' failed, errorcode'+inttostr(res),catwarning);
    31. end;

    Zippen doe ik niet, het zijn meetgevens, nadat ze gekopieerd zijn, worden ze direct verwerkt.

    Heb je overigens geprobeerd de compressie te verlagen? Voor mijn PNG compressor (die wel snelheids eisen had) scheelde het enorm veel als ik de compressie ergens halverwege de schaal (0=none..9=best) zette.

    Configuratie is een INI file in mijn geval. Admins in deze biz hebben de neiging alleen mappen te backupen, en dan zijn ze registry settings kwijt. Tegen de share moet pwd protected zijn ben ik ook aangelopen.

  3. #3
    ha @marcov ! dank voor je reactie..

    Wat is het voordeel van een exmovefile, ipv movefile ? Ik wist trouwens niet dat movefile kon tussen machines.. om threadproblemen te voorkomen heb ik een pending delete list ingebouwd, dat werkt.. ik heb daar ook een Assert fileexists(server\..) aangehangen, omdat het bij ons nodig is voor de certificatie, dat het backup-proces controleert dat het werk is gedaan. Als er een movefile is, kan ik dat loopje uitkleden, maar stel dat ik de file aan de andere kant niet aantref, is ie er dan nog wel na een movefile ?

    Leuk om het voorbeeld te zien in Delphi. Ik heb voor de mapdrive testerij de code gebruikt die ik online aantrof.. zie link. Het enige verschil met een wnetaddconnection2 login is, dat je in je NetResource een LocalName invult.. Overigens bleek dat in de service context dus niet te werken. Twee problemen: de drive stond in Explorer rood, "disconnected".. en de logout werkte niet. Kans dat het natuurlijk wel werkt met server\user, dat heb ik verder niet meer getest. Ik denk nu dat de drive rood is omdat er geen share is naar de local user.

    Quote Originally Posted by marcov
    Zippen doe ik niet, het zijn meetgevens, nadat ze gekopieerd zijn, worden ze direct verwerkt.
    Tsja aan deze kant zijn het ook meetgegevens, maar het is vrij oude apparatuur dus wet van de remmende voorsprong.. de devices 1 en 2 maken enorm veel data aan in kleine files. Het is een productieproces, dus dan zit je aan het einde van de dag met 100-300.000 files. Zippen is dus niet alleen voor de performance, ook voor de overzichtelijkheid en toegankelijkheid van de backup. Als de gebruiker wil kijken in de gebackupte data, dan heb ik daarvoor een Delphi-7 appje met Abbrevia klaarstaan aan de client-kant. Een en ander scheelt serverbelasting en heel veel wachttijd tussen werkvloer en backoffice..

    Quote Originally Posted by marcov
    Configuratie is een INI file in mijn geval. Admins in deze biz hebben de neiging alleen mappen te backupen, en dan zijn ze registry settings kwijt. Tegen de share moet pwd protected zijn ben ik ook aangelopen.
    Komt me bekend voor dat probleem.. de initialisatie van de registry - als de key nog niet bestaat - doe ik vanuit een .INI file, wanneer mijn service opstart. Ik wil sowieso niet teveel pielen op de server en op de prods..
    Minstens ?®?®n hobby naast programmeerwerk is echt noodzakelijk

  4. #4
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    movefileex staat tussen machines toe, en moved indien mogelijk, en doet copy+delete in andere gevallen. Je kan dus simpelweg willekeurige src en dest dirs opgeven. Bovendien is er een optie die zorgt dat de call niet returned voor het afgehandeld is. Ik move alleen files die een creatie datum van ouder dan een paar minuten hebben. Voorkomt allerlei sharing issues.

    Zelf zou ik in jouw situatie proberen te voorkomen dat ooit veel files in een directory staan. (veel=duizenden+). Ik zou de app later schrijven naar een directory, en die periodiek checken, en zo gauw er een x aantal instaan (x=zeg 500) of een maximale tijd inzippen (met zero compressie indien nodig). Directory operaties zijn altijd relatief kostbaar, zelfs met slechts enkele duizenden tot tienduizenden files als er tussenin ook writes gebreruen, dus zelfs als je niet over machine grenzen heen gaat. Dat snel reduceren zou prio 1 zijn voor mij. Hoe minder file operaties hoe beter (beste is natuurlijk de genererende app aanpassen maar ik neem aan dat dat niet kan).

    Zippers en tarrers zijn er voor Delphi+FPC te kust en te keur. Ik heb die van Delphi nog niet gebruikt (al ben op XE3), deels ook omdat dit origineel werk is uit de D2009 periode. Maar 64-bit zijn dit soort dingen wel belangrijker, omdat ouwe zooi vaak niet geupdate is (of de status onzeker). Mijn service is overigens 64-bit, da's makkelijker installeren op 64-bit systemen.

    Zoals gezegd heb ik meer ervaring met gecomprimeerde image formaten (png is ook zlib gebaseerd), en let enorm op die compressie kwaliteit (ik neem aan dat abbrevia dat ook kan, zoek voor zlib/inflate/compression level). Veel mensen kiezen daar "best" en dat is relatief traag. Die op een gemiddelde waarde zetten scheelt meer dan de helft in tijd, en dat staat niet in verhouding tot de compressie (output size), de hogere levels verbeteren compressie maar weinig.

    De image applicaties kunnen miljoenen files in een directory hebben (al is paar honderdduizend tot 1.5 miljoen meer realistisch). Regel 1 is dan simpelweg nooit itereren over files (findfirst). Een index bijhouden over wat je schrijft, en die gebruiken. Itereren in volle dirs is extreem duur, vooral als er ook continue naar geschreven wordt. Actieve dirs met veel files hebben ook een geheugen koste plaatje, omdat de MFT daarvoor gecached wordt. (zie sysinternals rammap.exe om MFT geheugen gebruik te monitoren, kolom metadata)
    Last edited by marcov; 17-Nov-14 at 14:46.

  5. #5
    Quote Originally Posted by marcov View Post
    movefileex staat tussen machines toe, en moved indien mogelijk, en doet copy+delete in andere gevallen. Je kan dus simpelweg willekeurige src en dest dirs opgeven. Bovendien is er een optie die zorgt dat de call niet returned voor het afgehandeld is. Ik move alleen files die een creatie datum van ouder dan een paar minuten hebben. Voorkomt allerlei sharing issues.
    Interessant is dat. Ik had die delete queue ook erin gezet, om zeker te stellen, dat een copyfile de tijd krijgt om zijn werk te doen. Files worden pas na 20-30 min gedelete. Met de delete queue (thread) bewaak ik ook de diskruimte ik toesta op een prod trouwens. Dan gaat het om zipjes: het aanmaken van de kleine files detecteer ik met een aparte thread, met een directory watcher (hook) dus die worden sowieso onmiddelijk opgeruimd.

    Voor D7 gebruik ik deze..

    http://www.osnews.com/story/7376/A_D...ass_For_Delphi

    .. maarja het project staat intussen in VS.NET, dus die heb ik niet meer nodig.

    Zelf zou ik in jouw situatie proberen te voorkomen dat ooit veel files in een directory staan. (veel=duizenden+). Ik zou de app later schrijven naar een directory, en die periodiek checken, en zo gauw er een x aantal instaan (x=zeg 500) of een maximale tijd inzippen (met zero compressie indien nodig). Directory operaties zijn altijd relatief kostbaar, zelfs met slechts enkele duizenden tot tienduizenden files als er tussenin ook writes gebreruen, dus zelfs als je niet over machine grenzen heen gaat. Dat snel reduceren zou prio 1 zijn voor mij. Hoe minder file operaties hoe beter (beste is natuurlijk de genererende app aanpassen maar ik neem aan dat dat niet kan).
    Een directory kan ik sowieso niet periodiek doen, dat is te duur.. Ik heb hooks aanstaan, dat werkt prima. Belasting van een prod is niet meer dan 0.9% tot 20% (spikes tijdens de inpak)

    Zippers en tarrers zijn er voor Delphi+FPC te kust en te keur. Ik heb die van Delphi nog niet gebruikt (al ben op XE3), deels ook omdat dit origineel werk is uit de D2009 periode. Maar 64-bit zijn dit soort dingen wel belangrijker, omdat ouwe zooi vaak niet geupdate is (of de status onzeker). Mijn service is overigens 64-bit, da's makkelijker installeren op 64-bit systemen.
    Ik gebruik al heel lang Abbrevia voor allerlei dingen. Het is niet snel, maar alle opties zitten erin - ook passw - geen memory leaks en het loopt ook prima in een (1) thread naast de main thread. Met 64-bit heb ik geen ervaring. Ik heb hier thuis wel een 64 bit en ook de toshi werkt op 64 bit, maar de prod machines zijn 32 bit, we hebben een upgrade geprobeerd maar die werkt niet (again: wet remmende voorsprong oftwel "kill your darlings", maar niet elke leverancier is daar toe bereid..)

    Zoals gezegd heb ik meer ervaring met gecomprimeerde image formaten (png is ook zlib gebaseerd), en let enorm op die compressie kwaliteit (ik neem aan dat abbrevia dat ook kan, zoek voor zlib/inflate/compression level). Veel mensen kiezen daar "best" en dat is relatief traag. Die op een gemiddelde waarde zetten scheelt meer dan de helft in tijd, en dat staat niet in verhouding tot de compressie (output size), de hogere levels verbeteren compressie maar weinig.
    Mja als het plaatjes zijn hoef je niet te zippen, of het moet alleen zijn om het aantal files te reduceren. Dat is bij mij niet het geval. De backup is fysiek ongeveer 30-40% van het origineel. En ja, Abbrevia kan ook "store" doen. Ik heb dat gebruikt voor jpg's in een andere toepassing.

    De image applicaties kunnen miljoenen files in een directory hebben (al is paar honderdduizend tot 1.5 miljoen meer realistisch). Regel 1 is dan simpelweg nooit itereren over files (findfirst). Een index bijhouden over wat je schrijft, en die gebruiken. Itereren in volle dirs is extreem duur, vooral als er ook continue naar geschreven wordt. Actieve dirs met veel files hebben ook een geheugen koste plaatje, omdat de MFT daarvoor gecached wordt. (zie sysinternals rammap.exe om MFT geheugen gebruik te monitoren, kolom metadata)
    Ik heb findfirst/findnext sowieso afgeschaft. Geen beginnen aan als een directory te groot is. Ik snap niet waarom Windoos dat niet kan.. op een Linux systeem is het geen enkel probleem om 300.000 tot 500.000 files in een directory te hebben, bij Windoos is de performance boven 16k files bedroevend. Op shares werkt het al helemaal niet. Zodra je de share loslaat wordt het sneller, maar ook dat loopt op, boven 16k files. Iets is er blijkbaar niet goed schaalbaar intern !
    Minstens ?®?®n hobby naast programmeerwerk is echt noodzakelijk

  6. #6
    Een heel werk, om dit netjes failsafe te onderhouden. Ik ben intussen een jaartje verder en de systeemeisen zijn flink opgeschroefd. De service moet boot-safe doorwerken aan beide kanten, ook wanneer de Domain server wordt gereboot.. er is van alles veranderd aan het batch-protocol en ik krijg nu ongeveer 20x zoveel size voor mijn kiezen (PNG's van de camera).

    Vandaag ontdekt hoe Microsoft geld verdient aan Pro-licenties: voor een Domain lidmaatschap heb je een Pro-versie nodig van Windows en wanneer je géén lid bent van het Domain, dan werkt de login dus niet. Zelfs wanneer je de machine netjes registreert in Active Directory op de server gaat het fout in de Service context van de client, terwijl dat normaal prima loopt voor een W7-Home User, die je toegang wilt geven tot het filesysteem database sync werkt ook niet met de gratis W7..10.. dus iedereen met een W2012 server holt naar de winkel voor Pro-licenties...
    Minstens ?®?®n hobby naast programmeerwerk is echt noodzakelijk

  7. #7
    ...of installeert een FTP server
    Marcel

  8. #8
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Quote Originally Posted by LxGoodies View Post

    Mja als het plaatjes zijn hoef je niet te zippen, of het moet alleen zijn om het aantal files te reduceren. Dat is bij mij niet het geval. De backup is fysiek ongeveer 30-40% van het origineel. En ja, Abbrevia kan ook "store" doen. Ik heb dat gebruikt voor jpg's in een andere toepassing.
    Plaatjes formaten gebruik vaak intern compressie en ook zlib (inflate/deflate), maar net zoals zip kan je daar ook de compressie instellen, en dat scheelde veel performance of je dat op higher ipv best zette.

    Directory doorloop problemen kan je evt voorkomen door een verschil te maken tussen de wachtqueue directory (wachten op moven naar een mogelijk tijdelijk onbereikbare source) en incoming directory (de locale acquistie die altijd doorgaat).

    De incoming queue blijft dan altijd kort->snelle doorloop. Daarna heb je alle data, en hoef je in de uitgaande queue nooit findfirst/next te doen

  9. #9
    Quote Originally Posted by Marcel View Post
    ...of installeert een FTP server
    Dat heb ik wel even geprobeerd in versie 1 maar het werkte moeizaam zonder compressie, omdat er grote aantallen kleine files zijn die een aparte save vereisen aan de serverkant. Je kunt natuurlijk zelf een FTP-server bouwen die dat doet.. dat was in bovenstaand project fase 1.5. Ik heb uiteindelijk in 2.0 gekozen voor een eigen protocol, om makkelijk over filegrenzen heen te continuen.. packet size > 4k is toch wel beter.

    Recent heb ik een testje gedraaid met een filetabel op SQLServer. Je schrijft dan je kleine filetjes naar een database, de namen verschijnen in een tabel (handig) en de directory size problemen verdwijnen als sneeuw voor de zon ! Dus.. er zijn waarschijnlijk veel betere oplossingen we leren elke dag bij.

    Quote Originally Posted by Marcov
    Directory doorloop problemen kan je evt voorkomen door een verschil te maken tussen de wachtqueue directory (wachten op moven naar een mogelijk tijdelijk onbereikbare source) en incoming directory (de locale acquistie die altijd doorgaat).
    Owja ik gebruik een lokale transfer directory en een aparte transfer agent thread met een eigen login. Op de locale transfer wordt eerst het materiaal voorgesorteerd (move). Per tray van N producten een directory. Wat precies de traynummer grens is.. haal ik op uit de database.
    Minstens ?®?®n hobby naast programmeerwerk is echt noodzakelijk

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •