0%

使用java代码 获取 TGT

1
2
3
4
5
public void login(Configuration conf) throws IOException {       
System.setProperty("java.security.krb5.conf", "krb5配置文件路径");
UserGroupInformation.setConfiguration(conf);
UserGroupInformation.loginUserFromKeytab(PRNCIPAL_NAME, PATH_TO_KEYTAB);
}
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
/*
* 通过java.security.krb5.conf 获取 krb.conf
* 通过hadoop.security.auth_to_local 设置 principal 映射规则
*/
public static void setConfiguration(Configuration conf) {
initialize(conf, true);
}
private static synchronized void initialize(Configuration conf,
boolean overrideNameRules) {
// 根据 hadoop.security.authentication 判断 hadoop 的认证方法
authenticationMethod = SecurityUtil.getAuthenticationMethod(conf);
if (overrideNameRules || !HadoopKerberosName.hasRulesBeenSet()) {
try {
// (以非IBM jdk为例)
// 1. 通过反射实例化 sun.security.krb5.Config: 在本例中Config的实例化信息 来自 java.security.krb5.conf 指定的krb5.conf配置文件
// 2. 读取 hadoop.security.auth_to_local,并设置principal映射规则
HadoopKerberosName.setConfiguration(conf);
} catch (IOException ioe) {
throw new RuntimeException(
"Problem with Kerberos auth_to_local name configuration", ioe);
}
}
// metrics 和 groups
if (!(groups instanceof TestingGroups)) {
groups = Groups.getUserToGroupsMappingService(conf);
}
UserGroupInformation.conf = conf;
if (metrics.getGroupsQuantiles == null) {
int[] intervals = conf.getInts(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS);
if (intervals != null && intervals.length > 0) {
final int length = intervals.length;
MutableQuantiles[] getGroupsQuantiles = new MutableQuantiles[length];
for (int i = 0; i < length; i++) {
getGroupsQuantiles[i] = metrics.registry.newQuantiles(
"getGroups" + intervals[i] + "s",
"Get groups", "ops", "latency", intervals[i]);
}
metrics.getGroupsQuantiles = getGroupsQuantiles;
}
}
}
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
public synchronized
static void loginUserFromKeytab(String user,
String path
) throws IOException {
if (!isSecurityEnabled())
return;

keytabFile = path;
keytabPrincipal = user;
Subject subject = new Subject();
LoginContext login;
long start = 0;
try {
//
login = newLoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME,
subject, new HadoopConfiguration());
start = Time.now();
// Krb5LoginModule
// HadoopLoginModule
login.login();
metrics.loginSuccess.add(Time.now() - start);
loginUser = new UserGroupInformation(subject);
loginUser.setLogin(login);
loginUser.setAuthenticationMethod(AuthenticationMethod.KERBEROS);
} catch (LoginException le) {
if (start > 0) {
metrics.loginFailure.add(Time.now() - start);
}
throw new IOException("Login failure for " + user + " from keytab " +
path+ ": " + le, le);
}
LOG.info("Login successful for user " + keytabPrincipal
+ " using keytab file " + keytabFile);
}

Krb5LoginModule 中几个重要的方法:

  • attemptAuthentication()
  • login()
  • commit()

HadoopLoginModule中几个重要的方法:

  • login()
  • commit()

文章收集

UserGroupInformation.doAs

https://blog.csdn.net/weixin_35852328/article/details/83620379

Hadoop安全认证(2)

https://blog.csdn.net/daiyutage/article/details/52091779

Should I call ugi.checkTGTAndReloginFromKeytab() before every action on hadoop?

https://stackoverflow.com/questions/34616676/should-i-call-ugi-checktgtandreloginfromkeytab-before-every-action-on-hadoop

Hadoop Delegation Tokens详解【译文】

https://www.jianshu.com/p/617fa722e057

MIT 官方文档

http://web.mit.edu/Kerberos/krb5-devel/doc/admin/index.html

artifactory 是一个通用的仓库管理器。可以管理 npm、docker、maven和 ivy 等等。

repositories 分为三种:

  • Local : 公司内部 jar 和 ArtifactoryWeb 页面上传的jar
  • remote: 缓存 其他远程仓库的jar
  • virtual: 仅是 local和 remote的集合,通过一个 virtual,代表多个local和remote的访问

artifactory 有个默认的全局 virtual仓库。访问路劲为 http://ip:port/artifactory/repo

Prometheus 是一个开源系统监控和警报工具包。跟springboot 有很好的兼容性。

架构

最佳实践

基本类型: Count

只增不减的计数器

常用的监控指标: 统计 请求总数、 jvm gc次数等。

结合 rate() 函数,可以获取监控指标过去一段时间的增长率

rate(http_requests_total[5m])

结合 topk() 函数,可以获取topk的指标

topk(10, http_requests_total)

基本类型: Gauge

可增可减的变量,反映当前的状态

常见指标: 当前活跃线程数、当前主机空闲内存等

直接通过指标名,即可获取指标的当前状态。

高级类型: 直方图和摘要

Histograms和Summaries 用来获取 监控指标 从初始化(重启)到某个时间点的采样点分布,监控指标一般要求服从正态分布。

Histograms或summaries 会同时维护观察对象(如 request )的两个指标:

  • *_count指标: 表示观察对象的请求次数,如 request的次数
  • *_sum指标: 表示 观察对象的值的总和,如 request的总耗时

通过这两个变量,我们可以计算出观察对象 一定时间的平均值。如:

