这里分类和汇总了欣宸的全部原创(含配套源码):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) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh协议 |