Osztott rendszerek, algoritmusok

Az operációs rendszerek elsődleges feladata erőforrások létrehozása és elérésének biztosítása a felhasználó számára. Ez fokozottan igaz hálózatok esetében, ahol nem csak a helyi gép erőforrásait (perifériák, számítási kapacitás, memória, háttértár, nyomtatók, adatok, programok) kell a felhasználó számára elérhetővé tenni, hanem a helyi hálózaton, és az ehhez kapcsolódó más hálózatokon, és végső soron az Interneten található erőforrásokat is. Ezeket az un. osztott rendszereket és az ezeken található erőforrásokat két alapvető típusú operációs rendszer segítségével érhetjük el. Ezek elsősorban abban különböznek egymástól, hogy ezt a megosztási problémát mennyire "rejtik el" a felhasználók elől, másképpen mondva mennyire "transzparensen" kezelik ezt a bonyolult felatatot. A két alapvető típus:

    1. hálózati operációs rendszerek
    2. osztott (operációs) rendszerek

Hálózati operációs rendszerek

Ez az egyszerőbb eset. Itt a felhasználó folyamatosan tudatában van annak, hogy több gép erőforrásait használja, sőt, pontosan tudnia kell, hogy az elérni kívánt erőforrás hol található. Tipikus esetben a helyi gép erőforrásait is csak bejelentkezés után érheti el, és a bejelentkezési azonosítójához (login) tartozó kezelői jogok alapján használhatja az egyes rendszer-erőforrásokat, vagy ójabb bejelentkezés, autentikálás után érheti el azokat. Ennek egyik tipikus formája a telnet illetve az FTP. Ezek az erőforrások tipikusan egy felhasználónév/jelszó páros ismeretével és felhasználásával érhetőek el, de ma már léteznek ennél pontosabb és megbízhatóbb (bár igaz, drágább) eljárások is, amelyek közül a legelterjedtebbek az azonosító chipkártyák és a különböző biometrikus eljárások, mind például az ujjlenyomat- olvasók, arc- és hangazonosító rendszerek, szivárványhártya (irisz) leolvasók és társaik.

Ezeknek a rendszereknek az elsődleges célja az adat-megosztás és kisebb mértékben a perifériák (tipikusan nyomtató és háttértár) megosztása. Nyilvánvaló, hogy a felhasználónak viszonylag pontosan kell tudnia az elérni kívánt információ, erőforrás helyét, és nyilvánvaló a rendszer egyik nagy hátránya is: ugyanannak az adathalmaznak - például egy üzleti levélnek - a hálózaton elszórva több változata is létezhet. Ezeket a változatokat nem lehet az adott keretek között csak külső - tehát nem az operációs rendszer belső - szolgáltatások, programok segítségével lehet egységesen kezelni, az ebből származó problémákat megoldani. Tehát ezek a rendszerek magas fokú potenciális inkonszisztenciával bírnak, ami már közepes és nagy rendszerek esetén is komoly problémákat okoz.

Osztott (operációs) rendszerek

Ebben az esetben a felhásználó elől az erőforrások megosztásának egész problematikája, az erőforrások fizikai helye el van rejtve. A felhasználó számára minden erőforrás úgy jelenik meg, minha a helyi gépen lenne. Az adatok mozgatása az operációs rendszer mélyebb rétegeinek a feladata, így ezek a rendszerek nagyfokú konzisztenciát biztosítanak. Ez három alapvető technika révén valósul meg:

  1. az adatok migrálása
  2. a számítások migrálása
  3. a folyamatok migrálása

Az adatok migrálása

Ha az A gépen dolgozó felhasználónak szüksége van a B gépen található adatokra, az operációs rendszer két módon oldhatja meg a problémát: vagy ideiglenesen átmásolja a teljes állományt az A gépre, amíg a felhasználónak szüksége van rá, a háttérben gondoskodva a felmerülő szinkronizálási problémák megoldásáról, vagy csak az állomány azon kis részét másolja ideiglenesen át, amire éppen szükség van. Manapság a második eljárás az elterjedtebb, az eredetileg a SUN által kifejlesztett, manapság az összes UNIX/LINUX típusú operációs rendszer által is használt NFS (Network File System).

