SlideShare a Scribd company logo
1 of 150
Download to read offline
那些大家常忽略的 Cache-Control
Kewang
Who I am
● 王慕羣 Kewang
● Java / PHP / Node.js / AngularJS
● HBase / SQL-like
● Git / DevOps
●
熱愛開源
GitHubGitHub kewangkewang
LinkedinLinkedin kewangtwkewangtw
SlideShareSlideShare kewangkewang
GmailGmail cpckewangcpckewang
FacebookFacebook Kewang 的資訊進化論Kewang 的資訊進化論
modernwebmodernweb '18'18
devopsday taipeidevopsday taipei '17'17
jcconfjcconf '16 '17'16 '17
hadoopconhadoopcon '14 '15'14 '15
mopconmopcon '14'14
Funliday
Funliday
Funliday
●
最棒的旅遊規劃 App
Funliday
●
最棒的旅遊規劃 App
●
輕鬆拖拉規劃完整路徑
Funliday
●
最棒的旅遊規劃 App
●
輕鬆拖拉規劃完整路徑
●
行程共同編輯
Funliday
●
最棒的旅遊規劃 App
●
輕鬆拖拉規劃完整路徑
●
行程共同編輯
●
旅遊社群
11
Agenda
12
Agenda
● HTTP Cache-Control
13
Agenda
● HTTP Cache-Control
● Guava Cache
14
Agenda
● HTTP Cache-Control
● Guava Cache
● Web Server
15
Agenda
● HTTP Cache-Control
● Guava Cache
● Web Server
● ZooKeeper
16
不會提到
17
不會提到
● In-memory database (Redis, Memcached...)
18
不會提到
● In-memory database (Redis, Memcached...)
● How to tuning JVM
19
Live DEMO
https://github.com/kewang/cache-control-boilerplate
20
HTTP Cache-Control
21
各種 Header - 1
22
各種 Header - 1
● Cache-Control
23
各種 Header - 1
● Cache-Control
– no-cache :先與 server 確認資料是否已變更,再決定
是否用 cache
24
各種 Header - 1
● Cache-Control
– no-cache :先與 server 確認資料是否已變更,再決定
是否用 cache
– no-store :完全不使用 cache
25
各種 Header - 1
● Cache-Control
– no-cache :先與 server 確認資料是否已變更,再決定
是否用 cache
– no-store :完全不使用 cache
– public :資料可以儲存在公開 cache ,如 CDN
26
各種 Header - 1
● Cache-Control
– no-cache :先與 server 確認資料是否已變更,再決定
是否用 cache
– no-store :完全不使用 cache
– public :資料可以儲存在公開 cache ,如 CDN
– private :資料僅能儲存在私有 cache ,如瀏覽器
27
各種 Header - 1
● Cache-Control
– no-cache :先與 server 確認資料是否已變更,再決定
是否用 cache
– no-store :完全不使用 cache
– public :資料可以儲存在公開 cache ,如 CDN
– private :資料僅能儲存在私有 cache ,如瀏覽器
– max-age :資料新鮮度,可使用的時間長度 ( 秒 )
28
各種 Header - 2
29
各種 Header - 2
● Last-Modified
30
各種 Header - 2
● Last-Modified
– 資料最後一次的修改時間
31
各種 Header - 2
● Last-Modified
– 資料最後一次的修改時間
– server 回傳給 client 的 response
32
各種 Header - 2
● Last-Modified
– 資料最後一次的修改時間
– server 回傳給 client 的 response
– 與 If-Modified-Since 搭配使用
33
各種 Header - 2
● Last-Modified
– 資料最後一次的修改時間
– server 回傳給 client 的 response
– 與 If-Modified-Since 搭配使用
● If-Modified-Since
34
各種 Header - 2
● Last-Modified
– 資料最後一次的修改時間
– server 回傳給 client 的 response
– 與 If-Modified-Since 搭配使用
● If-Modified-Since
– client 送給 server 詢問這個時間後是否有做修改
35
各種 Header - 2
● Last-Modified
– 資料最後一次的修改時間
– server 回傳給 client 的 response
– 與 If-Modified-Since 搭配使用
● If-Modified-Since
– client 送給 server 詢問這個時間後是否有做修改
– 如果有修改,則回傳新資料 (200) 給 client
36
各種 Header - 2
● Last-Modified
– 資料最後一次的修改時間
– server 回傳給 client 的 response
– 與 If-Modified-Since 搭配使用
● If-Modified-Since
– client 送給 server 詢問這個時間後是否有做修改
– 如果有修改,則回傳新資料 (200) 給 client
– 如果沒修改,則僅回傳沒有變更 (304) 給 client
37
各種 Header - 3
38
各種 Header - 3
● ETag
39
各種 Header - 3
● ETag
– 此次資料的 hash 值
40
各種 Header - 3
● ETag
– 此次資料的 hash 值
● inode+ 檔案大小 + 最後修改時間
41
各種 Header - 3
● ETag
– 此次資料的 hash 值
● inode+ 檔案大小 + 最後修改時間
●
檔案內容
42
各種 Header - 3
● ETag
– 此次資料的 hash 值
● inode+ 檔案大小 + 最後修改時間
●
檔案內容
●
其他方式
43
各種 Header - 3
● ETag
– 此次資料的 hash 值
● inode+ 檔案大小 + 最後修改時間
●
檔案內容
●
其他方式
– server 回傳給 client 的 response
44
各種 Header - 3
● ETag
– 此次資料的 hash 值
● inode+ 檔案大小 + 最後修改時間
●
檔案內容
●
其他方式
– server 回傳給 client 的 response
– 與 If-None-Match 搭配使用
45
各種 Header - 3
● ETag
– 此次資料的 hash 值
● inode+ 檔案大小 + 最後修改時間
●
檔案內容
●
其他方式
– server 回傳給 client 的 response
– 與 If-None-Match 搭配使用
● If-None-Match
46
各種 Header - 3
● ETag
– 此次資料的 hash 值
● inode+ 檔案大小 + 最後修改時間
●
檔案內容
●
其他方式
– server 回傳給 client 的 response
– 與 If-None-Match 搭配使用
● If-None-Match
– client 送給 server 詢問資料內容是否有做修改
47
各種 Header - 3
● ETag
– 此次資料的 hash 值
●
inode+ 檔案大小 + 最後修改時間
●
檔案內容
●
其他方式
– server 回傳給 client 的 response
– 與 If-None-Match 搭配使用
● If-None-Match
– client 送給 server 詢問資料內容是否有做修改
– 如果有修改,則回傳新資料 (200) 給 client
48
各種 Header - 3
● ETag
– 此次資料的 hash 值
●
inode+ 檔案大小 + 最後修改時間
●
檔案內容
●
其他方式
– server 回傳給 client 的 response
– 與 If-None-Match 搭配使用
● If-None-Match
– client 送給 server 詢問資料內容是否有做修改
– 如果有修改,則回傳新資料 (200) 給 client
– 如果沒修改,則僅回傳沒有變更 (304) 給 client
49
流程圖 - 1
50
流程圖 - 1
51
流程圖 - 1
52
流程圖 - 1
## 回傳給瀏覽器
* 快取有效時間為 120 秒
* 驗證值為 x234dff
53
流程圖 - 2
54
流程圖 - 2
55
流程圖 - 2
56
流程圖 - 2
## 再次跟伺服器送出請求
* 如果驗證值與 x234dff 不相符,則回傳新資料
57
流程圖 - 2
## 再次跟伺服器送出請求
* 如果驗證值與 x234dff 不相符,則回傳新資料
58
流程圖 - 2
## 回傳給瀏覽器
* 如果驗證值與 x234dff 相符,則僅回傳 304 Not Modified
## 再次跟伺服器送出請求
* 如果驗證值與 x234dff 不相符,則回傳新資料
59
Guava Cache
60
Population 1
LoadingCache<Integer, String> cache = CacheBuilder.newBuilder()
.build(new CacheLoader<Integer, String>() {
@Override
public String load(Integer integer) {
return "item" + integer;
}
});
int key = scanner.nextInt();
String value = cache.get(key);
System.out.println("cache item: " + value);
61
Population 2
Cache<Integer, String> cache = CacheBuilder.newBuilder().build();
int key = scanner.nextInt();
String value = cache.get(key, new Callable<String>() {
@Override
public String call() {
return "item" + key;
}
});
System.out.println("cache item: " + value);
62
Eviction - Size-based
63
Eviction - Size-based
● maximumSize(long)
64
Eviction - Size-based
● maximumSize(long)
● weigher(Weigher) & maximumWeight(long)
65
Eviction - Timed
66
Eviction - Timed
● expireAfterAccess(long,TimeUnit)
67
Eviction - Timed
● expireAfterAccess(long,TimeUnit)
● expireAfterWrite(long,TimeUnit)
68
Eviction - Explicit Removals
69
Eviction - Explicit Removals
● invalidate(Object)
70
Eviction - Explicit Removals
● invalidate(Object)
● invalidateAll(Iterable<?>)
71
Eviction - Explicit Removals
● invalidate(Object)
● invalidateAll(Iterable<?>)
● invalidateAll()
72
Eviction - Explicit Removals
● invalidate(Object)
● invalidateAll(Iterable<?>)
● invalidateAll()
● removalListener(RemovalListener)
73
Eviction - Others
74
Eviction - Others
● weakKeys()
75
Eviction - Others
● weakKeys()
● weakValues()
76
Eviction - Others
● weakKeys()
● weakValues()
● softValues()
77
Other features
78
Other features
● recordStats()
79
Other features
● recordStats()
● asMap()
80
Live DEMO
https://github.com/kewang/cache-control-sample
81
Web Server
82
Web Server
開始大量程式碼
83
Start Server - 1
public static void main(String[] args) {
HttpServer server = startServer();
ETagCacheManager.init();
System.out.println("Started at " + BASE_URI));
String ret = "";
Scanner scanner = new Scanner(System.in);
while (!ret.equalsIgnoreCase("stop")) {
ret = scanner.next();
}
server.stop();
}
84
Start Server - 1
public static void main(String[] args) {
HttpServer server = startServer();
ETagCacheManager.init();
System.out.println("Started at " + BASE_URI));
String ret = "";
Scanner scanner = new Scanner(System.in);
while (!ret.equalsIgnoreCase("stop")) {
ret = scanner.next();
}
server.stop();
}
85
Start Server - 1
public static void main(String[] args) {
HttpServer server = startServer();
ETagCacheManager.init();
System.out.println("Started at " + BASE_URI));
String ret = "";
Scanner scanner = new Scanner(System.in);
while (!ret.equalsIgnoreCase("stop")) {
ret = scanner.next();
}
server.stop();
}
## ZooKeeper 連線初始化
86
Start Server - 2
ResourceConfig rc = new ResourceConfig().packages("tw.kewang");
rc.register(UserInfoFilter.class);
rc.register(CacheFilterFactory.class);
return GrizzlyHttpServerFactory.createHttpServer(BASE_URI, rc);
87
Start Server - 2
ResourceConfig rc = new ResourceConfig().packages("tw.kewang");
rc.register(UserInfoFilter.class);
rc.register(CacheFilterFactory.class);
return GrizzlyHttpServerFactory.createHttpServer(BASE_URI, rc);
88
Start Server - 2
ResourceConfig rc = new ResourceConfig().packages("tw.kewang");
rc.register(UserInfoFilter.class);
rc.register(CacheFilterFactory.class);
return GrizzlyHttpServerFactory.createHttpServer(BASE_URI, rc);
## 運作 Cache-Control 機制的 filter
89
Register CacheFilterFactory - 1
MaxAge maxAge = method.annotation(MaxAge.class);
if (maxAge != null) {
register(new MaxAgeFilter(maxAge.value(), maxAge.unit()));
}
CacheControl cc = method.annotation(CacheControl.class);
if (cc != null) {
register(new ETagFilter(cc));
}
90
Register CacheFilterFactory - 1
MaxAge maxAge = method.annotation(MaxAge.class);
if (maxAge != null) {
register(new MaxAgeFilter(maxAge.value(), maxAge.unit()));
}
CacheControl cc = method.annotation(CacheControl.class);
if (cc != null) {
register(new ETagFilter(cc));
}
91
Register CacheFilterFactory - 1
MaxAge maxAge = method.annotation(MaxAge.class);
if (maxAge != null) {
register(new MaxAgeFilter(maxAge.value(), maxAge.unit()));
}
CacheControl cc = method.annotation(CacheControl.class);
if (cc != null) {
register(new ETagFilter(cc));
}
## 判斷 request ETag 的 filter
92
Register MaxAge filter - 1
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MaxAge {
long value();
TimeUnit unit() default TimeUnit.SECONDS;
}
93
Register CacheControl filter - 1
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheControl {
Class<? extends ETagCache> cacheType();
/**
* order USER_ID, HEADER, PATH_PARAMETER, QUERY_PARAMETER
*/
KeyType[] keyType();
String[] headers() default "";
String[] pathParameters() default "";
String[] queryParameters() default "";
KeyType extraType() default KeyType.UNDEFINED;
String extraValue() default "";
}
94
Register CacheControl filter - 1
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheControl {
Class<? extends ETagCache> cacheType();
/**
* order USER_ID, HEADER, PATH_PARAMETER, QUERY_PARAMETER
*/
KeyType[] keyType();
String[] headers() default "";
String[] pathParameters() default "";
String[] queryParameters() default "";
KeyType extraType() default KeyType.UNDEFINED;
String extraValue() default "";
}
95
Register CacheControl filter - 1
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheControl {
Class<? extends ETagCache> cacheType();
/**
* order USER_ID, HEADER, PATH_PARAMETER, QUERY_PARAMETER
*/
KeyType[] keyType();
String[] headers() default "";
String[] pathParameters() default "";
String[] queryParameters() default "";
KeyType extraType() default KeyType.UNDEFINED;
String extraValue() default "";
}
## 確定要用哪種 ETagCache
96
Register CacheControl filter - 1
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheControl {
Class<? extends ETagCache> cacheType();
/**
* order USER_ID, HEADER, PATH_PARAMETER, QUERY_PARAMETER
*/
KeyType[] keyType();
String[] headers() default "";
String[] pathParameters() default "";
String[] queryParameters() default "";
KeyType extraType() default KeyType.UNDEFINED;
String extraValue() default "";
}
## 確定要用哪種 ETagCache
97
Register CacheControl filter - 1
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheControl {
Class<? extends ETagCache> cacheType();
/**
* order USER_ID, HEADER, PATH_PARAMETER, QUERY_PARAMETER
*/
KeyType[] keyType();
String[] headers() default "";
String[] pathParameters() default "";
String[] queryParameters() default "";
KeyType extraType() default KeyType.UNDEFINED;
String extraValue() default "";
}
## 確定要用哪種 ETagCache
## ETag key 的組成方式
98
Register CacheControl filter - 2
Cache cache = (Cache) cacheType.newInstance().getCache();
if (cache == null) {
return;
}
ETag etagObj = retrieveETagObj(requestContext, cache);
if (etagObj == null) {
return;
}
99
Register CacheControl filter - 2
Cache cache = (Cache) cacheType.newInstance().getCache();
if (cache == null) {
return;
}
ETag etagObj = retrieveETagObj(requestContext, cache);
if (etagObj == null) {
return;
}
100
Register CacheControl filter - 2
Cache cache = (Cache) cacheType.newInstance().getCache();
if (cache == null) {
return;
}
ETag etagObj = retrieveETagObj(requestContext, cache);
if (etagObj == null) {
return;
}
## 若 cacheType 無法對應
* 回原 service 執行流程
101
Register CacheControl filter - 2
Cache cache = (Cache) cacheType.newInstance().getCache();
if (cache == null) {
return;
}
ETag etagObj = retrieveETagObj(requestContext, cache);
if (etagObj == null) {
return;
}
## 若 cacheType 無法對應
* 回原 service 執行流程
102
Register CacheControl filter - 2
Cache cache = (Cache) cacheType.newInstance().getCache();
if (cache == null) {
return;
}
ETag etagObj = retrieveETagObj(requestContext, cache);
if (etagObj == null) {
return;
}
## 若 cacheType 無法對應
* 回原 service 執行流程
## 若無法從對應 key 取回資料
* 回原 service 執行流程
103
Register CacheControl filter - 3
String etagKey = etagObj.getETagKey();
String ifNoneMatch = context.getHeaderString(IF_NONE_MATCH);
if (StringUtils.isEmpty(ifNoneMatch)) {
context.abort(ResUtils.ok(etagObj.getETagValue(), etagKey));
} else if (etagKey.equals(ifNoneMatch)) {
context.abort(ResUtils.notModified(ifNoneMatch));
}
printCacheStats(cache);
104
Register CacheControl filter - 3
String etagKey = etagObj.getETagKey();
String ifNoneMatch = context.getHeaderString(IF_NONE_MATCH);
if (StringUtils.isEmpty(ifNoneMatch)) {
context.abort(ResUtils.ok(etagObj.getETagValue(), etagKey));
} else if (etagKey.equals(ifNoneMatch)) {
context.abort(ResUtils.notModified(ifNoneMatch));
}
printCacheStats(cache);
105
Register CacheControl filter - 3
String etagKey = etagObj.getETagKey();
String ifNoneMatch = context.getHeaderString(IF_NONE_MATCH);
if (StringUtils.isEmpty(ifNoneMatch)) {
context.abort(ResUtils.ok(etagObj.getETagValue(), etagKey));
} else if (etagKey.equals(ifNoneMatch)) {
context.abort(ResUtils.notModified(ifNoneMatch));
}
printCacheStats(cache);
## 若 If-None-Match 為空
* 回傳 200 及 cache 內的資料
106
Register CacheControl filter - 3
String etagKey = etagObj.getETagKey();
String ifNoneMatch = context.getHeaderString(IF_NONE_MATCH);
if (StringUtils.isEmpty(ifNoneMatch)) {
context.abort(ResUtils.ok(etagObj.getETagValue(), etagKey));
} else if (etagKey.equals(ifNoneMatch)) {
context.abort(ResUtils.notModified(ifNoneMatch));
}
printCacheStats(cache);
## 若 If-None-Match 為空
* 回傳 200 及 cache 內的資料
107
Register CacheControl filter - 3
String etagKey = etagObj.getETagKey();
String ifNoneMatch = context.getHeaderString(IF_NONE_MATCH);
if (StringUtils.isEmpty(ifNoneMatch)) {
context.abort(ResUtils.ok(etagObj.getETagValue(), etagKey));
} else if (etagKey.equals(ifNoneMatch)) {
context.abort(ResUtils.notModified(ifNoneMatch));
}
printCacheStats(cache);
## 若 If-None-Match 為空
* 回傳 200 及 cache 內的資料 ## 若 If-None-Match 與 key 相同
* 僅回傳 304
108
Register resource - 1
@GET
@MaxAge(3)
@CacheControl(cache = GetCache.class, key = Type.USER_ID)
Response getArticles(HttpHeaders httpHeaders, int size) {
GetArticleRequest request = new GetArticleRequest();
request.size = size;
GetArticleService service = new GetArticleService();
GetArticleResponse response = service.execute(request);
return ResponseUtils.ok(response);
}
109
Register resource - 1
@GET
@MaxAge(3)
@CacheControl(cache = GetCache.class, key = Type.USER_ID)
Response getArticles(HttpHeaders httpHeaders, int size) {
GetArticleRequest request = new GetArticleRequest();
request.size = size;
GetArticleService service = new GetArticleService();
GetArticleResponse response = service.execute(request);
return ResponseUtils.ok(response);
}
110
Register resource - 1
@GET
@MaxAge(3)
@CacheControl(cache = GetCache.class, key = Type.USER_ID)
Response getArticles(HttpHeaders httpHeaders, int size) {
GetArticleRequest request = new GetArticleRequest();
request.size = size;
GetArticleService service = new GetArticleService();
GetArticleResponse response = service.execute(request);
return ResponseUtils.ok(response);
}
## GET /articles 的 filter
* response => max-age: 3
* request => 註冊正確的 cache 及 key 的產生方式
111
Register resource - 2
public static Response ok(BasicResponse response) {
String json = response.toJson();
ResponseBuilder builder = Response.ok(json);
ETagCache etagCache = response.getETagCache();
if (etagCache != null) {
return builder.tag(etagCache.toHash()).build();
} else {
return builder.build();
}
}
112
Register resource - 2
public static Response ok(BasicResponse response) {
String json = response.toJson();
ResponseBuilder builder = Response.ok(json);
ETagCache etagCache = response.getETagCache();
if (etagCache != null) {
return builder.tag(etagCache.toHash()).build();
} else {
return builder.build();
}
}
113
Register resource - 2
public static Response ok(BasicResponse response) {
String json = response.toJson();
ResponseBuilder builder = Response.ok(json);
ETagCache etagCache = response.getETagCache();
if (etagCache != null) {
return builder.tag(etagCache.toHash()).build();
} else {
return builder.build();
}
}
## 在 response 加上 ETag 後回傳至 client
114
Implement service - 1
public class GetArticleService
extends Service<GetRequest, GetResponse>
implements Cacheable<GetCache> {
}
115
Implement service - 1
public class GetArticleService
extends Service<GetRequest, GetResponse>
implements Cacheable<GetCache> {
}
116
Implement service - 1
public class GetArticleService
extends Service<GetRequest, GetResponse>
implements Cacheable<GetCache> {
}
## 執行 service 時確認可以被 cache
117
Implement service - 2
@Override
public BasicResponse processing(GetRequest request) {
GetResponse response = retrieveFromDatabase(request);
setCacheKey(UserInfoHolder.getUserInfo().userId);
setCacheValue(response.toJson());
return response;
}
118
Implement service - 2
@Override
public BasicResponse processing(GetRequest request) {
GetResponse response = retrieveFromDatabase(request);
setCacheKey(UserInfoHolder.getUserInfo().userId);
setCacheValue(response.toJson());
return response;
}
119
Implement service - 2
@Override
public BasicResponse processing(GetRequest request) {
GetResponse response = retrieveFromDatabase(request);
setCacheKey(UserInfoHolder.getUserInfo().userId);
setCacheValue(response.toJson());
return response;
}
## 儲存到 cache 的方式
* cacheKey :常用各種 ID 儲存,必須與 @CacheControl 對應
* cacheValue :常用 response 儲存
120
ZooKeeper
121
ZooKeeper server architecture
122
ZooKeeper server architecture
123
znode data architecture
124
znode data architecture
125
Features
126
Features
●
最終一致性
127
Features
●
最終一致性
●
可靠性
128
Features
●
最終一致性
●
可靠性
●
即時性
129
Scenarios
130
Scenarios
●
設定檔管理
131
Scenarios
●
設定檔管理
● Dynamic DNS
132
Scenarios
●
設定檔管理
● Dynamic DNS
● Message Queue
133
Scenarios
●
設定檔管理
● Dynamic DNS
● Message Queue
● Heartbeat detection
134
Scenarios
●
設定檔管理
● Dynamic DNS
● Message Queue
● Heartbeat detection
● Master election
135
用途
136
用途
將所有 web 的 cache 都 invalidate
137
1. Init
138
1. Init
/
ns
caches
invalidation
139
1. Init
/
ns
caches
invalidation
140
1. Init
/
ns
caches
invalidation
## ETagCacheManager.init()
* 監聽 /caches/invalidation 是否產生變化
141
2. Invalidate
142
2. Invalidate
/
ns
caches
invalidation
/d6ba5233-ea17-4fbb-a331-9fefb230fd78/caches/GetArticlesETagCache/kewang
143
2. Invalidate
/
ns
caches
invalidation
/d6ba5233-ea17-4fbb-a331-9fefb230fd78/caches/GetArticlesETagCache/kewang
144
2. Invalidate
/
ns
caches
invalidation
/d6ba5233-ea17-4fbb-a331-9fefb230fd78/caches/GetArticlesETagCache/kewang
## 當 cache 要 invalidate 時
* 新增 znode ,並寫入資料
145
3. Notify node
146
3. Notify node
/
ns
caches
invalidation
/d6..78/caches/GetArticlesETagCache/kewang GetArticlesETagCache
kewang
147
3. Notify node
/
ns
caches
invalidation
/d6..78/caches/GetArticlesETagCache/kewang GetArticlesETagCache
kewang
148
3. Notify node
/
ns
caches
invalidation
/d6..78/caches/GetArticlesETagCache/kewang GetArticlesETagCache
kewang
## 使用 Leader Election 機制
* 選出 leader , leader 將 cache invalidate
* leader 退出此次 election ,讓給其他 follower
149
References
● HTTP caching (MDN)
●
HTTP 快取 (Google Web Fundamentals)
●
循序漸進理解 HTTP Cache 機制
●
從Paxos到Zookeeper分散式一致性原理與實例
150