1
2
3
4
5
前五分钟,一个请求的平均耗时
-----------------------------
rate(http_request_duration_seconds_sum[5m])
/
rate(http_request_duration_seconds_count[5m])

常用函数

increase

获取 区间向量中的第一个样本与最后一个样本之间的增长量。increase 只能用于 Counter 类型的指标。

计算方式为:

(v5-v1) / (t5-t1) * 5

例子: 过去5分钟新增的请求数

1
increase(http_requests_total{job="api-server"}[5m])

rate

区间向量的平均增长率。rate 只能用于 Counter 类型的指标
计算方式为:

(v5-v1) / (t5-t1)

1
2
3
rate(http_requests_total{job="api-server"}[2m])
等同于
increase(http_requests_total{job="api-server"}[2m]) / 120

irate

基于 区间的最后两个连续的数据点,计算区间的平均增长率(秒)。irate 只能用于 Counter 类型的指标

1
2
3
基于过去5分钟的最后两个数据点,计算每秒HTTP请求率

irate(http_requests_total{job="api-server"}[5m])

histogram_quantile

用于获取某一数值,小于该数值的观察对象占 指定百分位

1
2
3
过去10分钟内,请求响应时间的 90th 百分位数(暂且称为A)。即 90% 的请求响应时间小于 A

histogram_quantile(0.9, rate(http_request_duration_seconds_bucket[10m]))

参考资料

直方图和摘要

Prometheus查询函数

prometheus中文

下面的类简单演示了 parallelStream 并行原理

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.CountDownLatch;

public class TestTwo {

public static void main(String[] args) throws Exception {
System.out.println("Hello World!");
// 构造一个10000个元素的集合
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
list.add(i);
}
// 统计并行执行list的线程
Set<Thread> threadSet = new CopyOnWriteArraySet<>();
// 并行执行
list.parallelStream().forEach(integer -> {
Thread thread = Thread.currentThread();
// System.out.println(thread);
// 统计并行执行list的线程
threadSet.add(thread);
});
System.out.println("threadSet一共有" + threadSet.size() + "个线程");
System.out.println("系统一个有" + Runtime.getRuntime().availableProcessors() + "个cpu");


List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
list1.add(i);
list2.add(i);
}
Set<Thread> threadSetTwo1 = new CopyOnWriteArraySet<>();
CountDownLatch countDownLatch = new CountDownLatch(2);
Thread threadA = new Thread(() -> {
list1.parallelStream().forEach(integer -> {
Thread thread = Thread.currentThread();
threadSetTwo1.add(thread);
});
countDownLatch.countDown();
});
Set<Thread> threadSetTwo2 = new CopyOnWriteArraySet<>();
Thread threadB = new Thread(() -> {
list2.parallelStream().forEach(integer -> {
Thread thread = Thread.currentThread();
threadSetTwo2.add(thread);
});
countDownLatch.countDown();
});

threadA.start();
threadB.start();
countDownLatch.await();
System.out.println("threadSetTwo1一共有" + threadSetTwo1.size() + "个线程");
System.out.println("threadSetTwo2一共有" + threadSetTwo2.size() + "个线程");

System.out.println("---------------------------");
System.out.println("threadSet:"+threadSet);
System.out.println("threadSet1:"+threadSetTwo1);
System.out.println("threadSet2:"+threadSetTwo2);
System.out.println("---------------------------");
//threadSetTwo.addAll(threadSet);
//System.out.println(threadSetTwo);
//System.out.println("threadSetTwo一共有" + threadSetTwo.size() + "个线程");
//System.out.println("系统一个有" + Runtime.getRuntime().availableProcessors() + "个cpu");
}
}

运行结果:

1
2
3
4
5
6
7
8
9
10
Hello World!
threadSet一共有4个线程
系统一个有4个cpu
threadSetTwo1一共有4个线程
threadSetTwo2一共有4个线程
---------------------------
threadSet:[Thread[ForkJoinPool.commonPool-worker-1,5,main], Thread[ForkJoinPool.commonPool-worker-2,5,main], Thread[ForkJoinPool.commonPool-worker-3,5,main], Thread[main,5,main]]
threadSet1:[Thread[Thread-0,5,], Thread[ForkJoinPool.commonPool-worker-3,5,main], Thread[ForkJoinPool.commonPool-worker-1,5,main], Thread[ForkJoinPool.commonPool-worker-2,5,main]]
threadSet2:[Thread[ForkJoinPool.commonPool-worker-1,5,main], Thread[ForkJoinPool.commonPool-worker-3,5,main], Thread[ForkJoinPool.commonPool-worker-2,5,main], Thread[Thread-1,5,]]
---------------------------

从结果可以看出,ForkJoinPool 产生4个线程(一个调用线程+3个ForkJoinPool通用线程)。 为什么是生成 4个线程的原因是: ForkJoinPool 默认根据计算机的处理器数量来设定。

parallelStream 缺点

默认情况下,parallelStream 使用的是 通用 ForkJoinPool。即 任何使用 parallelStream 方法的代码都公用 同一个 线程池。

当其中一个 任务阻塞时,会影响其他使用parallelStream的代码。

解决方案:

1
2
3
4
5
6
7
8
class Tse{
public static void main(String[] args){
ForkJoinPool forkJoinPool = new ForkJoinPool(2);
forkJoinPool.submit(() ->
IntStream.range(1, 1_000_000).parallel().filter(PrimesPrint::isPrime).collect(toList())
).get();
}
}

参考

https://blog.csdn.net/u011001723/article/details/52794455