Heim >Backend-Entwicklung >PHP-Tutorial >Die Verwendung von Cache in der Programmierung
Caching ist eine der häufigsten Methoden zur Optimierung der Systemleistung. Durch das Hinzufügen von Cache vor zeitaufwändigen Komponenten (z. B. Datenbanken) können Sie die Anzahl der tatsächlichen Aufrufe reduzieren und die Antwortzeit verkürzen. Denken Sie jedoch zweimal darüber nach, bevor Sie Caching einführen.
Die Beschaffung von Ressourcen über das Internet ist langsam und kostspielig. Zu diesem Zweck enthält das HTTP-Protokoll einen Cache-Steuerungsteil, sodass der HTTP-Client zuvor erhaltene Ressourcen zwischenspeichern und wiederverwenden kann, wodurch die Leistung optimiert und das Erlebnis verbessert wird. Allerdings hat der Cache-Steuerungsteil von HTTP im Zuge der Protokollentwicklung einige Änderungen erfahren. Ich bin jedoch der Meinung, dass Sie als Back-End-Programmierer bei der Entwicklung von Webdiensten nur auf den Anforderungsheader If-None-Match, den Antwortheader ETag und den Antwortheader Cache-Control achten müssen. Weil diese drei HTTP-Header Ihre Anforderungen erfüllen können und die meisten heutigen Browser diese drei HTTP-Header unterstützen. Wir müssen lediglich sicherstellen, dass jede Serverantwort die richtigen HTTP-Header-Anweisungen bereitstellt, um dem Browser mitzuteilen, wann und wie lange die Antwort zwischengespeichert werden kann.
Wo ist der Cache?
In der obigen Abbildung gibt es drei Rollen: Browser, Web-Proxy und Server. Wie in der Abbildung gezeigt, ist im Browser und im Web-Proxy ein HTTP-Cache vorhanden. Natürlich gibt es auch verschiedene Caches innerhalb des Servers, aber dies ist nicht mehr der HTTP-Cache, der in diesem Artikel behandelt wird. Die sogenannte HTTP-Cache-Steuerung ist eine Vereinbarung zur Steuerung der Cache-Nutzungsrichtlinien von Browsern und Web-Proxys durch Festlegen verschiedener Antwortheader Cache-Control und zur Steuerung des Caches durch Festlegen des Anforderungsheaders If-None-Match und des Antwortheaders ETag . Überprüfen Sie die Wirksamkeit.
Antwortheader ETag
Der vollständige Name von ETag ist Entity Tag, das zur Identifizierung einer Ressource verwendet wird. In der konkreten Implementierung kann das ETag der Hashwert der Ressource oder eine intern gepflegte Versionsnummer sein. Aber egal was passiert, ETag sollte in der Lage sein, Änderungen im Ressourceninhalt widerzuspiegeln, was die Grundlage dafür ist, dass das HTTP-Caching ordnungsgemäß funktioniert.
Wie im obigen Beispiel gezeigt, enthält der Server, wenn er eine Antwort zurückgibt, normalerweise einige Metadateninformationen über die Antwort im HTTP-Header, zu denen auch ETag gehört In diesem Beispiel wird das ETag mit dem Wert x1323ddx zurückgegeben. Wenn sich der Inhalt der Ressource/Datei ändert, sollte der Server ein anderes ETag zurückgeben.
Anforderungsheader If-None-Match
Für dieselbe Ressource, z. B. /file im vorherigen Beispiel, verfügt der Browser nach dem Senden einer Anforderung bereits über eine Version des /file-Inhalts und Wenn der Benutzer diese Ressource das nächste Mal benötigt und der Browser den Server erneut anfordert, kann der Anforderungsheader If-None-Match verwendet werden, um dem Server mitzuteilen, dass er bereits über ein /file mit einem ETag von x1323ddx verfügt , wenn /file auf dem Server sich nicht geändert hat, das heißt, wenn das ETag von /file auf dem Server auch x1323ddx ist, gibt der Server nicht den Inhalt von /file zurück, sondern eine 304-Antwort, die dem Browser mitteilt dass sich die Ressource nicht geändert hat, ist der Cache gültig.
Wie im obigen Beispiel gezeigt, benötigt der Server nach der Verwendung von If-None-Match nur eine kleine Antwort, um das gleiche Ergebnis zu erzielen, wodurch die Leistung optimiert wird.
Cache-Control des Antwortheaders
Jede Ressource kann ihre eigene Caching-Strategie definieren, indem der HTTP-Header Cache-Control steuert, wer die Antwort unter welchen Bedingungen wie lange zwischenspeichern kann. Die schnellsten Anfragen sind diejenigen, die nicht mit dem Server kommunizieren müssen: Mit einer lokalen Kopie der Antwort vermeiden wir jegliche Netzwerklatenz und die Datenkosten der Datenübertragung. Zu diesem Zweck ermöglicht die HTTP-Spezifikation dem Server, eine Reihe verschiedener Cache-Control-Anweisungen zurückzugeben, die steuern, wie und für wie lange der Browser oder ein anderer Relay-Cache eine Antwort zwischenspeichert.
Der Cache-Control-Header ist in der HTTP/1.1-Spezifikation definiert und ersetzt Header, die zuvor zum Definieren von Antwort-Caching-Richtlinien (z. B. Expires) verwendet wurden. Alle aktuellen Browser unterstützen Cache-Control, es reicht also aus, es zu verwenden.
Hier stelle ich die allgemeinen Anweisungen vor, die in Cache-Control festgelegt werden können.
max-age
Diese Direktive gibt die maximale Zeit (in Sekunden) an, die die erhaltene Antwort ab der aktuellen Anfrage wiederverwendet werden darf. Beispiel: Cache-Control:max-age =60 bedeutet, dass die Antwort für weitere 60 Sekunden zwischengespeichert und wiederverwendet werden kann. Es ist zu beachten, dass der Browser innerhalb der durch max-age angegebenen Zeit keine Anfragen an den Server sendet, einschließlich Anfragen zur Überprüfung, ob der Cache gültig ist. Das heißt, wenn sich innerhalb dieses Zeitraums die Ressourcen auf dem Server ändern, wird der Browser nicht benachrichtigt und verwendet die alte Version der Ressourcen. Daher müssen Sie beim Festlegen der Länge der Cache-Zeit vorsichtig sein.
Öffentlich und privat
Wenn „öffentlich“ festgelegt ist, bedeutet dies, dass die Antwort im Browser oder einem beliebigen weitergeleiteten Web-Proxy zwischengespeichert werden kann. Der Standardwert ist „Cache-Control“. :max-age=60 entspricht Cache-Control:public, max -age=60
Wenn der Server auf privat eingestellt ist, wie z. B. Cache-Control: privat, max-age=60, bedeutet dies dass nur der Browser des Benutzers private Antworten zwischenspeichern kann und kein Relay-Web-Proxy zulässig ist. Beispielsweise kann der Browser eines Benutzers eine HTML-Seite zwischenspeichern, die die privaten Informationen des Benutzers enthält, ein CDN kann sie jedoch nicht zwischenspeichern, wenn der Server keine Zwischenspeicherung vornimmt. Cache in der Antwort. Das heißt, Cache-Control: no-cache, dann muss der Browser zunächst mit dem Server bestätigen, ob die zurückgegebene Antwort geändert wurde, bevor die zwischengespeicherte Ressource verwendet wird, um das Herunterladen zu vermeiden Die vorherige Antwort wird durch den oben eingeführten Anforderungsheader If-None-match und den Antwortheader ETag erreicht. Es ist zu beachten, dass der Name „no-cache“ etwas irreführend ist Nach dem Festlegen von „No-Cache“ speichert der Browser die Daten nicht mehr im Cache, aber wenn er die zwischengespeicherten Daten verwendet, muss er zunächst bestätigen, ob die Daten noch mit dem Server übereinstimmen, wenn „No-Cache“ eingestellt ist und die ETag-Implementierung nicht angezeigt wird Wenn sich die Ressource ändert, wird dies dazu führen, dass die zwischengespeicherten Daten des Browsers nie aktualisiert werden -store, in der Antwort, dann der Browser Der Server und alle weitergeleiteten Web-Proxys speichern die entsprechenden Daten dieses Mal nicht. Wenn die Ressource das nächste Mal angefordert wird, kann der Browser den Server nur erneut anfordern und die Ressource erneut vom Server lesen .
Wie kann man eine Ressource ermitteln?
Das folgende Flussdiagramm kann Ihnen helfen.
Häufige Fehler
Caching beim StartManchmal werden wir feststellen, dass die Anwendung sehr langsam startet, Es stellte sich schließlich heraus, dass die Antwort eines der abhängigen Dienste lange dauerte. Was soll ich tun?Wenn ein solches Problem auftritt, bedeutet dies im Allgemeinen, dass der abhängige Dienst die Nachfrage nicht erfüllen kann. Wenn es sich um einen Drittanbieterdienst handelt und die Kontrolle nicht in unseren Händen liegt, können wir zu diesem Zeitpunkt Caching einführen.
Das Problem bei der Einführung von Caching besteht derzeit darin, dass die Cache-Invalidierungsstrategie nur schwer wirksam werden kann, da die ursprüngliche Absicht des Cache-Designs darin besteht, so wenige abhängige Dienste wie möglich anzufordern. Vorzeitiges Caching
Das hier erwähnte „frühe“ bezieht sich nicht auf den Lebenszyklus der Anwendung, sondern auf den Entwicklungszyklus. Manchmal stellen wir fest, dass einige Entwickler bereits in frühen Entwicklungsstadien Systemengpässe eingeschätzt und Caching eingeführt haben.
Tatsächlich verschleiert dieser Ansatz mögliche Leistungsoptimierungspunkte. Wie auch immer, der Rückgabewert dieses Dienstes wird bis dahin zwischengespeichert. Warum sollte ich Zeit damit verbringen, diesen Teil des Codes zu optimieren?
Integriertes Caching
Das „S“ im SOLID-Prinzip steht für – Single-Responsibility-Prinzip. Wenn die Anwendung das Cache-Modul integriert, sind das Cache-Modul und die Serviceschicht stark gekoppelt und können ohne die Beteiligung des Cache-Moduls nicht unabhängig voneinander ausgeführt werden.
Alle Inhalte zwischenspeichern
Um die Antwortverzögerung zu reduzieren, können Sie manchmal blind das Caching zu externen Anrufen hinzufügen. Tatsächlich kann ein solches Verhalten Entwickler und Betreuer leicht daran hindern, die Existenz des Cache-Moduls zu erkennen und letztendlich die Zuverlässigkeit der zugrunde liegenden abhängigen Module falsch einzuschätzen.
Kaskadierender Cache
Das Zwischenspeichern des gesamten Inhalts oder nur des größten Teils des Inhalts kann dazu führen, dass zwischengespeicherte Daten andere zwischengespeicherte Daten enthalten.
Wenn die Anwendung eine solche kaskadierende Cache-Struktur enthält, kann es dazu kommen, dass die Cache-Ablaufzeit nicht kontrollierbar ist. Der Cache der obersten Ebene muss warten, bis jede Cache-Ebene ungültig gemacht und aktualisiert wurde, bevor die endgültigen zurückgegebenen Daten vollständig aktualisiert werden.
Der Cache kann nicht aktualisiert werden
Normalerweise stellt die Cache-Middleware ein Tool zum Aktualisieren des Caches bereit. Mit Redis können Betreuer beispielsweise einige Daten löschen oder sogar den gesamten Cache über die bereitgestellten Tools aktualisieren.
Einige temporäre Caches enthalten solche Tools jedoch möglicherweise nicht. Beispielsweise erlauben Caches, die lediglich Daten innerhalb des Inhalts speichern, normalerweise nicht, dass externe Tools den zwischengespeicherten Inhalt ändern oder löschen. Wenn zu diesem Zeitpunkt abnormale Cache-Daten gefunden werden, kann das Wartungspersonal den Dienst nur neu starten, was die Betriebs- und Wartungskosten sowie die Reaktionszeit erheblich erhöht. Darüber hinaus schreiben einige Caches möglicherweise Cache-Inhalte zur Sicherung in das Dateisystem. Zu diesem Zeitpunkt müssen Sie zusätzlich zum Neustart des Dienstes auch sicherstellen, dass die Cache-Sicherung im Dateisystem gelöscht wird, bevor die Anwendung gestartet wird.
Die Auswirkungen von Caching
Die oben genannten häufigen Fehler, die aus der Einführung von Caching resultieren können, werden in einem System ohne Cache nicht berücksichtigt.
Die Bereitstellung eines Systems, das stark auf den Cache angewiesen ist, kann viel Zeit in Anspruch nehmen, bis der Cache abläuft. Wenn Sie beispielsweise Inhalte über ein CDN zwischenspeichern, kann es nach der Freigabe des Systems mehrere Stunden dauern, bis die CDN-Konfiguration und die vom CDN zwischengespeicherten Inhalte aktualisiert sind.
Darüber hinaus führt die Priorisierung des Caches bei Leistungsengpässen dazu, dass Leistungsprobleme vertuscht und nicht wirklich gelöst werden. Tatsächlich unterscheidet sich die Zeit, die für die Optimierung des Codes aufgewendet wird, oft nicht wesentlich von der Einführung von Caching-Komponenten.
Schließlich steigen bei Systemen, die Caching-Komponenten enthalten, die Kosten für das Debuggen erheblich. Es kommt häufig vor, dass der Code einen halben Tag lang verfolgt wird und die resultierenden Daten aus dem Cache stammen und nichts mit den Komponenten zu tun haben, von denen die eigentliche Logik abhängen sollte. Das gleiche Problem kann auch auftreten, nachdem alle relevanten Testfälle ausgeführt wurden, der geänderte Code jedoch nicht tatsächlich getestet wurde.
Wie nutzt man den Cache sinnvoll?
Caching verwerfen!
Nun, oft ist Caching unvermeidlich. In internetbasierten Systemen ist es schwierig, die Verwendung von Cache vollständig zu vermeiden. Sogar der HTTP-Protokoll-Header enthält die Cache-Konfiguration: Cache-Control: max-age=xxx.
Verstehen Sie die Daten
Wenn Sie Daten zwischenspeichern möchten, müssen Sie zunächst die Datenaktualisierungsstrategie verstehen. Nur wenn wir genau verstehen, wann die Daten aktualisiert werden müssen, können wir den If-Modified-Since-Header verwenden, um zu bestimmen, ob die vom Client angeforderten Daten aktualisiert werden müssen. Sollten wir einfach eine 304 Not Modified-Antwort zurückgeben und den Client wiederverwenden lassen? frühere lokal zwischengespeicherte Daten, oder sollten wir die neuesten Daten zurückgeben? Um den Cache im http-Protokoll besser nutzen zu können, wird außerdem empfohlen, Versionen der Daten zu unterscheiden oder eTag zum Markieren der Version der zwischengespeicherten Daten zu verwenden.
Leistung optimieren statt Caching verwenden
Wie bereits erwähnt, verschleiert die Verwendung von Caching häufig potenzielle Leistungsprobleme. Verwenden Sie nach Möglichkeit Leistungsanalysetools, um die wahre Ursache für die langsame Reaktion Ihrer Anwendung zu finden und zu beheben. Reduzieren Sie beispielsweise ungültige Codeaufrufe, optimieren Sie SQL gemäß dem SQL-Ausführungsplan usw.
Unten finden Sie den Code zum Löschen aller Caches der Anwendung
/* * 文 件 名: DataCleanManager.java * 描 述: 主要功能有清除内/外缓存,清除数据库,清除sharedPreference,清除files和清除自定义目录 */ package com.test.DataClean; import java.io.File; import android.content.Context; import android.os.Environment; /** * 本应用数据清除管理器 */ public class DataCleanManager { /** * 清除本应用内部缓存(/data/data/com.xxx.xxx/cache) * * @param context */ public static void cleanInternalCache(Context context) { deleteFilesByDirectory(context.getCacheDir()); } /** * 清除本应用所有数据库(/data/data/com.xxx.xxx/databases) * * @param context */ public static void cleanDatabases(Context context) { deleteFilesByDirectory(new File("/data/data/" + context.getPackageName() + "/databases")); } /** * 清除本应用SharedPreference(/data/data/com.xxx.xxx/shared_prefs) * * @param context */ public static void cleanSharedPreference(Context context) { deleteFilesByDirectory(new File("/data/data/" + context.getPackageName() + "/shared_prefs")); } /** * 按名字清除本应用数据库 * * @param context * @param dbName */ public static void cleanDatabaseByName(Context context, String dbName) { context.deleteDatabase(dbName); } /** * 清除/data/data/com.xxx.xxx/files下的内容 * * @param context */ public static void cleanFiles(Context context) { deleteFilesByDirectory(context.getFilesDir()); } /** * 清除外部cache下的内容(/mnt/sdcard/android/data/com.xxx.xxx/cache) * * @param context */ public static void cleanExternalCache(Context context) { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { deleteFilesByDirectory(context.getExternalCacheDir()); } } /** * 清除自定义路径下的文件,使用需小心,请不要误删。而且只支持目录下的文件删除 * * @param filePath */ public static void cleanCustomCache(String filePath) { deleteFilesByDirectory(new File(filePath)); } /** * 清除本应用所有的数据 * * @param context * @param filepath */ public static void cleanApplicationData(Context context, String... filepath) { cleanInternalCache(context); cleanExternalCache(context); cleanDatabases(context); cleanSharedPreference(context); cleanFiles(context); for (String filePath : filepath) { cleanCustomCache(filePath); } } /** * 删除方法 这里只会删除某个文件夹下的文件,如果传入的directory是个文件,将不做处理 * * @param directory */ private static void deleteFilesByDirectory(File directory) { if (directory != null && directory.exists() && directory.isDirectory()) { for (File item : directory.listFiles()) { item.delete(); } } } }
Zusammenfassung
Caching ist ein sehr nützliches Tool, das jedoch leicht missbraucht werden kann. Setzen Sie Caching erst in letzter Minute ein und priorisieren Sie andere Möglichkeiten zur Optimierung der Anwendungsleistung.