More Related Content

What's hot

Yet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom upYet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom upWen-Tien Chang
 
你畢業後要任職的軟體業到底都在做些什麼事
你畢業後要任職的軟體業到底都在做些什麼事你畢業後要任職的軟體業到底都在做些什麼事
你畢業後要任職的軟體業到底都在做些什麼事Mu Chun Wang
 
Monitor is all for ops
Monitor is all for opsMonitor is all for ops
Monitor is all for ops琛琳 饶
 
淺談 Groovy 與 Gradle
淺談 Groovy 與 Gradle淺談 Groovy 與 Gradle
淺談 Groovy 與 GradleJustin Lin
 
[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南Shengyou Fan
 
JCConf2015: groovy to gradle
 JCConf2015: groovy to gradle JCConf2015: groovy to gradle
JCConf2015: groovy to gradleChing Yi Chan
 
DNS协议与应用简介
DNS协议与应用简介DNS协议与应用简介
DNS协议与应用简介琛琳 饶
 
高性能Web服务器nginx及相关新技术的应用
高性能Web服务器nginx及相关新技术的应用高性能Web服务器nginx及相关新技术的应用
高性能Web服务器nginx及相关新技术的应用redhat9
 
Continuous Delivery with Ansible x GitLab CI
Continuous Delivery with Ansible x GitLab CIContinuous Delivery with Ansible x GitLab CI
Continuous Delivery with Ansible x GitLab CIChu-Siang Lai
 
独爽不如众乐
独爽不如众乐独爽不如众乐
独爽不如众乐Zheng Biao
 
Http Headers 與 Cache 機制(2016)
Http Headers 與 Cache 機制(2016)Http Headers 與 Cache 機制(2016)
Http Headers 與 Cache 機制(2016)振揚 陳
 
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)Continuous Delivery Workshop with Ansible x GitLab CI (2nd)
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)Chu-Siang Lai
 
