数据内存格式
参数:in-memory-format,有3种。
- BINARY
默认,数据k-v均二进制。
适合绝大多数put、get等操作,效率最高。 - OBJECT
数据存储为对象反序列化,适合对象复杂查询操作,避免反序列时间消耗。
k为二进制,v为对象。 - NATIVE
企业版,二进制格式,存储在非堆空间,避免GC。元数据策略
参数:Metadata Policy
自动预处理数据类型,以快速进行数据查询。
仅支持json类型,开启时,对json对象添加额外属性。
不影响其他类型的吞吐量。
如果json类型不需要复杂查询,可以关闭,默认开启。
1
2
3<map name="map-a">
<metadata-policy>OFF</metadata-policy>
</map>
数据更新
- MapStore,持久化接口,将数据持久化。
- MapLoader,数据加载接口。可以进行启动时的缓存初始化,采用多线程。
- 实现接口不应使用hz的例如map各种操作,应使用持久化的方法,否则陷入死循环。
持久化策略
支持3种策略,Read-Through、Write-Through和Write-Behind。
读时
如不存在从数据库读,同时写入缓存写时
写入缓存时,即时写入持久化,设置write-delay-seconds=0
触发条件:写入、更新(修改、删除)、backup-count大于0- 写后
写入缓存延迟时间后再写入持久化
write-delay-seconds大于0
异步执行,仅保存最后更新结果
可以设置MapStoreConfig.setWriteCoalescingto为FALSE存储所有更新。
超出负载抛出异常,停止异步存储。
删除方法
- delete删除缓存
- remove删除存储
- evict删除缓存和存储
持久化实现
1 | <map name="default"> |
class-name:MapLoader或MapStore的实现类
InitialLoadMode
MapLoader.loadAllKeys接口,预加载数据。
getMap()时提供InitialLoadMode模式,LAZY和EAGER。
LAZY,map创建时不加载所有,仅加载所触达的分区数据。
EAGER,map创建时所有分区全部加载。
1 | <map name="default"> |
Optimistic Locking乐观锁
使用1
map.replace( key, oldValue, newValue )
near-cache本地cache
- 在client端进行本地缓存,减少网络开销,提高性能
- 同时支持member上的修改和删除等操作导致的脏数据同步过期。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52<near-cache>
<time-to-live-seconds>0</time-to-live-seconds>
<max-idle-seconds>60</max-idle-seconds>
<invalidate-on-change>true</invalidate-on-change>
<in-memory-format>BINARY</in-memory-format>
<cache-local-entries>false</cache-local-entries>
<eviction size="1000" max-size-policy="ENTRY_COUNT" eviction-policy="LFU"/>
</near-cache>
```
- 适合本地大量读业务,例如client端
- 不适合大量修改业务,否则开销更大
- Near Cache不支持强一致性
- member上开启时,将增大内存消耗
- client或server均支持,各自也均需要配置
- client hits时和server hits无关,此时server上空闲时间不受影响
- client的name必须和member上一致,也可以用匹配符
- 仅对get操作生效
### 一个机器一个member
多节点在一个机器上性能不如一个节点一个机器,因为可能有大量的上下文切换。
### I/O线程
Hazelcast采用多线程的线程池进行IO操作。
每个member拆分3中线程类型:
- 接收请求
- 读取数据,从member或client
- 写数据,到member或client
`hazelcast.io.thread.count`配置每个member线程数默认是3.
默认3个线程数情况下,总计是7个io线程,1个接收数据,3个读,3个写。每个io线程有自己的Selector和waits。
### Back Pressure背压
解决负载和操作导致的OOM问题
- 设置并发操作数
- 设置定期异步备份
### Flake ID Generator
在member上的操作总是本地的。
在client上操作newId(),在指定的时间,会在本地随机一个member和获取批量的ids。
批量数和有效期在每个client及member均可指定。
配置
```xml
<flake-id-generator name="default">
<prefetch-count>100</prefetch-count>
<prefetch-validity-millis>600000</prefetch-validity-millis>
</flake-id-generator>
全局序列化
client端代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27public class GlobalStreamSerializer implements StreamSerializer<Object> {
public void write(ObjectDataOutput out, Object oo) throws IOException {
out.writeUTF(oo.getClass().getName());
out.writeByteArray(new ObjectMapper().writeValueAsBytes(oo));
}
public Object read(ObjectDataInput in) throws IOException {
String clazz = in.readUTF();
try {
return new ObjectMapper().readValue(in.readByteArray(), Class.forName(clazz));
} catch (ClassNotFoundException e) {
throw ExceptionUtil.peel(e);
}
}
public int getTypeId() {
return 1;
}
public void destroy() {
}
}
1 | <user-code-deployment enabled="true"> |