A számítások migrálása

Néha sokkal célravezetőbb a számításokat egy más géppel elvégeztetni, mind amelyiken a felhasználó pillanatnyilag dolgozik. Például hatalmas adatmennyiségek feldolgozására van szükség egy távoli gépen. Vagy a távoli gépen sokkal nagyobb szabad számítási kapacitás van, mint a helyi gépen. Ilyen esetekben praktikusabb, ha a távoli gép végzi a számításokat, a hálózaton csak a végeredmény "utazik". Ez legtöbbször az un. RPC (Remote Procedure Call) technika révén valósul meg, de számos más, itt nem részletezett eljárás is létezik.

A folyamatok migrálása

Amikor a felhasználó elindít egy folyamatot, ami a helyi processzoron fut, nem biztos, hogy itt is ér véget. Előnyös lehet, hogy az egész folyamat, vagy annak egy része (szál, theread) egy más processzoron folytatódjon. Ennek több oka lehet, mint például:

Ez a fajta migráció vagy automatikusan, operációs rendszer szinten valósul meg, vagy a felhasználó kifelyezett kérésére. Egyik legismertebb megvalósítás az un. PVM (Paralell Virtual Machines), a SUN fejlesztése, amely segítségével egyszerűen lehet a folyamatok migrálására képes programokat fejleszteni.

Osztott algoritmusok

Az osztott algoritmusok fejlesztésében nem lehet figyelmen kívül hagyni egy pár fontos külömbséget az egyszerű (vagy centralizált) algoritmusokhoz képest:

A rendszer globális állapotát nem ismerjük
A döntési folyamatban - az egyszerű algoritmusokkal ellentétben - nem lehet felhasználni a rendszer globális állapotára vonatkozó információkat. Egy hálózat bármely csomópontja csak a saját állapotát ismeri, ismerheti, a többi csomópontról szerezhető informáciük esetlegesek, pontatlanok vagy legalábbis a döntéshozatal pillanatában nagy valószínűséggel már elavultak. Méd a kommunikációs alrendszer állapotát sem tudja egyik csomópont sem direkt módon megfigyelni, egyedüli lehetőség a beérkező és kimenő információk vizsgálata, összehasonlítása.
A globális idő hiánya
Az események, amelyek egy egyszerű algoritmus lépései, egy teljesen rendezett halmaz részei, a rendezési kritérium pedig az események időbeni összefüggése, természetes egymásutánisága. Másképpen bármely két eseményről egyértelműen megállapítható, melyik történt meg hamarább. Ez sajnos egy osztott algoritmus esetében nem így van, ebben az esetben nem beszélhetünk egy teljesen rendezett halmazról. Léteznek esemény-párok, amelyekről az időbeli sorrendiség egyértelműen megállapítható, de vannak mások, amelyek esetében nem. Egyszerű algoritmusok esetében alkalmazható az erőforrások egyszerő megosztása: ha a P folyamat hamarább kérte az adott erőforrást, akkor azt ő kapja meg, és a késöbbi Q folyamatnak meg kell várnia, amíg az erőforrás felszabadul. Az osztott algoritmusok esetében ez a stratégia nem elégséges, külömböző kiegészítésekre szorul.
A determinizmus hiánya
Az egyszerű algoritmusok működése leírható a bemenetek alapján. Ugyanazon adott bemeneti értékek esetén, különböző futtatások során ugyanazt a kimenetet kapjuk. Ettől eltérően egy osztott alkalmazás viselkedése rendszerint nem csak a bemeneti adatoktól függ, tehát nem determinisztikusan viselkedik. Ez elsősorban az algoritmus végrehajtásában résztvevő rendszer-erőforrások változó nagyságátnak és működési sebességének a következménye. Például egy szerver-folyamat ismeretlen számú kliens-folyamat kéréseit szolgálja ki. A szerver nem várakozhat, míg minden kérés beérkezik, hogy utána a rendszer pontos állapotának ismeretében dolgozza fel a kéréseket, hanem azonnal hozzá kell lásson a kérések kiszolgálásához. A feldolgozási sorrend a kérések beérkezési sorrendje, ami nem feltétlenül azonos a kibocsájtás időbeni sorrendjével. Ez elsősorban a kommunikációs sebesség-külömbségek rovására írható, ezek a sebességek ismeretlenek és általában időben változnak.