高性能Web服务器Nginx及相关新技术的应用实践
高性能Web服务器Nginx及相关新技术的应用实践高性能Web服务器Nginx及相关新技术的应用实践
高性能Web服务器Nginx及相关新技术的应用实践rewinx
 
Continuous Delivery Workshop with Ansible x GitLab CI
Continuous Delivery Workshop with Ansible x GitLab CIContinuous Delivery Workshop with Ansible x GitLab CI
Continuous Delivery Workshop with Ansible x GitLab CIChu-Siang Lai
 
twMVC#26 | 淺談 ASP.NET Caching 技術與實踐
twMVC#26 | 淺談 ASP.NET Caching 技術與實踐twMVC#26 | 淺談 ASP.NET Caching 技術與實踐
twMVC#26 | 淺談 ASP.NET Caching 技術與實踐twMVC
 
Docker 基礎介紹與實戰
Docker 基礎介紹與實戰Docker 基礎介紹與實戰
Docker 基礎介紹與實戰Bo-Yi Wu
 
從軟體開發角度
談 Docker 的應用
從軟體開發角度
談 Docker 的應用從軟體開發角度
談 Docker 的應用
從軟體開發角度
談 Docker 的應用謝 宗穎
 
Golang 高性能实战
Golang 高性能实战Golang 高性能实战
Golang 高性能实战rfyiamcool
 

