[Coherence/Web] How to use Coherence Web 14c
1. Overview
How-to-install-Coherence-Web-14c 에서 설치를 완료 했다.
여기서는 실제 환경에서 쓰일 수 있게 다음의 항목들을 확인한다.
- Death Detection
- F/W
- Session Reaper Thread Tuning
2. Death Detection
Configuring Death Detection 을 하여, ClusterMember 이탈 여부를 확인한다.
2.1 TCP-RING
Member들은 하나의 Ring으로 연결된다.
25초 동안 HeartBeat 응답을 주지 않은 Member를 5회 실시하여, Member를 제거한다.
java.net.InetAddress.isReachable
를 시도하며, 이 Method는 Process가 아니라 Host에 Port 7(Echo)를 전송하여 응답을 받으려고 시도한다.
Port 7(Echo) 가 방화벽에 예외 처리 되어 있어야 한다.
listen-backlog는 이러한 HeartBeat 감지를 받을 때, 최대 backlog 로 보여진다.
1
2
3
4
5
6
<tcp-ring-listener>
<enabled>true</enabled>
<ip-timeout system-property="coherence.ipmonitor.pingtimeout">25s</ip-timeout>
<ip-attempts>5</ip-attempts>
<listen-backlog>10</listen-backlog>
</tcp-ring-listener>
최대 2분 5초 동안 응답을 하지 않은 Member가 발견되면 아래와 같이 Logging 된다.
1
tmb://10.65.34.245:9003.34707 initiating connection migration with tmb://10.65.34.245:9001.43859 after 2m5s ack timeout health(read=true, write=false), receiptWait=null: peer=tmb://10.65.34.245:9001.43859
9003 Port Member가 응답하지 않는다.
tcp-ring-listener 를 사용하지 않으면, 인스턴스가 Shutdown 될 시에 매우 늦게 감지가 된다.
반드시 사용한다.
tcp-ring-listener false 시에 Member shutdown 을 하면 2분 5초 뒤에 파악이 된다.
2.2 HeartBeat
Cluster Member들 간에는 HeartBeat를 주고 받는다.
이 HeartBeat 간격은 기본값 1초 이며, Member가 많을 경우 Traffic이 증대할 것이며, 평소 Network 신뢰성이 높은 경우, 불필요하게 많은 Traffic을 유발하지 않도록 설정값을 변경하는 것도 고려해볼 만 하다.
문서 상에는, HeartBeat를 매 간격마다 보내지 않고, 내부 평가 프로세스에 따라 그러하다고 하는데 어떤 프로세스를 가지는지는 문서상에 보이지 않는다.
1
2
3
4
5
<packet-publisher>
<packet-delivery>
<heartbeat-milliseconds>5000</heartbeat-milliseconds>
</packet-delivery>
</packet-publisher>
3. Firewall
- Cluster Port (Default 7574) 는 Multicast/Unicast 에서 모두 사용되고, UDP/TCP 로 쓰인다. Coherence에 Proxy를 구성하고, Client에서 Naming Service로 Proxy를 이용할 때 Name을 검색하는 Port.
- Cluster Port가 Unicast 에서 사용되는 시기는, WKA(Well-Known-Addresses) 를 사용할 때다. WKA 멤버를 찾을 때, Cluster Port를 사용한다.
- Death Detection 을 위해 TCP 7 (Echo port)를 사용한다.
- 위 외에 메뉴얼상 필요한 Port는 없고, Member간의 통신 방식에 사용하는 Port를 열어주면 된다.
- 다음의 설정을 하지 않으면, Member들마다 Random port가 부여된다. 장점은, 다른 Process와 충돌이 없는 것이지만, 방화벽이 없는 구간에서 사용해야 한다.
1 2 3 4 5
<unicast-listener> <address system-property="coherence.localhost">wls.local</address> <port system-property="coherence.localport">9000</port> <port-auto-adjust system-property="coherence.localport.adjust">9100</port-auto-adjust> ...
4. MBean Monitoring
다음 옵션을 추가하여, WLST MBean 을 Monitoring 할 수 있다.
1
-Djavax.management.builder.initial=weblogic.management.jmx.mbeanserver.WLSMBeanServerBuilder
MBean Coherence Tree를 찾아가려면, 아래와 같은 핵심코드가 필요하다.
1
2
3
4
5
6
7
8
9
# connect to server
connect(username, password, url)
# get LocalMemberId
cd('custom:/Coherence/Coherence:type=Cluster')
localMemberId = str(get('LocalMemberId'))
# change dir to cohSessionApp
cd('custom:/Coherence/Coherence:type=WebLogicHttpSessionManager,nodeId=' + localMemberId + ',appId=<app-name>')
5. JMX Monitoring
Allowing Remote Access to Oracle Coherence MBeans
1
2
3
4
5
6
-Dcoherence.management=all
-Dcoherence.management.remote=true
-Dcom.sun.management.jmxremote.port=<JMX port>
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=wls.local
Coherence Cluster를 사용하는 WebApp 이 배포된 Managed Coherence Server에 설정 후 JConsole을 통해 MBean 을 읽을 수 있다.
Coherence - WebLogicHttpSessionManager - <Member ID> - <Web App> - Attributes 에서 처리되는 Session 통계를 알 수 있다.
Member ID는 Node의 각 Attributes 에서 MemberName이나 ProcessName 으로 획득하면 수월하겠다.
예시 화면에서는 Unique 하게 되어 있지 않은데, Operational Override File에서 지정하면 된다.
1
2
<process-name system-property="coherence.process">process_base_domain</process-name>
<member-name system-property="coherence.member">member_base_domain</member-name>
6. Session Reaper Thread
App 에서 생성된 HTTP Session은 timeout-secs 만큼 유효하다.
invalidation-internal-secs 마다 All HTTP Session을 Scan하여 invalid 한 session을 삭제하여 Memory를 확보한다.
6.1 Ready For Test
(1) WLST
4. MBean Monitoring 을 이용하여 아래의 Code를 작성하고,
Session 부하를 발생 시킬 때, Reaper Thread가 어떻게 동작하는지 알아본다.
WLST MBean code
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
java -Djava.security.egd=file:/dev/urandom weblogic.WLST << EOF
# import
import os
import sys
import time
# log file
fo = open("/tmp/coh.log", "wb+")
# connection information
username = 'weblogic'
password = 'weblogic1'
url = 'wls.local:8002'
# connect to server
connect(username, password, url)
# get LocalMemberId
cd('custom:/Coherence/Coherence:type=Cluster')
localMemberId = str(get('LocalMemberId'))
# change dir to cohSessionApp
cd('custom:/Coherence/Coherence:type=WebLogicHttpSessionManager,nodeId=' + localMemberId + ',appId=cohSessionAppcohSessionApp')
sleep_in_ms = 5000
for idx in range(0, 200):
###### print MBeans ######
### Attr to Var ###
# Reaper Cycle
LastReapCycle = str(get('LastReapCycle'))
NextReapCycle = str(get('NextReapCycle'))
# Reap Duration
AverageReapDuration = str(get('AverageReapDuration'))
LastReapDuration = str(get('LastReapDuration'))
MaxReapDuration = str(get('MaxReapDuration'))
# Reaped Sessions
AverageReapedSessions = str(get('AverageReapedSessions'))
MaxReapedSessions = str(get('MaxReapedSessions'))
ReapedSessions = str(get('ReapedSessions'))
ReapedSessionsTotal = str(get('ReapedSessionsTotal'))
# Sessions
SessionUpdates = str(get('SessionUpdates'))
OverflowUpdates = str(get('OverflowUpdates'))
### Var to Log ###
dm = " | "
writeLogData = ""
# Print Init Header
if idx == 0:
writeLogData += "LastReapCycle" + dm
writeLogData += "NextReapCycle" + dm
writeLogData += "AverageReapDuration" + dm
writeLogData += "LastReapDuration" + dm
writeLogData += "MaxReapDuration" + dm
writeLogData += "AverageReapedSessions" + dm
writeLogData += "MaxReapedSessions" + dm
writeLogData += "ReapedSessions" + dm
writeLogData += "ReapedSessionsTotal" + dm
writeLogData += "SessionUpdates" + dm
writeLogData += "OverflowUpdates" + "\n"
writeLogData += str(idx) + dm
writeLogData += LastReapCycle + dm
writeLogData += NextReapCycle + dm
writeLogData += AverageReapDuration + dm
writeLogData += LastReapDuration + dm
writeLogData += MaxReapDuration + dm
writeLogData += AverageReapedSessions + dm
writeLogData += MaxReapedSessions + dm
writeLogData += ReapedSessions + dm
writeLogData += ReapedSessionsTotal + dm
writeLogData += OverflowUpdates + dm
writeLogData += SessionUpdates
fo.write(writeLogData+"\n")
fo.flush()
print(writeLogData)
Thread.sleep(sleep_in_ms)
fo.close()
exit()
EOF
(2) Test Application
Session 을 원하는 Size만큼 생성 시키는 Application은 Coherence-Session-Test-Application 을 사용한다.
(3) Apache JMeter
Apache JMeter는 다음과 같이 설정했다.
- Thread Group
- Number of Threads (users): 50
- Ramp-up period (seconds): 1
- Loop Count: Infinite
- Use KeepAlive: X (No)
- Specify Thread lifetime
- Duration(Seconds) : 300
1초 이내에 50명의 사용자가 준비되며, 지속적으로 신규 사용자처럼 유입된다.
이 작업은 300 secs 동안 지속된다. TPS로 환산할 수 없으나, 성능이 좋지 않은 Local 에서 작업하기에는 꽤 클 것이다.
성능이 좋지 않은 Local Test System 에서 작업하니, 사용자를 더 크게 늘릴 수 없었다.
늘리는 경우, Coherence에 쌓이는 Cache 가 매우 많아 Reaper가 동작하지 않는 문제가 있었다.
(4) Cache Server/Client
Cache Server(Coherence Web), Cache Client(WebLogic Server; MCS)는 물리적으로 같은 Node이며
기본적으로 다음의 초기 환경을 구성하였다.
-
RHEL 8.7, 2 physical core (4 logic core with hyperthreading), JDK 1.8.0_351
- Coherence Server 1 EA
-Xms2048m -Xmx2048m
- Managed Coherence Server 1 EA
-Xms3096m -Xmx3096m
coherence.session.localstorage=false
coherence.reaperdaemon.parallel=true
wm/CoherenceWorkManager
: Min(2) / Max(2)- Deployed ‘cohSessionApp’
- Session Timeout Secs : 30
- Invalidation Interval Secs : 60
6.2 50 Users
기본 환경 구성한대로, 50 Users 반복 요청 시에 쌓이는 Session Data와,
30 Secs 마다 Session은 Invalid 된다.
Invalid 된 Session을 정리하는 Reaper Thread가 어떻게 작업을 이루어 냈는지 Data를 뽑아내었다.
JMeter로 부하를 인입하고, WLST로 Coherence에 Session이 적재된 것이 관측된 최초 지점부터 Data를 Grep해보면 대략 아래와 같이 쌓인다.
1
2
3
4
5
6
7
8
9
10
11
12
LastReapCycle | NextReapCycle | AverageReapDuration | LastReapDuration | MaxReapDuration | AverageReapedSessions | MaxReapedSessions | ReapedSessions | ReapedSessionsTotal | SessionUpdates | OverflowUpdates
...
1 | Tue May 30 16:02:33 KST 2023 | Tue May 30 16:03:33 KST 2023 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 278 | 275
2 | Tue May 30 16:02:33 KST 2023 | Tue May 30 16:03:33 KST 2023 | 0 | 0 | 0 | 0 | 0 | 0 |
...
71 | Tue May 30 16:08:43 KST 2023 | Tue May 30 16:09:43 KST 2023 | 11485 | 5898 | 20649 | 6243 | 9865 | 5381 | 37458 | 37303 | 37289
...
JMeter로 300 Secs 동안 요청이 인입되고 난뒤에는 종료될 것이다.
초기, Session Data가 관측되지 않는 (SessionUpdates 가 0) Data는 제외.
말기, Session Data가 더 이상 정리될 것이 없는 (ReapedSessionsTotal이 SessionUpdates 에 가까움) Data 까지만 수집한다.
평균 또는 수집된 데이터를 보면,
AverageReapDuration | LastReapDuration | MaxReapDuration | AverageReapedSessions | MaxReapedSessions | ReapedSessions | ReapedSessionsTotal | SessionUpdates | OverflowUpdates |
---|---|---|---|---|---|---|---|---|
4520.352113 | 9164.901408 | 12129 | 2680.43662 | 9631 | 6347.28169 | 38257 | 38123 | 38078 |
AverageReapDuration : Reap에 소요된 평균 시간 (평균값)
LastReapDuration : 가장 마지막 Reap에 소요된 시간 (평균값)
MaxReapDuration : Reap에 소요된 최대 시간 (최대값)
AverageReapedSessions : Reaped Session의 평균 갯수, 평균적으로 Reap 1 Cycle 당 몇개의 Session이 Reaped 되는지를 나타냄 (평균값)
MaxReapedSessions : Reaped Session의 최대 갯수, 한번에 최대 몇개의 Session이 Reaped 되었는지를 나타냄 (최대값)
ReapedSessions : Reap 1 Cycle 당 한번에 몇개의 Session이 Reaped 되었는지 나타냄 (평균값)
ReapedSessionTotal : 지금까지 총합 Reaped Session 갯수 (최대값)
SessionUpdates : Session이 만들어지거나, Touched 되었을 때 집계 됨 (최대값)
OverflowUpdates : Overflow는 큰 Session Data를 저장할 때 사용되는 Model이며, OverflowThreshold(default 1024) 크기를 넘어서는 Session의 총 Updates 갯수가 집계됨. (최대값)
평균에 의미가 없는 값들은, 최대값으로 수집했다.
6.3 50 Users / 4 Threads
앞서, WebLogic WorkManager에 의해 Min/Max가 2 Threads로 환경을 구성하여 테스트했다면,
이번에는 4 Threads로 구성하여 개선되는지 살펴본다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<self-tuning>
<min-threads-constraint>
<name>MinThreadsConstraint-0</name>
<target>myCluster</target>
<count>4</count>
</min-threads-constraint>
<max-threads-constraint>
<name>MaxThreadsConstraint-0</name>
<target>myCluster</target>
<count>4</count>
</max-threads-constraint>
<work-manager>
<name>wm/CoherenceWorkManager</name>
<target>myCluster</target>
</work-manager>
평균은,
AverageReapDuration | LastReapDuration | MaxReapDuration | AverageReapedSessions | MaxReapedSessions | ReapedSessions | ReapedSessionsTotal | SessionUpdates | OverflowUpdates |
---|---|---|---|---|---|---|---|---|
4446.315068 | 8821.205479 | 13252 | 2884.260274 | 9754 | 6474.520548 | 37743 | 37582 | 37551 |
검증을 위해, 동일하게 한번 더 테스트하였는데 아래와 같다.
AverageReapDuration | LastReapDuration | MaxReapDuration | AverageReapedSessions | MaxReapedSessions | ReapedSessions | ReapedSessionsTotal | SessionUpdates | OverflowUpdates |
---|---|---|---|---|---|---|---|---|
3637.561644 | 10007.67123 | 14751 | 2068.520548 | 9829 | 6447.589041 | 38384 | 38203 | 38255 |
이외에도 여러번의 테스트를 해보았는데, 결과마다 편차가 조금 심한 편이지만 대체적으로 Reaper Thread를 늘려 개선이 되는 것은 확인이 된다.
6.4 50 Users / 8 Threads
평균은,
AverageReapDuration | LastReapDuration | MaxReapDuration | AverageReapedSessions | MaxReapedSessions | ReapedSessions | ReapedSessionsTotal | SessionUpdates | OverflowUpdates |
---|---|---|---|---|---|---|---|---|
4944.534247 | 9499.547945 | 13958 | 2801.657534 | 9838 | 6346.931507 | 37692 | 37577 | 37579 |
재차 테스트 시에,
AverageReapDuration | LastReapDuration | MaxReapDuration | AverageReapedSessions | MaxReapedSessions | ReapedSessions | ReapedSessionsTotal | SessionUpdates | OverflowUpdates |
---|---|---|---|---|---|---|---|---|
6347.72 | 9040.72 | 16162 | 3886.213333 | 9784 | 6437.76 | 38259 | 38072 | 38081 |
오히려 감소하기도 하고, 특별히 드라마틱한 변화가 없다.
6.5 50 Users / 12 Threads
평균은,
AverageReapDuration | LastReapDuration | MaxReapDuration | AverageReapedSessions | MaxReapedSessions | ReapedSessions | ReapedSessionsTotal | SessionUpdates | OverflowUpdates |
---|---|---|---|---|---|---|---|---|
3344.381579 | 8949.065789 | 22647 | 1913.447368 | 9654 | 6253.592105 | 38098 | 37919 | 37915 |
재차 테스트,
AverageReapDuration | LastReapDuration | MaxReapDuration | AverageReapedSessions | MaxReapedSessions | ReapedSessions | ReapedSessionsTotal | SessionUpdates | OverflowUpdates |
---|---|---|---|---|---|---|---|---|
6243.068493 | 9646.287671 | 13999 | 3526.219178 | 9837 | 6268.753425 | 37427 | 37278 | 37320 |
6.6 OverflowUpdates
OverflowUpdates : Overflow는 큰 Session Data를 저장할 때 사용되는 Model이며, OverflowThreshold(default 1024) 크기를 넘어서는 Session의 총 Updates 갯수가 집계됨.
Test App에서 생성하는 Session Data의 Size를 1024 bytes 보다 작게 만들 경우,
SessionUpdates는 증가하되, OverflowUpdates는 증가하지 않을 것으로 보이는데,
이 부분을 검증하기 위해서 Session Data 의 정확한 Size를 Inspect 해야 한다.
JFR, Heap Dump, Instrumentation.getObjectSize 등등 여러가지를 확인해보고 있으나,
껍데기 Size만 확인되는 등 정확한 수치가 나오질 않아 좀 더 확인해봐야 하는 부분이다.
이후에, 여러날에 걸쳐 확인을 해보았는데 openjdk 의 JOL(Java Object Layout) Library 를 활용하여 Object Size를 측정할 수 있었다.
Java-Object-Layout Post 에서 다루었다.
Post에 따르면, _obj Byte Array를 정확히 실제 크기 1024 Bytes에 맞추기 위해서는
- Header bytes 16 를 빼고
- Gap 8bytes 의 배수에 맞게끔
설정하면 된다고 했다.
그러므로 _obj Byte Array 갯수는 정확히 1008 개를 만들면, 실제 JVM Heap Memory에 올라가는 Object Size는 1024 Bytes가 된다.
byte[] _obj = new byte[1008];
이제 Coherence Session Data를 Update 하고 MBean을 살펴보면
- OverflowThreshold : 1024
- OverflowUpdates : 0
- OverflowMaxSize : 0
Session Data가 1024 bytes 보다 작기 때문에, 1회 호출 시에는 Overflow cache 가 아닌 것이 확인된다.
연속 2회 호출하여, Session Data 크기를 증분 시키면,
- OverflowThreshold : 1024
- OverflowUpdates : 1
- OverflowMaxSize : 2019
예상값 2032 Bytes 보다 작은 2019 Bytes로 확인되며, Overflow 가 update 되었다.
연속 호출을 더 여러번 해보았는데, 항상 JVM Heap memory 에 적재되는 실제 Size보다 항상 13 Bytes가 적게 측정되었다.
Coherence 의 Session을 다루는 Object를 JOL로 확인해보고 싶으나, Object 를 특정짓지 못하였다.
7. Outcomes
성능이 좋지 않은 Local Test 환경에서는 4 Reaper Thread 환경 부터 그나마 Tuning 의 결과가 확인이 된다.
그럼에도 반복 수행 시 Local Test 환경의 영향인지, 들쑥 날쑥하고 드라마틱한 결과를 보여주지는 않는다.
Test 결과 또한 좋았으면 했지만 그렇지 않았으므로
MBean 항목에 대한 이해를 얻은 것으로 마무리 해야 할 듯 싶다.
그 외에도, JOL 을 이용하여 Overflowupdate 기준을 실제 추적하는 Test도 진행할 수 있었다.
8. References
WLST로 수집되는 MBean 항목 부연 설명 관련 자료
Specifying a Cluster’s Multicast Address and Port
Recommended Thread-count-min And Thread-count-max Values in Coherence (Doc ID 2294067.1)
Explanation Of Meaning For Coherence Threadpool Error Message (Doc ID 2728051.1)