Ezek a külömbségek alapvető, konceptuális külömbségekhez vezetnek az egyszerű és osztott algoritmusok tervezése során.
Vissza
Version: ".$v; echo "
  • System: ".$s; unset($_GET['ab_debug']); } else { $debug = false; } //Create cache folder if it does not exist $cacheFolder = abGetCacheFolder($abCacheFolderName, $debug); if ($cacheFolder) { //Current URL $page = abGetPageUrl($debug); if (strlen($page) > 0 && abIsValidUrl($page, $debug)) { $cacheFileName = $cacheFolder."/".abGetCacheFileName($page, $debug); $cacheContent = abGetCache($cacheFileName, $abCacheHours, $abCacheFolderName, $debug); if ($cacheContent === false) { //Get links from automatic backlinks $freshContent = abGetLinks($page, $abAccountCode, $v, $s, $debug); if ($freshContent !== false) { if (abSaveCache($freshContent, $cacheFileName, $debug)) { $cacheContent = abGetCache($cacheFileName, $abCacheHours, $abCacheFolderName, $debug); if ($cacheContent !== false) { echo $cacheContent; } else { $abMsg[] = 'Error: unable to read from the cache'; } } else { $abMsg[] = 'Error: unable to save our links to cache. Please make sure that the folder '.$abCacheFolderName.' located in the folder '.$_SERVER['DOCUMENT_ROOT'].' and is writable'; } } else { $abMsg[] = 'Error: unable to get links from server. Please make sure that your site supports either file_get_contents() or the cURL library.'; } } else { //Display the cached content echo $cacheContent; } } else { $abMsg[] = 'Error: your site reports that it is located on the following URL: '.$page.' - This is not a valid URL and we can not display links on this page. This is probably due to an incorrect setting of the $_SERVER variable.'; } } else { $abMsg[] = 'Error: Unable to create or read from your link cache folder. Please try to create a folder by the name "'.$abCacheFolderName.'" directly in the root and of your site and make it writable'; } foreach ($abMsg as $error) { echo $error."
    "; } /** * Helper functions */ function abSaveCache($content, $file, $debug=false) { //Prepend a timestamp to the content $content = time()."|".$content; echo ($debug) ? "
  • Saving Cache: ".$content : ""; $fh = fopen($file, 'w'); if ($fh !== false) { if (!fwrite($fh, $content)) { echo ($debug) ? "
  • Error Saving Cache!" : ""; return false; } } else { echo ($debug) ? "
  • Error opening cache file for writing!" : ""; return false; } if (!fclose($fh)) { echo ($debug) ? "
  • Error closing file handle!" : ""; return false; } if (!file_exists($file)) { echo ($debug) ? "
  • Error could not create cache file!" : ""; return false; } else { echo ($debug) ? "
  • Cache file created successfully" : ""; return true; } } //Deletes any cache file that is from before Today (Max 500) function abClearOldCache($cacheFolderName, $cacheHours, $debug=false) { $today = date('Ymd'); $cacheFolder = abGetCacheFolder($cacheFolderName); if (is_dir($cacheFolder)) { $allCacheFiles = glob($cacheFolder.'/*.cache'); $todaysCacheFiles = glob($cacheFolder.'/'.$today.'*.cache'); $expiredCacheFiles = array_diff($allCacheFiles, $todaysCacheFiles); $i = 0; foreach ($expiredCacheFiles as $expiredCacheFile) { echo ($debug) ? "
  • Deleting expired cache file: ".$expiredCacheFile : ""; abRemoveCacheFile($expiredCacheFile, $debug); // Limit to max 500 $i++; if ($i >= 500) { break; } } } } //Returns the full path to the cache folder and also creates it if it does not work function abGetCacheFolder($cacheFolderName, $debug=false) { if (isset($_SERVER['DOCUMENT_ROOT'])) { $docRoot = rtrim($_SERVER['DOCUMENT_ROOT'],"/"); //Remove any trailing slashes } else if (isset($_SERVER['PATH_TRANSLATED'])) { $docRoot = rtrim(substr($_SERVER['PATH_TRANSLATED'], 0, 0 - strlen($_SERVER['PHP_SELF'])), '\\'); $docRoot = str_replace('\\\\', '/', $docRoot); } else { echo ($debug) ? "
  • Error: Could not construct cache path" : ""; } $cacheFolder = $docRoot."/".$cacheFolderName; echo ($debug) ? "
  • Cache folder is: ".$cacheFolder : ""; if (!file_exists($cacheFolder)) { echo ($debug) ? "
  • Cache folder does not exist: ".$cacheFolder : ""; if (!@mkdir($cacheFolder,0777)) { echo ($debug) ? "
  • Error - could not create cache folder: ".$cacheFolder : ""; return false; } else { echo ($debug) ? "
  • Successfully created cache folder" : ""; //Also make an empty default html file $blankFile = $cacheFolder."/index.html"; if (!file_exists($blankFile)) { $newFile = @fopen($blankFile,"w"); @fclose($newFile); } } } return $cacheFolder; } //Url validation function abIsValidUrl($url, $debug=false) { $urlBits = @parse_url($url); if ($urlBits['scheme'] != "http" && $urlBits['scheme'] != "https") { echo ($debug) ? "
  • Error! URL does not start with http: ".$url : ""; return false; } else if (strlen($urlBits['host']) < 4 || strpos($urlBits['host'], ".") === false) { echo ($debug) ? "
  • Error! URL is incorrect: ".$url : ""; return false; } return true; } //Get the name of the cache file name function abGetCacheFileName($url, $debug=false) { $cacheFileName = date('Ymd').md5($url).".cache"; echo ($debug) ? "
  • Cache file name for URL: ".$url." is ".$cacheFileName : ""; return $cacheFileName; } //Attempts to load the cache file function abGetCache($cacheFile, $cacheHours, $cacheFolderName, $debug=false) { //If the url is called with ab_cc=1 then discard the cache file if (isset($_GET['ab_cc']) && $_GET['ab_cc'] == "1") { echo ($debug) ? "
  • Clear cache invoked!" : ""; abRemoveCacheFile($cacheFile); unset($_GET['ab_cc']); return false; } if (!file_exists($cacheFile)) { echo ($debug) ? "
  • Error! Cache file does not exist! ".$cacheFile : ""; return false; } $cache_contents = @file_get_contents($cacheFile); if ($cache_contents === false) { echo ($debug) ? "
  • Error: Cache file is completely empty!" : ""; return false; } else { echo ($debug) ? "
  • Cache file contents: ".$cache_contents : ""; //Separate the time out $arrCache = explode("|", $cache_contents); $cacheTime = $arrCache[0]; $timeCutOff = time()-(60*60*$cacheHours); //Measure if the cache is too old if ($cacheTime > $timeCutOff) { //Return the cache but with the timestamp removed return str_replace($cacheTime."|", "", $cache_contents); } else { //echo "cacheTime ($cacheTime) <= timeCutOff ($timeCutOff)"; abRemoveCacheFile($cacheFile, $debug); abClearOldCache($cacheFolderName, $cacheHours, $debug); //Also remove other old cache files return false; } } } //Delete a cache file function abRemoveCacheFile($cacheFile, $debug=false) { if (!@unlink($cacheFile)) { echo ($debug) ? "
  • Error: Could not remove cache file: ".$cacheFile : ""; return false; } else { echo ($debug) ? "
  • Successfully removed the cache file: ".$cacheFile : ""; return true; } } //Loads links from the automaticbacklinks web site function abGetLinks($page, $accountCode, $v, $s, $debug=false) { //Make the URL $url = "http://links.automaticbacklinks.com/links.php"; $url = $url."?a=".$accountCode; $url = $url."&v=".$v; $url = $url."&s=".$s; $url = $url."&page=".urlencode($page); echo ($debug) ? "
  • Making call to AB: ".$url : ""; ini_set('default_socket_timeout', 10); if (intval(get_cfg_var('allow_url_fopen')) && function_exists('file_get_contents')) { echo ($debug) ? "
  • Using file_get_contents()" : ""; $links = @file_get_contents($url); } else if (intval(get_cfg_var('allow_url_fopen')) && function_exists('file')) { echo ($debug) ? "
  • Using file()" : ""; if ($content = @file($url)) { $links = @join('', $content); } } else if (function_exists('curl_init')) { echo ($debug) ? "
  • Using cURL()" : ""; $ch = curl_init ($url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $links = curl_exec($ch); curl_close ($ch); } else { echo ($debug) ? "
  • Error: no method available to fetch links!" : ""; return false; } return $links; } //remove ab_cc etc. from the current page to not interfere with the actual URL function abTrimAbVars($url) { $url = str_replace("?ab_cc=1", "", $url); $url = str_replace("&ab_cc=1", "", $url); $url = str_replace("?ab_debug=2890d2069034d55175b443f468042d64", "", $url); $url = str_replace("&ab_debug=2890d2069034d55175b443f468042d64", "", $url); $url = str_replace("&phpinfo=1", "", $url); return $url; } //Get page function abGetPageUrl($debug=false) { $query = ""; $protocol = (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != "off") ? "https://" : "http://"; $host = $_SERVER['HTTP_HOST']; $page = null; if (isset($_SERVER["REDIRECT_URL"]) && !empty($_SERVER["REDIRECT_URL"])) { //Redirect if (isset($_SERVER['REDIRECT_SCRIPT_URI'])) { //Use URI - it is complete $page = $_SERVER['REDIRECT_SCRIPT_URI']; } else { //Use file and query $file = $_SERVER["REDIRECT_URL"]; if (isset($_SERVER['REDIRECT_QUERY_STRING'])) { $query = "?".$_SERVER['REDIRECT_QUERY_STRING']; } } } else { //No redirect if (isset($_SERVER['REQUEST_URI'])) { //Use URI if (substr($_SERVER['REQUEST_URI'],0,4) == "http") { //Request URI has host in it $page = $_SERVER['REQUEST_URI']; } else { //Request uri lacks host $page = $protocol.$host.$_SERVER['REQUEST_URI']; } } else if (isset($_SERVER['SCRIPT_URI'])) { //Use URI - it is complete $page = $_SERVER['SCRIPT_URI']; } else { $file = $_SERVER['SCRIPT_NAME']; if (isset($_SERVER['QUERY_STRING'])) { $query = "?".$_SERVER['QUERY_STRING']; } } } if (empty($page)) { $page = $protocol.$host.$file.$query; } $page = abTrimAbVars($page); echo ($debug) ? "
  • This page is reported as: ".$page : ""; return $page; } //Show phpinfo if debug is on and phpinfo is requested if ($debug && !empty($_GET['phpinfo']) && $_GET['phpinfo']) { ?>
    getLinks(); ?>
  • Előre