What's hot (19)

Yet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom upYet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom up
 
你畢業後要任職的軟體業到底都在做些什麼事
你畢業後要任職的軟體業到底都在做些什麼事你畢業後要任職的軟體業到底都在做些什麼事
你畢業後要任職的軟體業到底都在做些什麼事
 
Monitor is all for ops
Monitor is all for opsMonitor is all for ops
Monitor is all for ops
 
淺談 Groovy 與 Gradle
淺談 Groovy 與 Gradle淺談 Groovy 與 Gradle
淺談 Groovy 與 Gradle
 
[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南
 
JCConf2015: groovy to gradle
 JCConf2015: groovy to gradle JCConf2015: groovy to gradle
JCConf2015: groovy to gradle
 
DNS协议与应用简介
DNS协议与应用简介DNS协议与应用简介
DNS协议与应用简介
 
Git 經驗分享
Git 經驗分享Git 經驗分享
Git 經驗分享
 
高性能Web服务器nginx及相关新技术的应用
高性能Web服务器nginx及相关新技术的应用高性能Web服务器nginx及相关新技术的应用
高性能Web服务器nginx及相关新技术的应用
 
Continuous Delivery with Ansible x GitLab CI
Continuous Delivery with Ansible x GitLab CIContinuous Delivery with Ansible x GitLab CI
Continuous Delivery with Ansible x GitLab CI
 
独爽不如众乐
独爽不如众乐独爽不如众乐
独爽不如众乐
 
Http Headers 與 Cache 機制(2016)
Http Headers 與 Cache 機制(2016)Http Headers 與 Cache 機制(2016)
Http Headers 與 Cache 機制(2016)
 
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)Continuous Delivery Workshop with Ansible x GitLab CI (2nd)
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)
 
高性能Web服务器Nginx及相关新技术的应用实践
高性能Web服务器Nginx及相关新技术的应用实践高性能Web服务器Nginx及相关新技术的应用实践
高性能Web服务器Nginx及相关新技术的应用实践
 
Continuous Delivery Workshop with Ansible x GitLab CI
Continuous Delivery Workshop with Ansible x GitLab CIContinuous Delivery Workshop with Ansible x GitLab CI
Continuous Delivery Workshop with Ansible x GitLab CI
 
twMVC#26 | 淺談 ASP.NET Caching 技術與實踐
twMVC#26 | 淺談 ASP.NET Caching 技術與實踐twMVC#26 | 淺談 ASP.NET Caching 技術與實踐
twMVC#26 | 淺談 ASP.NET Caching 技術與實踐
 
Docker 基礎介紹與實戰
Docker 基礎介紹與實戰Docker 基礎介紹與實戰
Docker 基礎介紹與實戰
 
從軟體開發角度
談 Docker 的應用
從軟體開發角度
談 Docker 的應用從軟體開發角度
談 Docker 的應用
從軟體開發角度
談 Docker 的應用
 
Golang 高性能实战
Golang 高性能实战Golang 高性能实战
Golang 高性能实战
 

Similar to 那些大家常忽略的 Cache-Control

如何在有限資源下實現十年的後端服務演進
如何在有限資源下實現十年的後端服務演進如何在有限資源下實現十年的後端服務演進
如何在有限資源下實現十年的後端服務演進Mu Chun Wang
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)jeffz
 
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUGYingSiang Geng
 
Varnish简介
Varnish简介Varnish简介
Varnish简介fangdeng
 
Puppet安装总结
Puppet安装总结Puppet安装总结
Puppet安装总结Yiwei Ma
 
Performance Monitoring With AOP
Performance Monitoring With AOPPerformance Monitoring With AOP
Performance Monitoring With AOPivannotes
 
分享平台构建之旅
分享平台构建之旅分享平台构建之旅
分享平台构建之旅tblanlan
 
twMVC#19 | opserver監控服務的解決
twMVC#19 | opserver監控服務的解決twMVC#19 | opserver監控服務的解決
twMVC#19 | opserver監控服務的解決twMVC
 
Node cluster
Node clusterNode cluster
Node clusteraleafs
 
gRPC - 打造輕量、高效能的後端服務
gRPC - 打造輕量、高效能的後端服務gRPC - 打造輕量、高效能的後端服務
gRPC - 打造輕量、高效能的後端服務升煌 黃
 
纵览Loadrunner核心功能
纵览Loadrunner核心功能纵览Loadrunner核心功能
纵览Loadrunner核心功能beiyu95
 
Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)FLASH开发者交流会
 
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)Shanda innovation institute
 
twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧twMVC
 
Web Caching Architecture and Design
Web Caching Architecture and DesignWeb Caching Architecture and Design
Web Caching Architecture and DesignHo Kim
 
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代scott liao
 
深入淺出 autocomplete
深入淺出 autocomplete深入淺出 autocomplete
深入淺出 autocompleteMu Chun Wang
 
Ops as Code using Serverless
Ops as Code using Serverless Ops as Code using Serverless
Ops as Code using Serverless Rick Hwang
 
使用Nginx轻松实现开源负载均衡
使用Nginx轻松实现开源负载均衡使用Nginx轻松实现开源负载均衡
使用Nginx轻松实现开源负载均衡cachowu
 

Similar to 那些大家常忽略的 Cache-Control (20)

如何在有限資源下實現十年的後端服務演進
如何在有限資源下實現十年的後端服務演進如何在有限資源下實現十年的後端服務演進
如何在有限資源下實現十年的後端服務演進
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)
 
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
 
Varnish简介
Varnish简介Varnish简介
Varnish简介
 
Puppet安装总结
Puppet安装总结Puppet安装总结
Puppet安装总结
 
Performance Monitoring With AOP
Performance Monitoring With AOPPerformance Monitoring With AOP
Performance Monitoring With AOP
 
分享平台构建之旅
分享平台构建之旅分享平台构建之旅
分享平台构建之旅
 
twMVC#19 | opserver監控服務的解決
twMVC#19 | opserver監控服務的解決twMVC#19 | opserver監控服務的解決
twMVC#19 | opserver監控服務的解決
 
Node cluster
Node clusterNode cluster
Node cluster
 
gRPC - 打造輕量、高效能的後端服務
gRPC - 打造輕量、高效能的後端服務gRPC - 打造輕量、高效能的後端服務
gRPC - 打造輕量、高效能的後端服務
 
纵览Loadrunner核心功能
纵览Loadrunner核心功能纵览Loadrunner核心功能
纵览Loadrunner核心功能
 
Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)
 
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
 
twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧
 
Web Caching Architecture and Design
Web Caching Architecture and DesignWeb Caching Architecture and Design
Web Caching Architecture and Design
 
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
 
深入淺出 autocomplete
深入淺出 autocomplete深入淺出 autocomplete
深入淺出 autocomplete
 
Ops as Code using Serverless
Ops as Code using Serverless Ops as Code using Serverless
Ops as Code using Serverless
 
-Nginx book
 -Nginx book -Nginx book
-Nginx book
 
使用Nginx轻松实现开源负载均衡
使用Nginx轻松实现开源负载均衡使用Nginx轻松实现开源负载均衡
使用Nginx轻松实现开源负载均衡
 

More from Mu Chun Wang

大解密!用 PostgreSQL 提升 350 倍的 Funliday 推薦景點計算速度
大解密!用 PostgreSQL 提升 350 倍的 Funliday 推薦景點計算速度大解密!用 PostgreSQL 提升 350 倍的 Funliday 推薦景點計算速度
大解密!用 PostgreSQL 提升 350 倍的 Funliday 推薦景點計算速度Mu Chun Wang
 
如何使用 iframe 製作一個易於更新及更安全的前端套件
如何使用 iframe 製作一個易於更新及更安全的前端套件如何使用 iframe 製作一個易於更新及更安全的前端套件
如何使用 iframe 製作一個易於更新及更安全的前端套件Mu Chun Wang
 
pppr - 解決 JavaScript 無法被搜尋引擎正確索引的問題
pppr - 解決 JavaScript 無法被搜尋引擎正確索引的問題pppr - 解決 JavaScript 無法被搜尋引擎正確索引的問題
pppr - 解決 JavaScript 無法被搜尋引擎正確索引的問題Mu Chun Wang
 
Git 可以做到的事
Git 可以做到的事Git 可以做到的事
Git 可以做到的事Mu Chun Wang
 
如何與 Git 優雅地在樹上唱歌
如何與 Git 優雅地在樹上唱歌如何與 Git 優雅地在樹上唱歌
如何與 Git 優雅地在樹上唱歌Mu Chun Wang
 
API Blueprint - API 文件規範的三大領頭之一
API Blueprint - API 文件規範的三大領頭之一API Blueprint - API 文件規範的三大領頭之一
API Blueprint - API 文件規範的三大領頭之一Mu Chun Wang
 
團體共同協作與版本管理 - 01認識共同協作
團體共同協作與版本管理 - 01認識共同協作團體共同協作與版本管理 - 01認識共同協作
團體共同協作與版本管理 - 01認識共同協作Mu Chun Wang
 
手把手教你如何串接 Log 到各種網路服務
手把手教你如何串接 Log 到各種網路服務手把手教你如何串接 Log 到各種網路服務
手把手教你如何串接 Log 到各種網路服務Mu Chun Wang
 
你有想過畢業九年後的你會變什麼樣子嗎?
你有想過畢業九年後的你會變什麼樣子嗎?你有想過畢業九年後的你會變什麼樣子嗎?
你有想過畢業九年後的你會變什麼樣子嗎?Mu Chun Wang
 
HR Search - 輕鬆管理面試者
HR Search - 輕鬆管理面試者HR Search - 輕鬆管理面試者
HR Search - 輕鬆管理面試者Mu Chun Wang
 
Hedis - GET HBase via Redis
Hedis - GET HBase via RedisHedis - GET HBase via Redis
Hedis - GET HBase via RedisMu Chun Wang
 
104學年度行動裝置程式設計課程說明
104學年度行動裝置程式設計課程說明104學年度行動裝置程式設計課程說明
104學年度行動裝置程式設計課程說明Mu Chun Wang
 
Webduino introduction
Webduino introductionWebduino introduction
Webduino introductionMu Chun Wang
 
Firebase introduction
Firebase introductionFirebase introduction
Firebase introductionMu Chun Wang
 
How to build a scalable SNS via Polling & Push
How to build a scalable SNS via Polling & PushHow to build a scalable SNS via Polling & Push
How to build a scalable SNS via Polling & PushMu Chun Wang
 
How to build a scalable SNS using HBase
How to build a scalable SNS using HBaseHow to build a scalable SNS using HBase
How to build a scalable SNS using HBaseMu Chun Wang
 

More from Mu Chun Wang (18)

大解密!用 PostgreSQL 提升 350 倍的 Funliday 推薦景點計算速度
大解密!用 PostgreSQL 提升 350 倍的 Funliday 推薦景點計算速度大解密!用 PostgreSQL 提升 350 倍的 Funliday 推薦景點計算速度
大解密!用 PostgreSQL 提升 350 倍的 Funliday 推薦景點計算速度
 
如何使用 iframe 製作一個易於更新及更安全的前端套件
如何使用 iframe 製作一個易於更新及更安全的前端套件如何使用 iframe 製作一個易於更新及更安全的前端套件
如何使用 iframe 製作一個易於更新及更安全的前端套件
 
pppr - 解決 JavaScript 無法被搜尋引擎正確索引的問題
pppr - 解決 JavaScript 無法被搜尋引擎正確索引的問題pppr - 解決 JavaScript 無法被搜尋引擎正確索引的問題
pppr - 解決 JavaScript 無法被搜尋引擎正確索引的問題
 
Git 可以做到的事
Git 可以做到的事Git 可以做到的事
Git 可以做到的事
 
如何與 Git 優雅地在樹上唱歌
如何與 Git 優雅地在樹上唱歌如何與 Git 優雅地在樹上唱歌
如何與 Git 優雅地在樹上唱歌
 
API Blueprint - API 文件規範的三大領頭之一
API Blueprint - API 文件規範的三大領頭之一API Blueprint - API 文件規範的三大領頭之一
API Blueprint - API 文件規範的三大領頭之一
 
團體共同協作與版本管理 - 01認識共同協作
團體共同協作與版本管理 - 01認識共同協作團體共同協作與版本管理 - 01認識共同協作
團體共同協作與版本管理 - 01認識共同協作
 
手把手教你如何串接 Log 到各種網路服務
手把手教你如何串接 Log 到各種網路服務手把手教你如何串接 Log 到各種網路服務
手把手教你如何串接 Log 到各種網路服務
 
