Memcacheとは何ですか?
Memcacheクラスター環境のキャッシュソリューション
Memcacheは、高性能分散メモリオブジェクトキャッシュシステムです。メモリに統一された巨大なハッシュテーブルを維持することにより、画像、ビデオ、ファイル、データベースの取得結果など、さまざまな形式のデータを保存するために使用できます。簡単に言えば、データをメモリに呼び出してからメモリから読み取り、読み取り速度を大幅に改善することです。
MemcacheはDangaのプロジェクトです。 LiveJournalによって最初に提供されました。もともとは、LiveJournalのアクセス速度を高速化するために開発されました。後に多くの大規模なWebサイトで採用されました。
Memcachedは、デーモンモードで1つ以上のサーバーで実行され、いつでもクライアントの接続と操作を受信します。
なぜmemcacheとmemcachedの2つの名前があるのですか?
実際、Memcacheはこのプロジェクトの名前であり、Memcachedはそのサーバー側のメインプログラムファイル名です。私の言っていることが分かるよね。 1つはプロジェクト名で、もう1つはメインプログラムファイル名です。多くの人がそれを理解していないことをオンラインで見たので、私はそれを混ぜました。
Memcachedは、データベースの負荷を削減し、動的アプリケーションのアクセス速度を向上させるために使用される高性能の分散メモリオブジェクトキャッシュシステムです。 Memcachedは、LiveJournal.comへのアクセスを改善するためにDanga Interactiveによって開発されました。 LJは毎秒数千の動的なページ訪問を行い、700万人のユーザーがいます。 Memcachedは、データベースの負荷を大幅に削減し、リソースをより適切に割り当て、アクセスを高速化します。
この記事では、以下を取り上げます。
memcache
Memcacheは、データベースコール、API呼び出し、またはページレンダリングの結果からの任意のデータ(文字列、オブジェクト)の小さなチャンク用のメモリ内キー価値ストアです。
つまり、Key-Valueペアデータベースであるインメモリキャッシュデータベースです。データベースは、メモリ内の他のサービスから取得したデータを一時的に保存するために存在し、繰り返されるアクセス時にヒットキャッシュから直接返すことができます。これにより、アクセス率が高速化されるだけでなく、他のサービスの負荷も削減されます。ここでは、Memcacheの単一サーバーバージョンが実装され、複数のクライアント間の同時接続をサポートします。
クライアントは、サーバーとのTelnet接続を確立し、Memcacheプロトコルに従ってサーバーキャッシュと対話します。ここで実装されている指示は、Get、Set、Delです。各命令の形式を見てみましょう
セット
セットはストレージ命令です。命令の特性を保存する場合、基本情報を最初の行に入力し、対応する値を2行目に入力します。
SET <Key> <Flags> <Exptime> <bytes> [noreply]/r/n
<値>/r/n
ストレージが成功した場合、保存された保存が返され、指令にNoreply属性が含まれている場合、サーバーは情報を返しません。
この指令の各ドメインの内容は次のとおりです。
命令が基準を満たしていない場合、サーバーはエラーを返します。
得る
GETはGETコマンドであり、このコマンドの特性は次のとおりです。
<key>*/r/nを取得します
複数のキーの合格値をサポートします。キャッシュが1つ以上のキーにヒットすると、対応するデータが返され、終了で終了します。ヒットが行われない場合、返されたメッセージにはキーに対応する値が含まれていません。フォーマットは次のとおりです。
Value <Key> <Flags> <bytes>/r/n <データブロック>/r/nValue <Key> <Flags> <bytes>/r/n <データブロック>/r/nenddel
コマンドを削除すると、コマンドの形式は次のとおりです。
del <key> [noreply]/r/n
削除が成功した場合、削除/r/nを返し、それ以外の場合はnot_foundを返します。 NOREPLYパラメーターがある場合、サーバーは応答を返しません。
Javaソケット
Javaソケットは、TCPプロトコル、ソケット、およびIOストリームです。ここでは詳しく説明しません。私の一連の記事を参照できます。また、Javaネットワークプログラミングを読むこともお勧めします。本。
コード実装
ここでは、マップ機能が問題になっています。記事の最後にある私のプロジェクトアドレスにアクセスして、クラス図を表示できます。
ここでは、命令モードと工場モードを使用して、命令の作成と実行の分離を実装します。コマンドファクトリーはコマンドラインを受け取り、コマンドインスタンスを返します。各コマンドには、独自のユニークな操作を実行する実行方法があります。 DEL命令の特別な実装のみがここに投稿されています。
/** *さまざまなディレクティブ *現在、get、set、delete * * *およびcustom *エラー、end */public interfaceコマンド{/** * @param reader * @param writer */void execute(reader reader、writer writer)をサポートしています。 / ***コマンドのタイプを取得* @return*/ commandType getType();} /***ディレクティブファクトリーの単一インスタンス*/public class commandfactory {private static commandfactory commandfactory;プライベート静的キャッシュ<item> memcache; private commandfactory(){} public static commandfactory getInstance(cache <item> cache){if(commandfactory == null){commandfactory = new CommandFactory(); memcache = cache; } return commandfactory; } / ** *ディレクティブのタイプに従ってコマンドを取得 * @param commandline * @return * / public command getCommand(string commandline){if(commandline.matches( "^set。 * $")){return new setCommand(commandline、memcache); } else if(commandline.matches( "^get。*$")){return new getCommand(commandline、memcache); } else if(commandline.matches( "^del。*$")){return new deletecommand(commandline、memcache); } else if(commandline.matches( "^end $")){return new endcommand(commandline); } else {return new errorcommand(commandline、errorcommand.errortype.error); }}} /***キャッシュディレクティブを削除*/public class deletecommand command {private final stringコマンド;プライベートファイナルキャッシュ<item>キャッシュ。プライベート文字列キー。プライベートブールナレプライ。 public deletecommand(最終文字列コマンド、最終キャッシュ<アイテム>キャッシュ){this.command = command; this.cache = cache; initcommand(); } private void initcommand(){if(this.command.contains( "noreply")){noreply = true; } string [] info = command.split( ""); key = info [1]; } @Override public void execute(Reader Reader、Writer Writer){bufferedwriter bfw =(bufferedwriter)writer; item item = cache.delete(key); if(!noreply){try {if(item == null){bfw.write( "not_found/r/n"); } else {bfw.write( "削除/r/n"); } bfw.flush(); } catch(ioException e){try {bfw.write( "error/r/n"); bfw.flush(); } catch(ioexception e1){e1.printstacktrace(); } e.printstacktrace(); }}} @Override public commandType getType(){return commandType.search; }}次に、メモリサーバーを実装します。ファーストインファーストアウト機能をサポートするために、LinkedTreeMapは基礎となる実装として使用され、remodESTestメソッドが書き直されます。同時に、CacheManagerの背景スレッドは、期限切れのキャッシュエントリを時間内にクリアするためにも使用されます。
パブリッククラスmemcacheはcache <item> {private logger logger = logger.getLogger(memcache.class.getName()); // linkedhashmapを使用して、lru private static linkedhashmap <string、item> cacheを実装します。プライベートファイナルイントマックスサイズ。 //ロードファクタープライベートファイナルフロートdefault_load_factor = 0.75f; public memcache(final int maxsize){this.maxsize = maxsize; // maxsizeに到達した後、キャッシュが自動的に展開されないことを確認してください。 this.cache = new linkedhashmap <string、item>(容量、default_load_factor、true){@override protected boolean removeeldestentry(map.entry <string、item> eldest){if(size()> maxsize){ogger.info( "cache not in super sull seed of sult exted" } return size()> maxsize; }}; // Synchronized Access Collections.synchronizedMap(キャッシュ)を実装します。 } public synchronized boolean isfull(){return cache.size()> = maxsize; } @Override public item get(string key){item item = cache.get(key); if(item == null){logger.info( "cache in cache:" + key + "not Not inced"); nullを返します。 } else if(item!= null && item.isexpired()){//キャッシュの有効期限が切れた場合、null logger.infoを削除して返す( "cache:" + key + "value:" + item.getValue() + "が有効期限が切れます"); cache.remove(key); nullを返します。 } logger.info( "キャッシュからキーを読む:" + key + "value:" + item.getValue() + "残りの有効な時間" + item.remaintime());返品アイテム。 } @Override public void set(string key、item value){logger.info( "cache:" + key + "value:" + value); cache.put(key、value); } @Override public item delete(string key){logger.info( "cache:" + key); cache.remove(key)を返します。 } @Override public int size(){return cache.size(); } @Override public int capiought(){return maxsize; } @Override public Iterator <map.entry <string、item >> iterator(){return cache.entryset()。iterator(); }} /***キャッシュマネージャー*バックグラウンドスレッド*キャッシュで期限切れのキャッシュを削除*/パブリッククラスCACHEMANAGER実装runnable {private logger logger = ogger.getLogger(cachemanager.class.getName()); //パブリックキャッシュ<item>キャッシュをキャッシュします。 public cachemanager(cache <item> cache){this.cache = cache; } @Override public void run(){while(true){iterator <map.entry <string、item >> itemiterator = cache.iterator(); while(itemiterator.hasnext()){map.entry <string、item> entry = itemiterator.next(); item item = entry.getValue(); if(item.isexpired()){logger.info( "key:" + entry.getKey() + "value" + item.getValue() + "有効、データベースから削除された"); itemiterator.remove(); }} try {// 5秒ごとにバックグラウンドプログラムを実行するTimeUnit.seconds.sleep(5); } catch(arturnedexception e){e.printstacktrace(); }}}}最後に、マルチスレッドソケットサーバーを実装します。ここでは、サーバーソケットがインターフェイスにバインドされ、受け入れられたソケットを追加のスレッドに引き渡します。
/*** SERVER*/PUBLIC CLASS IOSERVER IMPLEMESS SERVER {private Boolean Stop; //ポート番号プライベートファイナルイントポート。 //サーバースレッドプライベートサーバーソケットサーバーソケット。プライベートファイナルロガーロガー= logger.getLogger(ioserver.class.getName()); //スレッドプール、スレッド容量はmaxconnectionプライベート最終executorservice executorserviceです。プライベートファイナルキャッシュ<item>キャッシュ。 public ioserver(int port、int maxconnection、cache <item> cache){if(maxconnection <= 0)新しいIllegalargumentexception( "サポートされている接続の最大数は正の整数でなければなりません"); this.port = port; executorservice = executors.newfixedthreadpool(maxconnection); this.cache = cache; } @Override public void start(){try {serversocket = new Serversocket(port); logger.info( "サーバーはポートで起動します"+ポート+"); e.printstacktrace() !Serversocket.isclosed(); /***各クライアントの接続を処理* end命令を取得した後、接続を閉じます。プライベート最終ソケットソケット。プライベートファイナルキャッシュ<item>キャッシュ。プライベートブール仕上げ; Public Sockethandler(Socket S、Cache <item> Cache){this.socket = s; this.cache = cache; } @Override public void run(){try {// get socket input stream final bufferedreader reader = new BufferedReader(new inputstreamreader(socket.getinputStream())); // get socket output stream final bufferedwriter writer = new BufferedWriter(new outputStreamWriter(socket.getOutputStream())); commandfactory commandfactory = commandfactory.getInstance(cache); while(!finish){final string commandline = reader.readline(); logger.info( "ip:" + socket.getLocalAddress() + "directive:" + commandline); if(commandline == null || commandline.trim()。isempty()){継続; } //コマンドファクトリを使用して、コマンドインスタンスfinalコマンドコマンド= commandfactory.getCommand(commandline)を取得します。 command.execute(reader、writer); if(command.getType()== commandType.end){logger.info( "接続を閉じるリクエスト");仕上げ= true; }}} catch(ioexception e){e.printstacktrace(); logger.info( "" + socket.getLocalAddress() + ""から接続を閉じる); }最後に{try {if(socket!= null){socket.close(); }} catch(ioexception e){e.printstacktrace(); }}}}プロジェクトアドレスについては、ここをクリックしてください。あなたがそれがかなり良いと思うなら、私はあなたが私に星を与えることができることを願っています。
参照
Memcached公式ウェブサイト
Memcacheプロトコル
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。