Cassandra Java堆外内存排查经历全记录

时间:2019-08-22
本文章向大家介绍Cassandra Java堆外内存排查经历全记录,主要包括Cassandra Java堆外内存排查经历全记录使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

背景

最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测。压测时候比较容易触发OOM Killer,把cassandra进程干掉。问题是8G这个规格我配置的heap(Xmx)并不高(约6.5g)已经留出了足够的空间给系统。只有可能是Java堆外内存使用超出预期,导致RES增加,才可能触发OOM。

调查过程

0.初步怀疑是哪里有DirectBuffer泄漏,或者JNI库的问题。
1.按惯例通过google perftools追踪堆外内存开销,但是并未发现明显的异常。
2.然后用Java NMT 看了一下,也没有发现什么异常。

3.查到这里思路似乎断了,因为跟DirectBuffer似乎没啥关系。这时候我注意到进程虚拟内存非常高,已经超过ECS内存了。怀疑这里有些问题。

4.进一步通过/proc/pid/smaps 查看进程内存地址空间分布,发现有大量mmap的文件。这些文件是cassandra的数据文件。

此时这些mmap file 虚拟内存是2G,但是物理内存是0(因为我之前重启过,调低过内存防止进程挂掉影响问题排查)。

显然mmap的内存开销是不受JVM heap控制的,也就是堆外内存。如果mmap的文件数据被从磁盘load进物理内存(RES增加),Java NMT和google perftool是无法感知的,这是kernel的调度过程。

5.考虑到是在压测时候出现问题的,所以我只要读一下这些文件,观察下RES是否会增加,增加多少,为啥增加,就能推断问题是不是在这里。通过下面的命令简单读一下之前导入的数据。

cassandra-stress read duration=10m cl=ONE -rate threads=20 -mode native cql3 user=cassandra password=123 -schema keysp
ace=keyspace5 -node core-3

6.可以观察到压测期间(sar -B),major page fault是明显上升的,因为数据被实际从磁盘被load进内存。

同时观察到mmap file物理内存增加到20MB:

最终进程RES涨到7.1g左右,增加了大约600M:

如果加大压力(50线程),还会涨,每个mmap file物理内存会从20MB,涨到40MB

7.Root cause是cassandra识别系统是64还是32来确定要不要用mmap,ECS都是64,但是实际上小规格ECS内存并不多。

结论


2 from .metrics import accuracy_score
3
4
5 class LogisticRegression:
6
7 def __init__(self):
8 """初始化Linear Regression模型"""
9 self.coef_ = None
10 self.intercept_ = None
11 self._theta = None
12
13 def _sigmoid(self, t):
14 return 1. / (1. + np.exp(www.leyouzaixan.cn-t))
15
16 def fit(self, X_train, y_train, eta=0.01, n_iters=1e4):
17 """根据训练数据集X_train, y_train, 使用梯度下降法训练Logistic Regression模型"""
18 assert X_train.shape[www.xingtuylgw.com] == y_train.shape[0], \
19 "the size of X_train must be equal to the size of y_train"
20
21 def J(theta, X_b, y):
22 y_hat = self._sigmoid(X_b.dot(theta))
23 try:
24 return - np.sum(y*np.log(y_hat) + (1-y)*np.log(1-y_hat)) / len(y)
25 except:
26 return float('inf'www.yongshenyuL.com)
27
28 def dJ(theta, X_b, y):
29 return X_b.T.dot(self._sigmoid(X_b.dot(theta)) - y) / len(X_b)
30
31 def gradient_descent(www.yacuangpt.com_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):
32
33 theta = initial_theta
34 cur_iter = 0
35
36 while cur_iter < n_iters:
37 gradient = dJ(theta, X_b, y)
38 last_theta = theta
39 theta = theta - eta * gradient
40 if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
41 break
42
43 cur_iter += 1
44
45 return theta
46
47 X_b = np.hstack([np.ones((len(www.yuxinyulept.com_train), 1)), X_train])
48 initial_theta = np.zeros(X_b.shape[1])
49 self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters)
50
51 self.intercept_ www.jintianxuesha.com= self._theta[0]
52 self.coef_ = self._theta[1:]
53
54 return self
55
56
57
58 def predict_proba(self, X_predict):
59 """给定待预测数据集X_predict,返回表示X_predict的结果概率向量"""
60 assert self.intercept_ is not None and self.coef_ is not None, \
61 "must fit before predict!"
62 assert X_predict.shape[1] == len(self.coef_), \
63 "the feature number of X_predict must be equal to X_train"
64
65 X_b = np.hstack([np.ones((len(www.zhuyngyule.cn_predict), 1)), X_predict])
66 return self._sigmoid(X_b.dot(self._theta))
67
68 def predict(self, X_predict):
69 """给定待预测数据集X_predict,返回表示X_predict的结果向量"""
70 assert self.intercept_ is not None and self.coef_ is not None, \
71 "must fit before predict!"
72 assert X_predict.shape[www.51dfyLgw.com] == len(self.coef_), \
73 "the feature number of X_predict must be equal to X_train"
74
75 proba = self.predict_proba(X_predict)
76 return np.array(proba >www.yunsengyule.com= 0.5, dtype='int')
77
78 def score(self, X_test, y_test):
79 """根据测试数据集 X_test 和 y_test 确定当前模型的准确度"""
80
81 y_predict = self.predict(X_test)
82 return accuracy_score(y_test, y_predict)
83
84 def __repr__(self):
85 return "LogisticRegression()"
复制代码

1.问题诱因是mmap到内存开销没有考虑进去,具体调整方法有很多。可以针对小规格ECS降低heap配置或者关闭mmap特性(disk_access_mode=standard)

2.排查Java堆外内存还是比较麻烦的,推荐先用NMT查查,用起来比较简单,配置JVM参数即可,可以看到内存申请情况。

作者:Roin

原文地址:https://www.cnblogs.com/dakunqq/p/11397496.html