你有想過畢業九年後的你會變什麼樣子嗎?
你有想過畢業九年後的你會變什麼樣子嗎?你有想過畢業九年後的你會變什麼樣子嗎?
你有想過畢業九年後的你會變什麼樣子嗎?
 
HR Search - 輕鬆管理面試者
HR Search - 輕鬆管理面試者HR Search - 輕鬆管理面試者
HR Search - 輕鬆管理面試者
 
Hedis - GET HBase via Redis
Hedis - GET HBase via RedisHedis - GET HBase via Redis
Hedis - GET HBase via Redis
 
104學年度行動裝置程式設計課程說明
104學年度行動裝置程式設計課程說明104學年度行動裝置程式設計課程說明
104學年度行動裝置程式設計課程說明
 
Webduino introduction
Webduino introductionWebduino introduction
Webduino introduction
 
Lightning Hedis
Lightning HedisLightning Hedis
Lightning Hedis
 
職涯之路
職涯之路職涯之路
職涯之路
 
Firebase introduction
Firebase introductionFirebase introduction
Firebase introduction
 
How to build a scalable SNS via Polling & Push
How to build a scalable SNS via Polling & PushHow to build a scalable SNS via Polling & Push
How to build a scalable SNS via Polling & Push
 
How to build a scalable SNS using HBase
How to build a scalable SNS using HBaseHow to build a scalable SNS using HBase
How to build a scalable SNS using HBase
 

