Apa itu memcache?
Solusi cache dalam lingkungan cluster memcache
Memcache adalah sistem cache objek memori terdistribusi berkinerja tinggi. Dengan mempertahankan tabel hash terpadu dan besar dalam memori, dapat digunakan untuk menyimpan data dalam berbagai format, termasuk gambar, video, file, dan hasil pengambilan basis data. Sederhananya, itu untuk memanggil data ke dalam memori dan kemudian membacanya dari memori, sehingga sangat meningkatkan kecepatan membaca.
Memcache adalah proyek di Danga. Ini pertama kali dilayani oleh LiveJournal. Awalnya dikembangkan untuk mempercepat kecepatan akses LiveJournal. Itu kemudian diadopsi oleh banyak situs web besar.
Memcached berjalan di satu atau lebih server dalam mode daemon, dan menerima koneksi dan operasi klien kapan saja.
Mengapa ada dua nama memcache dan memcached?
Bahkan, memcache adalah nama proyek ini, dan memcached adalah nama file program utama di sisi servernya. Anda tahu apa yang saya maksud. Salah satunya adalah nama proyek dan yang lainnya adalah nama file program utama. Saya melihatnya secara online bahwa banyak orang tidak memahaminya, jadi saya mencampuradukkannya.
Memcached adalah sistem caching objek memori yang berkinerja tinggi dan terdistribusi yang digunakan untuk mengurangi beban basis data dan meningkatkan kecepatan akses dalam aplikasi dinamis. Memcached dikembangkan oleh Danga Interactive untuk meningkatkan akses ke livejournal.com. LJ memiliki ribuan kunjungan halaman dinamis per detik dan memiliki 7 juta pengguna. Memcached sangat mengurangi beban basis data, mengalokasikan sumber daya yang lebih baik dan akses yang lebih cepat.
Artikel ini akan membahas yang berikut:
Memcache
Memcache adalah penyimpanan nilai kunci dalam memori untuk potongan kecil data sewenang-wenang (string, objek) dari hasil basis data, panggilan API, atau rendering halaman.
Artinya, database cache dalam memori, yang merupakan database pasangan nilai kunci. Database ada untuk sementara menyimpan data yang diperoleh dari layanan lain dalam memori dan dapat dikembalikan langsung dari cache hit saat akses berulang. Ini tidak hanya mempercepat laju akses, tetapi juga mengurangi beban pada layanan lain. Di sini, versi server tunggal dari memcache akan diimplementasikan dan mendukung koneksi simultan antara banyak klien.
Klien akan membuat koneksi telnet dengan server dan kemudian berinteraksi dengan cache server sesuai dengan protokol memcache. Instruksi yang diterapkan di sini adalah Get, Set dan Del. Mari kita lihat format setiap instruksi
mengatur
Set adalah instruksi penyimpanan. Saat menyimpan karakteristik instruksi, masukkan informasi dasar di baris pertama dan masukkan nilai yang sesuai di baris kedua.
Atur <Eymy> <agel
<value>/r/n
Jika penyimpanan berhasil, disimpan akan dikembalikan, dan jika arahan berisi atribut noreply, server tidak akan mengembalikan informasi.
Isi masing -masing domain dalam arahan ini adalah sebagai berikut:
Jika instruksi tidak memenuhi kriteria, server akan mengembalikan kesalahan.
mendapatkan
Get adalah perintah get, dan karakteristik perintah ini adalah sebagai berikut:
Dapatkan <yy>*/r/n
Ini mendukung nilai yang lewat dari beberapa tombol. Jika cache mencapai satu atau lebih tombol, data yang sesuai akan dikembalikan dan berakhir dengan ujung. Jika tidak ada hit yang dibuat, pesan yang dikembalikan tidak berisi nilai yang sesuai dengan kunci. Formatnya adalah sebagai berikut:
Nilai <Eny> <agrand> <teTes>/r/n <Block Data>/r/nValue <Yey> <agrand> <drags>/r/n <Block Data>/r/nenddel
Hapus perintah, format perintah adalah sebagai berikut:
del <yyy> [noreply]/r/n
Jika penghapusan berhasil, ia akan mengembalikan/r/n yang dihapus, jika tidak ia akan mengembalikan not_found. Jika ada parameter noreply, server tidak akan mengembalikan respons.
Soket Java
Semua soket Java perlu diketahui adalah protokol TCP, soket, dan aliran IO. Saya tidak akan membahas detailnya di sini. Anda dapat merujuk pada serangkaian artikel saya. Juga disarankan untuk membaca pemrograman Java Network. Sebuah buku.
Implementasi Kode
Ada yang salah dengan fungsi peta di sini. Anda dapat pergi ke alamat proyek saya di akhir artikel untuk melihat diagram kelas.
Di sini, mode instruksi dan mode pabrik digunakan untuk menerapkan decoupling pembuatan dan eksekusi instruksi. Pabrik Perintah akan menerima Commandline dan mengembalikan instance perintah. Setiap perintah memiliki metode eksekusi untuk melakukan operasi uniknya sendiri. Hanya implementasi khusus dari instruksi del yang diposting di sini.
/** * berbagai arahan * Saat ini mendukung Get, Set, Delete * * dan Custom * Error, End */Perintah Antarmuka Publik {/** * Eksekusi Perintah * @param Reader * @param Writer */void Execute (pembaca pembaca, penulis penulis); / *** Dapatkan jenis perintah* @return*/ commandType getType ();} /*** Instance tunggal dari Pabrik Directive*/Public Class CommandFactory {private static commandFactory commandFactory; Private Static Cache <TEMET> memcache; private commandFactory () {} public static commandFactory getInstance (cache <TIMET> cache) {if (commandFactory == null) {commandFactory = commandFactory baru (); memcache = cache; } return commandfactory; } / ** * Dapatkan perintah sesuai dengan jenis arahan * @param commandline * @return * / perintah publik getCommand (string commandline) {if (commandline.matches ("^set. * $")) {Return baru 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); }}} /*** Hapus Cache Directive*/Public Class Deletecommand mengimplementasikan perintah {private final string perintah; cache akhir privat <TEMET> cache; kunci string pribadi; noreply boolean pribadi; deletecommand publik (perintah string final, cache akhir <TEMET> cache) {this.Command = perintah; this.cache = cache; initCommand (); } private void initCommand () {if (this.command.contains ("noreply")) {noreply = true; } String [] info = command.split (""); kunci = info [1]; } @Override public void execute (pembaca pembaca, penulis penulis) {bufferedwriter bfw = (bufferedwriter) penulis; Item item = cache.delete (key); if (! noreply) {coba {if (item == null) {bfw.write ("not_found/r/n"); } else {bfw.write ("dihapus/r/n"); } bfw.flush (); } catch (ioException e) {coba {bfw.write ("error/r/n"); bfw.flush (); } catch (ioException e1) {e1.printstacktrace (); } e.printstacktrace (); }}} @Override CommandType getType () {return commandType.search; }}Kemudian, terapkan server memori. Untuk mendukung fungsi pertama-tama, LinkedTeMeMap digunakan sebagai implementasi yang mendasarinya, dan metode RemopOldest ditulis ulang. Pada saat yang sama, utas latar belakang CacheManager juga digunakan untuk menghapus entri cache yang kadaluwarsa dalam waktu.
Public Class Memcache mengimplementasikan Cache <Item> {private Logger Logger = logger.getLogger (memcache.class.getName ()); // Gunakan LinkedHashMap untuk mengimplementasikan LRU Private Static LinkedHashMap <String, Item> cache; Int Maksimal Final Pribadi; // Load Factor Private Final Float Default_Load_factor = 0.75F; memcache publik (final int maxsize) {this.maxsize = maxSize; // Pastikan cache tidak akan secara otomatis mengembang setelah MaxSize tercapai int kapasitas = (int) math.ceil (MaxSize /Default_Load_factor) + 1; this.cache = new LinkedHashMap<String, Item>(capacity, DEFAULT_LOAD_FACTOR, true){ @Override protected boolean removeEldestEntry(Map.Entry<String,Item>eldest) { if (size() > maxSize){ logger.info("The cache number has reached the upper limit, and the least recently used entry will be deleted"); } return size ()> MaxSize; }}; // mengimplementasikan koleksi akses yang disinkronkan. SynchronizedMap (Cache); } public Synchronized boolean isfull () {return cache.size ()> = maxSize; } @Override item publik get (tombol string) {item item = cache.get (key); if (item == null) {logger.info ("key in cache:" + key + "tidak ada"); kembali nol; } else if (item! = null && item.isexpired ()) {// Jika cache kedaluwarsa, hapus dan kembalikan null logger.info ("Baca kunci dari cache:" + key + "value:" + item.getValue () + "telah kedaluwarsa"); cache.remove (kunci); kembali nol; } Logger.info ("Baca Kunci dari Cache:" + Kunci + "Nilai:" + item.getValue () + "Waktu Valid yang Tersisa" + Item.Remaintime ()); item pengembalian; } @Override public void set (tombol string, nilai item) {logger.info ("Tulis Kunci ke Cache:" + Key + "Value:" + Value); cache.put (tombol, nilai); } @Override item publik hapus (tombol string) {logger.info ("Hapus tombol dari cache:" + key); return cache.remove (kunci); } @Override public int size () {return cache.size (); } @Override public int kapasitas () {return maxsize; } @Override Iterator publik <map.entry <string, item >> iterator () {return cache.entryset (). Iterator (); }} /*** Cache Manager* Latar belakang utas* Hapus cache yang sudah kadaluwarsa dalam cache*/kelas publik CacheManager mengimplementasikan runnable {private Logger Logger = logger.getLogger (cacheManager.class.getName ()); // cache public cache <TEMET> cache; Public CacheManager (cache <TEMET> 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> entri = itemIterator.next (); Item item = entry.getValue (); if (item.isexpired ()) {logger.info ("key:" + entry.getKey () + "value" + item.getValue () + "kedaluwarsa, dihapus dari database"); itemIterator.remove (); }} coba {// Jalankan program latar belakang setiap 5 detik timeunit.seconds.sleep (5); } catch (InterruptedException e) {E.PrintStackTrace (); }}}}Akhirnya, terapkan server soket multi-threaded, di mana server terikat ke antarmuka dan menyerahkan soket yang diterima ke utas tambahan untuk diproses.
/*** server*/kelas publik IOServer mengimplementasikan server {private boolean stop; // Port Number Private Final Int Port; // Server Thread Private Serversocket Serversocket; Private Final Logger Logger = Logger.GetLogger (ioServer.class.getName ()); // kumpulan utas, kapasitas utas adalah maxconnection swasta eksekutif ExecutorService ExecutorService; cache akhir privat <TEMET> cache; IOServer publik (int port, int maxConnection, cache <TEMET> cache) {if (maxConnection <= 0) melempar baru ilegalargumentException ("jumlah maksimum koneksi yang didukung harus integer positif"); this.port = port; ExecutorService = Executors.newfixedThreadPool (MaxConnection); this.cache = cache; } @Override public void start () {coba {serversocket = new Serverersocket (port); logger.info("The server starts on port"+port+"); while (true){ try { Socket socket = serverSocket.accept(); logger.info("Received a connection of "+socket.getLocalAddress()+""); executorService.submit(new SocketHandler(socket, cache)); } catch (IOException e) { E.PrintStackTrace (); ! Serversocket.isclosed (); /*** Tangani koneksi masing -masing klien* Tutup koneksi setelah mendapatkan instruksi akhir S*/kelas publik Sockethandler mengimplementasikan runnable {private static logger logger = logger.getLogger (sockethandler.class.getName ()); soket soket terakhir pribadi; cache akhir privat <TEMET> cache; finish boolean pribadi; sockethandler publik (soket S, cache <TEMET> cache) {this.socket = s; this.cache = cache; } @Override public void run () {coba {// Dapatkan Socket Input Stream Final BufferedReader Reader = BufferedReader baru (inputStreamReader baru (socket.getInputStream ())); // Dapatkan Socket Output Stream Final BufferedWriter Writer = New BufferedWriter (outputStreamWriter baru (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 ()) {lanjutan; } // Gunakan pabrik perintah untuk mendapatkan perintah perintah final instance = commandfactory.getCommand (commandline); command.execute (pembaca, penulis); if (command.getType () == commandType.end) {logger.info ("Permintaan untuk menutup koneksi"); finish = true; }}} catch (ioException e) {E.PrintStackTrace (); logger.info ("Tutup koneksi dari" + socket.getLocalAddress () + ""); } akhirnya {coba {if (socket! = null) {socket.close (); }} catch (ioException e) {E.PrintStackTrace (); }}}}Silakan klik di sini untuk alamat proyek. Jika Anda pikir itu cukup bagus, saya harap Anda bisa memberi saya bintang.
Referensi
Situs web resmi memcached
Protokol Memcache
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.