這裡分類和彙總了欣宸的全部原創(含配套原始碼):https://github.com/zq2599/blog_demos
所以,單機版nginx如果遇到多個worker的資料同步問題,可以考慮共用記憶體方案,這也是咱們今天實戰的主要內容:在使用nginx-clojure進行java開發時,用共用記憶體在多個worker之間同步資料
本文由以下內容組成:
package com.bolingcavalry.sharedmap;
import nginx.clojure.java.ArrayMap;
import nginx.clojure.java.NginxJavaRingHandler;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import static nginx.clojure.MiniConstants.CONTENT_TYPE;
import static nginx.clojure.MiniConstants.NGX_HTTP_OK;
public class HeapSaveCounter implements NginxJavaRingHandler {
/**
* 通過UUID來表明當前jvm程序的身份
*/
private String tag = UUID.randomUUID().toString();
private int requestCount = 1;
@Override
public Object[] invoke(Map<String, Object> map) throws IOException {
String body = "From "
+ tag
+ ", total request count [ "
+ requestCount++
+ "]";
return new Object[] {
NGX_HTTP_OK, //http status 200
ArrayMap.create(CONTENT_TYPE, "text/plain"), //headers map
body
};
}
}
worker_processes auto;
location /heapbasedcounter {
content_handler_type 'java';
content_handler_name 'com.bolingcavalry.sharedmap.HeapSaveCounter';
}
(base) willdeMBP:~ will$ jps
4944
4945
4946
4947
4948
4949
4950
4968 Jps
4943
先用Safari瀏覽器存取/heapbasedcounter,第一次收到的響應如下圖,總數是1:
重新整理頁面,UUID不變,總數變成2,這意味著兩次請求到了同一個worker的JVM上:
改用Chrome瀏覽器,存取同樣的地址,如下圖,這次UUID變了,證明請求是另一個worker的jvm處理的,總數變成了1:
至此,問題得到證明:多個worker的時候,用jvm的類的成員變數儲存的計數只是各worker的情況,不是整個nginx的總數
接下來看如何用共用記憶體解決此類問題
特性 | Tiny Map | Hash Map |
---|---|---|
鍵數量 | 2^31=2.14Billions | 64位元系統:2^63 32位元系統:2^31 |
使用記憶體上限 | 64位元系統:4G 32位元系統:2G |
受限於作業系統 |
單個鍵的大小 | 16M | 受限於作業系統 |
單個值的大小 | 64位元系統:4G 32位元系統:2G |
受限於作業系統 |
entry物件自身所用記憶體 | 24 byte | 64位元系統:40 byte 32位元系統:28 byte |
# 增加一個共用記憶體的初始化分配,型別tiny,空間1M,鍵數量8K
shared_map uri_access_counters tinymap?space=1m&entries=8096;
package com.bolingcavalry.sharedmap;
import nginx.clojure.java.ArrayMap;
import nginx.clojure.java.NginxJavaRingHandler;
import nginx.clojure.util.NginxSharedHashMap;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import static nginx.clojure.MiniConstants.CONTENT_TYPE;
import static nginx.clojure.MiniConstants.NGX_HTTP_OK;
public class SharedMapSaveCounter implements NginxJavaRingHandler {
/**
* 通過UUID來表明當前jvm程序的身份
*/
private String tag = UUID.randomUUID().toString();
private NginxSharedHashMap smap = NginxSharedHashMap.build("uri_access_counters");
@Override
public Object[] invoke(Map<String, Object> map) throws IOException {
String uri = (String)map.get("uri");
// 嘗試在共用記憶體中新建key,並將其值初始化為1,
// 如果初始化成功,返回值就是0,
// 如果返回值不是0,表示共用記憶體中該key已經存在
int rlt = smap.putIntIfAbsent(uri, 1);
// 如果rlt不等於0,表示這個key在呼叫putIntIfAbsent之前已經在共用記憶體中存在了,
// 此時要做的就是加一,
// 如果relt等於0,就把rlt改成1,表示存取總數已經等於1了
if (0==rlt) {
rlt++;
} else {
// 原子性加一,這樣並行的時候也會順序執行
rlt = smap.atomicAddInt(uri, 1);
rlt++;
}
// 返回的body內容,要體現出JVM的身份,以及share map中的計數
String body = "From "
+ tag
+ ", total request count [ "
+ rlt
+ "]";
return new Object[] {
NGX_HTTP_OK, //http status 200
ArrayMap.create(CONTENT_TYPE, "text/plain"), //headers map
body
};
}
}
location /sharedmapbasedcounter {
content_handler_type 'java';
content_handler_name 'com.bolingcavalry.sharedmap.SharedMapSaveCounter';
}
名稱 | 連結 | 備註 |
---|---|---|
專案主頁 | https://github.com/zq2599/blog_demos | 該專案在GitHub上的主頁 |
git倉庫地址(https) | https://github.com/zq2599/blog_demos.git | 該專案原始碼的倉庫地址,https協定 |
git倉庫地址(ssh) | [email protected]:zq2599/blog_demos.git | 該專案原始碼的倉庫地址,ssh協定 |