那些大家常忽略的 Cache-Control

  • 2. Who I am ● 王慕羣 Kewang ● Java / PHP / Node.js / AngularJS ● HBase / SQL-like ● Git / DevOps ● 熱愛開源 GitHubGitHub kewangkewang LinkedinLinkedin kewangtwkewangtw SlideShareSlideShare kewangkewang GmailGmail cpckewangcpckewang FacebookFacebook Kewang 的資訊進化論Kewang 的資訊進化論 modernwebmodernweb '18'18 devopsday taipeidevopsday taipei '17'17 jcconfjcconf '16 '17'16 '17 hadoopconhadoopcon '14 '15'14 '15 mopconmopcon '14'14
  • 3.
  • 4.
  • 14. 14 Agenda ● HTTP Cache-Control ● Guava Cache ● Web Server
  • 15. 15 Agenda ● HTTP Cache-Control ● Guava Cache ● Web Server ● ZooKeeper
  • 17. 17 不會提到 ● In-memory database (Redis, Memcached...)
  • 18. 18 不會提到 ● In-memory database (Redis, Memcached...) ● How to tuning JVM
  • 22. 22 各種 Header - 1 ● Cache-Control
  • 23. 23 各種 Header - 1 ● Cache-Control – no-cache :先與 server 確認資料是否已變更,再決定 是否用 cache
  • 24. 24 各種 Header - 1 ● Cache-Control – no-cache :先與 server 確認資料是否已變更,再決定 是否用 cache – no-store :完全不使用 cache
  • 25. 25 各種 Header - 1 ● Cache-Control – no-cache :先與 server 確認資料是否已變更,再決定 是否用 cache – no-store :完全不使用 cache – public :資料可以儲存在公開 cache ,如 CDN
  • 26. 26 各種 Header - 1 ● Cache-Control – no-cache :先與 server 確認資料是否已變更,再決定 是否用 cache – no-store :完全不使用 cache – public :資料可以儲存在公開 cache ,如 CDN – private :資料僅能儲存在私有 cache ,如瀏覽器
  • 27. 27 各種 Header - 1 ● Cache-Control – no-cache :先與 server 確認資料是否已變更,再決定 是否用 cache – no-store :完全不使用 cache – public :資料可以儲存在公開 cache ,如 CDN – private :資料僅能儲存在私有 cache ,如瀏覽器 – max-age :資料新鮮度,可使用的時間長度 ( 秒 )
  • 29. 29 各種 Header - 2 ● Last-Modified
  • 30. 30 各種 Header - 2 ● Last-Modified – 資料最後一次的修改時間
  • 31. 31 各種 Header - 2 ● Last-Modified – 資料最後一次的修改時間 – server 回傳給 client 的 response
  • 32. 32 各種 Header - 2 ● Last-Modified – 資料最後一次的修改時間 – server 回傳給 client 的 response – 與 If-Modified-Since 搭配使用
  • 33. 33 各種 Header - 2 ● Last-Modified – 資料最後一次的修改時間 – server 回傳給 client 的 response – 與 If-Modified-Since 搭配使用 ● If-Modified-Since
  • 34. 34 各種 Header - 2 ● Last-Modified – 資料最後一次的修改時間 – server 回傳給 client 的 response – 與 If-Modified-Since 搭配使用 ● If-Modified-Since – client 送給 server 詢問這個時間後是否有做修改
  • 35. 35 各種 Header - 2 ● Last-Modified – 資料最後一次的修改時間 – server 回傳給 client 的 response – 與 If-Modified-Since 搭配使用 ● If-Modified-Since – client 送給 server 詢問這個時間後是否有做修改 – 如果有修改,則回傳新資料 (200) 給 client
  • 36. 36 各種 Header - 2 ● Last-Modified – 資料最後一次的修改時間 – server 回傳給 client 的 response – 與 If-Modified-Since 搭配使用 ● If-Modified-Since – client 送給 server 詢問這個時間後是否有做修改 – 如果有修改,則回傳新資料 (200) 給 client – 如果沒修改,則僅回傳沒有變更 (304) 給 client
  • 38. 38 各種 Header - 3 ● ETag
  • 39. 39 各種 Header - 3 ● ETag – 此次資料的 hash 值
  • 40. 40 各種 Header - 3 ● ETag – 此次資料的 hash 值 ● inode+ 檔案大小 + 最後修改時間
  • 41. 41 各種 Header - 3 ● ETag – 此次資料的 hash 值 ● inode+ 檔案大小 + 最後修改時間 ● 檔案內容
  • 42. 42 各種 Header - 3 ● ETag – 此次資料的 hash 值 ● inode+ 檔案大小 + 最後修改時間 ● 檔案內容 ● 其他方式
  • 43. 43 各種 Header - 3 ● ETag – 此次資料的 hash 值 ● inode+ 檔案大小 + 最後修改時間 ● 檔案內容 ● 其他方式 – server 回傳給 client 的 response
  • 44. 44 各種 Header - 3 ● ETag – 此次資料的 hash 值 ● inode+ 檔案大小 + 最後修改時間 ● 檔案內容 ● 其他方式 – server 回傳給 client 的 response – 與 If-None-Match 搭配使用
  • 45. 45 各種 Header - 3 ● ETag – 此次資料的 hash 值 ● inode+ 檔案大小 + 最後修改時間 ● 檔案內容 ● 其他方式 – server 回傳給 client 的 response – 與 If-None-Match 搭配使用 ● If-None-Match
  • 46. 46 各種 Header - 3 ● ETag – 此次資料的 hash 值 ● inode+ 檔案大小 + 最後修改時間 ● 檔案內容 ● 其他方式 – server 回傳給 client 的 response – 與 If-None-Match 搭配使用 ● If-None-Match – client 送給 server 詢問資料內容是否有做修改
  • 47. 47 各種 Header - 3 ● ETag – 此次資料的 hash 值 ● inode+ 檔案大小 + 最後修改時間 ● 檔案內容 ● 其他方式 – server 回傳給 client 的 response – 與 If-None-Match 搭配使用 ● If-None-Match – client 送給 server 詢問資料內容是否有做修改 – 如果有修改,則回傳新資料 (200) 給 client
  • 48. 48 各種 Header - 3 ● ETag – 此次資料的 hash 值 ● inode+ 檔案大小 + 最後修改時間 ● 檔案內容 ● 其他方式 – server 回傳給 client 的 response – 與 If-None-Match 搭配使用 ● If-None-Match – client 送給 server 詢問資料內容是否有做修改 – 如果有修改,則回傳新資料 (200) 給 client – 如果沒修改,則僅回傳沒有變更 (304) 給 client
  • 52. 52 流程圖 - 1 ## 回傳給瀏覽器 * 快取有效時間為 120 秒 * 驗證值為 x234dff
  • 56. 56 流程圖 - 2 ## 再次跟伺服器送出請求 * 如果驗證值與 x234dff 不相符,則回傳新資料
  • 57. 57 流程圖 - 2 ## 再次跟伺服器送出請求 * 如果驗證值與 x234dff 不相符,則回傳新資料
  • 58. 58 流程圖 - 2 ## 回傳給瀏覽器 * 如果驗證值與 x234dff 相符,則僅回傳 304 Not Modified ## 再次跟伺服器送出請求 * 如果驗證值與 x234dff 不相符,則回傳新資料
  • 60. 60 Population 1 LoadingCache<Integer, String> cache = CacheBuilder.newBuilder() .build(new CacheLoader<Integer, String>() { @Override public String load(Integer integer) { return "item" + integer; } }); int key = scanner.nextInt(); String value = cache.get(key); System.out.println("cache item: " + value);
  • 61. 61 Population 2 Cache<Integer, String> cache = CacheBuilder.newBuilder().build(); int key = scanner.nextInt(); String value = cache.get(key, new Callable<String>() { @Override public String call() { return "item" + key; } }); System.out.println("cache item: " + value);
  • 63. 63 Eviction - Size-based ● maximumSize(long)
  • 64. 64 Eviction - Size-based ● maximumSize(long) ● weigher(Weigher) & maximumWeight(long)
  • 66. 66 Eviction - Timed ● expireAfterAccess(long,TimeUnit)
  • 67. 67 Eviction - Timed ● expireAfterAccess(long,TimeUnit) ● expireAfterWrite(long,TimeUnit)
  • 69. 69 Eviction - Explicit Removals ● invalidate(Object)
  • 70. 70 Eviction - Explicit Removals ● invalidate(Object) ● invalidateAll(Iterable<?>)
  • 71. 71 Eviction - Explicit Removals ● invalidate(Object) ● invalidateAll(Iterable<?>) ● invalidateAll()
  • 72. 72 Eviction - Explicit Removals ● invalidate(Object) ● invalidateAll(Iterable<?>) ● invalidateAll() ● removalListener(RemovalListener)
  • 75. 75 Eviction - Others ● weakKeys() ● weakValues()
  • 76. 76 Eviction - Others ● weakKeys() ● weakValues() ● softValues()
  • 83. 83 Start Server - 1 public static void main(String[] args) { HttpServer server = startServer(); ETagCacheManager.init(); System.out.println("Started at " + BASE_URI)); String ret = ""; Scanner scanner = new Scanner(System.in); while (!ret.equalsIgnoreCase("stop")) { ret = scanner.next(); } server.stop(); }
  • 84. 84 Start Server - 1 public static void main(String[] args) { HttpServer server = startServer(); ETagCacheManager.init(); System.out.println("Started at " + BASE_URI)); String ret = ""; Scanner scanner = new Scanner(System.in); while (!ret.equalsIgnoreCase("stop")) { ret = scanner.next(); } server.stop(); }
  • 85. 85 Start Server - 1 public static void main(String[] args) { HttpServer server = startServer(); ETagCacheManager.init(); System.out.println("Started at " + BASE_URI)); String ret = ""; Scanner scanner = new Scanner(System.in); while (!ret.equalsIgnoreCase("stop")) { ret = scanner.next(); } server.stop(); } ## ZooKeeper 連線初始化
  • 86. 86 Start Server - 2 ResourceConfig rc = new ResourceConfig().packages("tw.kewang"); rc.register(UserInfoFilter.class); rc.register(CacheFilterFactory.class); return GrizzlyHttpServerFactory.createHttpServer(BASE_URI, rc);
  • 87. 87 Start Server - 2 ResourceConfig rc = new ResourceConfig().packages("tw.kewang"); rc.register(UserInfoFilter.class); rc.register(CacheFilterFactory.class); return GrizzlyHttpServerFactory.createHttpServer(BASE_URI, rc);
  • 88. 88 Start Server - 2 ResourceConfig rc = new ResourceConfig().packages("tw.kewang"); rc.register(UserInfoFilter.class); rc.register(CacheFilterFactory.class); return GrizzlyHttpServerFactory.createHttpServer(BASE_URI, rc); ## 運作 Cache-Control 機制的 filter
  • 89. 89 Register CacheFilterFactory - 1 MaxAge maxAge = method.annotation(MaxAge.class); if (maxAge != null) { register(new MaxAgeFilter(maxAge.value(), maxAge.unit())); } CacheControl cc = method.annotation(CacheControl.class); if (cc != null) { register(new ETagFilter(cc)); }
  • 90. 90 Register CacheFilterFactory - 1 MaxAge maxAge = method.annotation(MaxAge.class); if (maxAge != null) { register(new MaxAgeFilter(maxAge.value(), maxAge.unit())); } CacheControl cc = method.annotation(CacheControl.class); if (cc != null) { register(new ETagFilter(cc)); }
  • 91. 91 Register CacheFilterFactory - 1 MaxAge maxAge = method.annotation(MaxAge.class); if (maxAge != null) { register(new MaxAgeFilter(maxAge.value(), maxAge.unit())); } CacheControl cc = method.annotation(CacheControl.class); if (cc != null) { register(new ETagFilter(cc)); } ## 判斷 request ETag 的 filter
  • 92. 92 Register MaxAge filter - 1 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MaxAge { long value(); TimeUnit unit() default TimeUnit.SECONDS; }
  • 93. 93 Register CacheControl filter - 1 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CacheControl { Class<? extends ETagCache> cacheType(); /** * order USER_ID, HEADER, PATH_PARAMETER, QUERY_PARAMETER */ KeyType[] keyType(); String[] headers() default ""; String[] pathParameters() default ""; String[] queryParameters() default ""; KeyType extraType() default KeyType.UNDEFINED; String extraValue() default ""; }
  • 94. 94 Register CacheControl filter - 1 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CacheControl { Class<? extends ETagCache> cacheType(); /** * order USER_ID, HEADER, PATH_PARAMETER, QUERY_PARAMETER */ KeyType[] keyType(); String[] headers() default ""; String[] pathParameters() default ""; String[] queryParameters() default ""; KeyType extraType() default KeyType.UNDEFINED; String extraValue() default ""; }
  • 95. 95 Register CacheControl filter - 1 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CacheControl { Class<? extends ETagCache> cacheType(); /** * order USER_ID, HEADER, PATH_PARAMETER, QUERY_PARAMETER */ KeyType[] keyType(); String[] headers() default ""; String[] pathParameters() default ""; String[] queryParameters() default ""; KeyType extraType() default KeyType.UNDEFINED; String extraValue() default ""; } ## 確定要用哪種 ETagCache
  • 96. 96 Register CacheControl filter - 1 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CacheControl { Class<? extends ETagCache> cacheType(); /** * order USER_ID, HEADER, PATH_PARAMETER, QUERY_PARAMETER */ KeyType[] keyType(); String[] headers() default ""; String[] pathParameters() default ""; String[] queryParameters() default ""; KeyType extraType() default KeyType.UNDEFINED; String extraValue() default ""; } ## 確定要用哪種 ETagCache
  • 97. 97 Register CacheControl filter - 1 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CacheControl { Class<? extends ETagCache> cacheType(); /** * order USER_ID, HEADER, PATH_PARAMETER, QUERY_PARAMETER */ KeyType[] keyType(); String[] headers() default ""; String[] pathParameters() default ""; String[] queryParameters() default ""; KeyType extraType() default KeyType.UNDEFINED; String extraValue() default ""; } ## 確定要用哪種 ETagCache ## ETag key 的組成方式
  • 98. 98 Register CacheControl filter - 2 Cache cache = (Cache) cacheType.newInstance().getCache(); if (cache == null) { return; } ETag etagObj = retrieveETagObj(requestContext, cache); if (etagObj == null) { return; }
  • 99. 99 Register CacheControl filter - 2 Cache cache = (Cache) cacheType.newInstance().getCache(); if (cache == null) { return; } ETag etagObj = retrieveETagObj(requestContext, cache); if (etagObj == null) { return; }
  • 100. 100 Register CacheControl filter - 2 Cache cache = (Cache) cacheType.newInstance().getCache(); if (cache == null) { return; } ETag etagObj = retrieveETagObj(requestContext, cache); if (etagObj == null) { return; } ## 若 cacheType 無法對應 * 回原 service 執行流程
  • 101. 101 Register CacheControl filter - 2 Cache cache = (Cache) cacheType.newInstance().getCache(); if (cache == null) { return; } ETag etagObj = retrieveETagObj(requestContext, cache); if (etagObj == null) { return; } ## 若 cacheType 無法對應 * 回原 service 執行流程
  • 102. 102 Register CacheControl filter - 2 Cache cache = (Cache) cacheType.newInstance().getCache(); if (cache == null) { return; } ETag etagObj = retrieveETagObj(requestContext, cache); if (etagObj == null) { return; } ## 若 cacheType 無法對應 * 回原 service 執行流程 ## 若無法從對應 key 取回資料 * 回原 service 執行流程
  • 103. 103 Register CacheControl filter - 3 String etagKey = etagObj.getETagKey(); String ifNoneMatch = context.getHeaderString(IF_NONE_MATCH); if (StringUtils.isEmpty(ifNoneMatch)) { context.abort(ResUtils.ok(etagObj.getETagValue(), etagKey)); } else if (etagKey.equals(ifNoneMatch)) { context.abort(ResUtils.notModified(ifNoneMatch)); } printCacheStats(cache);
  • 104. 104 Register CacheControl filter - 3 String etagKey = etagObj.getETagKey(); String ifNoneMatch = context.getHeaderString(IF_NONE_MATCH); if (StringUtils.isEmpty(ifNoneMatch)) { context.abort(ResUtils.ok(etagObj.getETagValue(), etagKey)); } else if (etagKey.equals(ifNoneMatch)) { context.abort(ResUtils.notModified(ifNoneMatch)); } printCacheStats(cache);
  • 105. 105 Register CacheControl filter - 3 String etagKey = etagObj.getETagKey(); String ifNoneMatch = context.getHeaderString(IF_NONE_MATCH); if (StringUtils.isEmpty(ifNoneMatch)) { context.abort(ResUtils.ok(etagObj.getETagValue(), etagKey)); } else if (etagKey.equals(ifNoneMatch)) { context.abort(ResUtils.notModified(ifNoneMatch)); } printCacheStats(cache); ## 若 If-None-Match 為空 * 回傳 200 及 cache 內的資料
  • 106. 106 Register CacheControl filter - 3 String etagKey = etagObj.getETagKey(); String ifNoneMatch = context.getHeaderString(IF_NONE_MATCH); if (StringUtils.isEmpty(ifNoneMatch)) { context.abort(ResUtils.ok(etagObj.getETagValue(), etagKey)); } else if (etagKey.equals(ifNoneMatch)) { context.abort(ResUtils.notModified(ifNoneMatch)); } printCacheStats(cache); ## 若 If-None-Match 為空 * 回傳 200 及 cache 內的資料
  • 107. 107 Register CacheControl filter - 3 String etagKey = etagObj.getETagKey(); String ifNoneMatch = context.getHeaderString(IF_NONE_MATCH); if (StringUtils.isEmpty(ifNoneMatch)) { context.abort(ResUtils.ok(etagObj.getETagValue(), etagKey)); } else if (etagKey.equals(ifNoneMatch)) { context.abort(ResUtils.notModified(ifNoneMatch)); } printCacheStats(cache); ## 若 If-None-Match 為空 * 回傳 200 及 cache 內的資料 ## 若 If-None-Match 與 key 相同 * 僅回傳 304
  • 108. 108 Register resource - 1 @GET @MaxAge(3) @CacheControl(cache = GetCache.class, key = Type.USER_ID) Response getArticles(HttpHeaders httpHeaders, int size) { GetArticleRequest request = new GetArticleRequest(); request.size = size; GetArticleService service = new GetArticleService(); GetArticleResponse response = service.execute(request); return ResponseUtils.ok(response); }
  • 109. 109 Register resource - 1 @GET @MaxAge(3) @CacheControl(cache = GetCache.class, key = Type.USER_ID) Response getArticles(HttpHeaders httpHeaders, int size) { GetArticleRequest request = new GetArticleRequest(); request.size = size; GetArticleService service = new GetArticleService(); GetArticleResponse response = service.execute(request); return ResponseUtils.ok(response); }
  • 110. 110 Register resource - 1 @GET @MaxAge(3) @CacheControl(cache = GetCache.class, key = Type.USER_ID) Response getArticles(HttpHeaders httpHeaders, int size) { GetArticleRequest request = new GetArticleRequest(); request.size = size; GetArticleService service = new GetArticleService(); GetArticleResponse response = service.execute(request); return ResponseUtils.ok(response); } ## GET /articles 的 filter * response => max-age: 3 * request => 註冊正確的 cache 及 key 的產生方式
  • 111. 111 Register resource - 2 public static Response ok(BasicResponse response) { String json = response.toJson(); ResponseBuilder builder = Response.ok(json); ETagCache etagCache = response.getETagCache(); if (etagCache != null) { return builder.tag(etagCache.toHash()).build(); } else { return builder.build(); } }
  • 112. 112 Register resource - 2 public static Response ok(BasicResponse response) { String json = response.toJson(); ResponseBuilder builder = Response.ok(json); ETagCache etagCache = response.getETagCache(); if (etagCache != null) { return builder.tag(etagCache.toHash()).build(); } else { return builder.build(); } }
  • 113. 113 Register resource - 2 public static Response ok(BasicResponse response) { String json = response.toJson(); ResponseBuilder builder = Response.ok(json); ETagCache etagCache = response.getETagCache(); if (etagCache != null) { return builder.tag(etagCache.toHash()).build(); } else { return builder.build(); } } ## 在 response 加上 ETag 後回傳至 client
  • 114. 114 Implement service - 1 public class GetArticleService extends Service<GetRequest, GetResponse> implements Cacheable<GetCache> { }
  • 115. 115 Implement service - 1 public class GetArticleService extends Service<GetRequest, GetResponse> implements Cacheable<GetCache> { }
  • 116. 116 Implement service - 1 public class GetArticleService extends Service<GetRequest, GetResponse> implements Cacheable<GetCache> { } ## 執行 service 時確認可以被 cache
  • 117. 117 Implement service - 2 @Override public BasicResponse processing(GetRequest request) { GetResponse response = retrieveFromDatabase(request); setCacheKey(UserInfoHolder.getUserInfo().userId); setCacheValue(response.toJson()); return response; }
  • 118. 118 Implement service - 2 @Override public BasicResponse processing(GetRequest request) { GetResponse response = retrieveFromDatabase(request); setCacheKey(UserInfoHolder.getUserInfo().userId); setCacheValue(response.toJson()); return response; }
  • 119. 119 Implement service - 2 @Override public BasicResponse processing(GetRequest request) { GetResponse response = retrieveFromDatabase(request); setCacheKey(UserInfoHolder.getUserInfo().userId); setCacheValue(response.toJson()); return response; } ## 儲存到 cache 的方式 * cacheKey :常用各種 ID 儲存,必須與 @CacheControl 對應 * cacheValue :常用 response 儲存
  • 133. 133 Scenarios ● 設定檔管理 ● Dynamic DNS ● Message Queue ● Heartbeat detection
  • 134. 134 Scenarios ● 設定檔管理 ● Dynamic DNS ● Message Queue ● Heartbeat detection ● Master election
  • 136. 136 用途 將所有 web 的 cache 都 invalidate
  • 140. 140 1. Init / ns caches invalidation ## ETagCacheManager.init() * 監聽 /caches/invalidation 是否產生變化
  • 148. 148 3. Notify node / ns caches invalidation /d6..78/caches/GetArticlesETagCache/kewang GetArticlesETagCache kewang ## 使用 Leader Election 機制 * 選出 leader , leader 將 cache invalidate * leader 退出此次 election ,讓給其他 follower
  • 149. 149 References ● HTTP caching (MDN) ● HTTP 快取 (Google Web Fundamentals) ● 循序漸進理解 HTTP Cache 機制 ● 從Paxos到Zookeeper分散式一致性原理與實例
  • 150. 150