Commit 431a092d 431a092dd9113690f2a6fbbea04a4f5b526e8150 by Christian Gerdes

First version with PDB support in LILOM. Needs more testing.

1 parent e8332d60
No preview for this file type
# Notes
## PDB logic
Bytt approuch och tagit bort allt som tidigare fanns i PDB branchen och har mergat den med master (då den innehöll TNS koden).
Gamla tanken var att via en PDB klura ut vad CDB databasens conn sträng är, ansluta till den, och hämta data för alla PDBer istället och cacha detta i CDB objektet.
Hade funkat fint, förutom att det förutsätter att CDB och PDB har samma lyssnare, vilket de inte nödvändigtvist har. Jag kan inte klura ut vad lyssnaren ska vara till CDB.
Istället får det bli en lösning där användaren alltid anger CDB databasens conn sträng, men kan med en flagga välja att få ut en PDB's info istället.
Idag ser tex ett anrop ut så här:
GET /OraMonREST/getData?age=14&connectionString=jdbc%3Aoracle%3Athin%3A%40%2F%2Fu03634.kap.rsv.se%3A1526%2FDB1K12
I detta kan vi lägga till en parameter, forPDB=DA1K001 tex och då returneras endast värden för den PDB'n.
På så sätt kommer anrop till flera olika PDB att hämtas från samma CDB data cache.
Anropet till CDB'n skulle kunna returnera en lista på alla PDBer också.
Ännu snyggare vore om en CDB kunde bryta ner graferna per PDB också ;)
SQL satser
select cdb from v$database;
Returnerar YES om databasen är en CDB (dvs Oracle 12 med CDB påslaget). Returnerar YES även på en PDB.
Views for PDB's
V_$CON_SYSSTAT
V_$CON_SYSTEM_WAIT_CLASS
V_$CON_SYSTEM_EVENT
V_$CON_SYS_TIME_MODEL
Can be checked with a select like
select view_name from all_views where view_name like 'V_$CON_%';
Slå samman con_id med statname
select systimestamp, name || con_id, value from V$CON_SYSSTAT;
2018-03-28
Första versionen med PDB stöd. Behövs mer tester.
PDB CPU: 11.056953715796771
CDB CPU: 11.204673034978592
DA1K001: 11.084891829252536
DA1K002: 55.75905904774211
TOTAL : 66.84395087699465
Exemplet ovan är med ett delta på 60 sekunder, PDB går direkt mot PDB con string, CDB direkt mot CDB och DA räknarna är från denna CDB.
DA1K002 är på samma CDB, och getCPUPercent() ovan returnerar av någon anledning att den tar 55% cpu när hela CDB bara tar 11.2 vilket känns fel.
Det är bara DA1K001 som jobbar. Nedan från samma mätning fast Logical IO per Second istället:
PDB LIO: 433961.7046663872
CDB LIO: 433532.02901594585
DA1K001: 435343.22211814864
DA1K002: 9.075934239850135
TOTAL : 435352.2980523885
Här känns alla värden rätt.
\ No newline at end of file
......@@ -83,4 +83,17 @@ class Collector {
else
return 0;
}
public double getSeconds(String name) throws Throwable {
LongDelta myDelta = null;
for(int x = 0; x<list.size() && myDelta == null; x++) {
if(name.equals(list.get(x).name)) {
myDelta = list.get(x);
}
}
if(myDelta != null)
return myDelta.getSeconds();
else
return 0;
}
}
\ No newline at end of file
......
package se.lil.om;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Properties;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
......@@ -15,11 +17,6 @@ public class OraMon {
String dbName = null;
String serviceName = null;
Boolean isPDB = false;
Boolean isCDB = false;
Boolean hasContainers = null;
OraMon containerDB = null;
public static final int SYSSTAT = 1;
public static final int OSSTAT = 2;
......@@ -29,6 +26,13 @@ public class OraMon {
int getDataCalls = 0;
int getDataSucess = 0;
boolean getPdbs = false;
Collector colPdbSysStat = null;
Collector colPdbCPU = null;
public static final String strCpuTime = " cputime";
public static final String strNiwTime = " niwtime";
public static final String strSeparator = " ";
public int getDataCalled() {
return getDataCalls;
}
......@@ -81,48 +85,80 @@ public class OraMon {
//DB CPU
LongDelta cpuTime = new LongDelta(true);
LongDelta niwTime = new LongDelta(true);
public double getCPUPercent(boolean excludeNonIdleWaitTime) throws Throwable {
double perSec = cpuTime.getPerSecondValue();
public double getCPUPercent(boolean excludeNonIdleWaitTime, String pdbName) throws Throwable {
double cpuPerSec;
if(pdbName == null) cpuPerSec = cpuTime.getPerSecondValue();
else cpuPerSec = colPdbCPU.getPerSecValue(pdbName + strCpuTime);
double niwPerSec;
if(pdbName == null) niwPerSec = niwTime.getPerSecondValue();
else niwPerSec = colPdbCPU.getPerSecValue(pdbName + strNiwTime);
if(excludeNonIdleWaitTime) {
double newPerSec = perSec - (niwTime.getPerSecondValue() * 1000);
if(newPerSec > 0) perSec = newPerSec; else perSec = 0;
double newPerSec = cpuPerSec - (niwPerSec * 1000);
if(newPerSec > 0) cpuPerSec = newPerSec; else cpuPerSec = 0;
}
double totSec = numCpus * 1000 * 1000;
double percent = (perSec / totSec) * 100;
double percent = (cpuPerSec / totSec) * 100;
if(percent > 100D) percent=100D;
if(percent < 0D) percent=0D;
return percent;
}
public double getCPUPercent(boolean excludeNonIdleWaitTime) throws Throwable {
return getCPUPercent(excludeNonIdleWaitTime, null);
}
public double getCPUPercent() throws Throwable {
return getCPUPercent(false);
}
public double getCPUPercent(String pdbName) throws Throwable {
return getCPUPercent(false, pdbName);
}
public double getCPUAvailableSeconds() throws Throwable {
return cpuTime.getSeconds()*numCpus;
}
public double getCPUAvailableSeconds(String pdbName) throws Throwable {
return colPdbCPU.getSeconds(pdbName + strCpuTime)*numCpus;
}
public long getCPURawValue() throws Throwable {
return cpuTime.getCurrentValue();
}
public long getCPURawDiff() {
if(cpuTime != null && cpuTime.lastValue != null)
return cpuTime.curValue - cpuTime.lastValue;
else
return 0;
public long getCPURawValue(String pdbName) throws Throwable {
return colPdbCPU.getCurrentValue(pdbName + strCpuTime);
}
public long getCPURawDiff() throws Throwable {
return cpuTime.getDelta();
}
public long getCPURawDiff(String pdbName) throws Throwable {
return colPdbCPU.getDelta(pdbName + strCpuTime);
}
public double getCPUTimePerSecond() throws Throwable {
return cpuTime.getPerSecondValue();
}
public double getCPUTimePerSecond(String pdbName) throws Throwable {
return colPdbCPU.getPerSecValue(pdbName + strCpuTime);
}
public double getPerSecondValue(String name) throws Throwable {
return getPerSecondValue(name, SYSSTAT);
return getPerSecondValue(name, SYSSTAT, null);
}
public double getPerSecondValue(String name, int table) throws Throwable {
return getPerSecondValue(name, table, null);
}
public double getPerSecondValue(String name, int table, String pdbName) throws Throwable {
switch (table) {
case OSSTAT:
return colOsStat.getPerSecValue(name);
case SYSSTAT:
if(pdbName == null)
return colSysStat.getPerSecValue(name);
else
return colPdbSysStat.getPerSecValue(pdbName + strSeparator + name);
default:
return colSysStat.getPerSecValue(name);
}
......@@ -140,10 +176,6 @@ public class OraMon {
else return this.dbName;
}
public boolean isPDB() {
return isPDB;
}
public double getOsBusyPercent() throws Throwable {
double idle = getPerSecondValue("IDLE_TIME", OSSTAT);
double busy = getPerSecondValue("BUSY_TIME", OSSTAT);
......@@ -171,9 +203,23 @@ public class OraMon {
}
public double getBufferCacheHitRatioPercent() throws Throwable {
double conGetsCache = getPerSecondValue("consistent gets from cache");
double dbBlocksCache = getPerSecondValue("db block gets from cache");
double physReadsCache = getPerSecondValue("physical reads cache");
return getBufferCacheHitRatioPercent(null);
}
public double getBufferCacheHitRatioPercent(String pdbName) throws Throwable {
double conGetsCache;
double dbBlocksCache;
double physReadsCache;
if(pdbName == null) {
conGetsCache = getPerSecondValue("consistent gets from cache");
dbBlocksCache = getPerSecondValue("db block gets from cache");
physReadsCache = getPerSecondValue("physical reads cache");
} else {
conGetsCache = colPdbSysStat.getPerSecValue(pdbName + strSeparator + "consistent gets from cache");
dbBlocksCache = colPdbSysStat.getPerSecValue(pdbName + strSeparator + "db block gets from cache");
physReadsCache = colPdbSysStat.getPerSecValue(pdbName + strSeparator + "physical reads cache");
}
if (conGetsCache + dbBlocksCache + physReadsCache == 0) {
return 100;
}
......@@ -189,9 +235,23 @@ public class OraMon {
}
public double getCacheHitRatioPercent() throws Throwable {
double conGets = getPerSecondValue("consistent gets");
double dbBlocks = getPerSecondValue("db block gets");
double physReads = getPerSecondValue("physical reads");
return getCacheHitRatioPercent(null);
}
public double getCacheHitRatioPercent(String pdbName) throws Throwable {
double conGets;
double dbBlocks;
double physReads;
if(pdbName == null) {
conGets = getPerSecondValue("consistent gets");
dbBlocks = getPerSecondValue("db block gets");
physReads = getPerSecondValue("physical reads");
} else {
conGets = colPdbSysStat.getPerSecValue(pdbName + strSeparator + "consistent gets");
dbBlocks = colPdbSysStat.getPerSecValue(pdbName + strSeparator + "db block gets");
physReads = colPdbSysStat.getPerSecValue(pdbName + strSeparator + "physical reads");
}
if (conGets + dbBlocks + physReads == 0) {
return 100;
}
......@@ -206,7 +266,13 @@ public class OraMon {
}
public double getLogicalReadsPerSecond() throws Throwable {
return getLogicalReadsPerSecond(null);
}
public double getLogicalReadsPerSecond(String pdbName) throws Throwable {
if(pdbName == null)
return getPerSecondValue("consistent gets") + getPerSecondValue("db block gets");
else
return colPdbSysStat.getPerSecValue(pdbName + strSeparator + "consistent gets") + colPdbSysStat.getPerSecValue(pdbName + strSeparator + "db block gets");
}
long lastRTns = 0;
......@@ -221,15 +287,24 @@ public class OraMon {
}
public boolean getData() throws Throwable {
return getData(0);
return getData(0, null);
}
public boolean getData(long ageTs) throws Throwable {
return getData(ageTs, null);
}
Lock lock = new ReentrantLock();
Throwable lastEx = null;
public boolean getData(long ageTs) throws Throwable {
//Check age
public boolean getData(long ageTs, String pdbName) throws Throwable {
//Check age (unless pdbName was set for the first time, in that case we need to discard the cached data)
if(getPdbs == false && pdbName != null) {
getPdbs = true;
}
else {
if ((System.nanoTime() - lastFetchTSns) < (ageTs * 1000 * 1000 * 1000)) return false;
}
// Start thread safe
// Try to get a lock
......@@ -283,8 +358,6 @@ public class OraMon {
// Get OS Load
osLoad.update(stmt.executeQuery("select systimestamp, value from V$OSSTAT where stat_name='LOAD'"));
// SYSSTAT and SYS_TIME_MODEL are specific for PDB and CDB/Instance is the total.
// Get DB CPU use time
rset = stmt.executeQuery("select systimestamp, s.value as NIWT, t.value as DBCPU from V$SYSSTAT s, V$SYS_TIME_MODEL t where s.name='non-idle wait time' and t.STAT_NAME='DB CPU'");
rset.next();
......@@ -295,6 +368,22 @@ public class OraMon {
//Get the entire V_$SYSSTAT table from DB
colSysStat.update(stmt.executeQuery("select systimestamp, name, value from V$SYSSTAT"));
//Get PDB specific data if getPDB is set to true
if(getPdbs) {
//CPU
if(colPdbCPU == null) colPdbCPU = new Collector();
rset = stmt.executeQuery("select systimestamp, c.NAME, s.value as NIWT, t.value as DBCPU from V$CON_SYSSTAT s, V$CON_SYS_TIME_MODEL t, V$CONTAINERS c where s.CON_ID=t.CON_ID and s.CON_ID=c.CON_ID and s.name='non-idle wait time' and t.STAT_NAME='DB CPU'");
while(rset.next()) {
colPdbCPU.updateValue(rset.getTimestamp(1), rset.getString(2) + strNiwTime, rset.getLong(3));
colPdbCPU.updateValue(rset.getTimestamp(1), rset.getString(2) + strCpuTime, rset.getLong(4));
}
rset.close();
//SYSSTATS
if(colPdbSysStat == null) colPdbSysStat = new Collector();
colPdbSysStat.update(stmt.executeQuery("select systimestamp, c.NAME || '" + strSeparator + "' || s.name, s.value from V$CON_SYSSTAT s, V$CONTAINERS c where s.CON_ID=c.CON_ID"));
}
stmt.close();
getDataSucess++;
lastFetchTSns = System.nanoTime();
......
......@@ -14,7 +14,36 @@ public class TestRunner {
public static void main(String[] args) throws Throwable {
//runner1();
//test1();
testTns();
//testTns();
testPDB();
}
public static void testPDB() throws Throwable {
OraMon cdb = new OraMon("jdbc:oracle:thin:@//u03634.kap.rsv.se:1526/DB1K12","dbsnmp","dbsnmp"); // CDB
OraMon pdb = new OraMon("jdbc:oracle:thin:@//u03634.kap.rsv.se:1526/DA1K001","dbsnmp","dbsnmp"); // PDB
int times = 5;
while(times-- > 0) {
cdb.getData(0, "DA1K001");
pdb.getData();
System.out.println("PDB CPU: " + pdb.getCPUPercent());
System.out.println("CDB CPU: " + cdb.getCPUPercent());
System.out.println("DA1K001: " + cdb.getCPUPercent(false, "DA1K001"));
System.out.println("DA1K002: " + cdb.getCPUPercent(false, "DA1K002"));
System.out.println("TOTAL : " + (cdb.getCPUPercent(false, "DA1K001") + cdb.getCPUPercent(false, "DA1K002")));
System.out.println("PDB LIO: " + pdb.getLogicalReadsPerSecond());
System.out.println("CDB LIO: " + cdb.getLogicalReadsPerSecond());
System.out.println("DA1K001: " + cdb.getLogicalReadsPerSecond("DA1K001"));
System.out.println("DA1K002: " + cdb.getLogicalReadsPerSecond("DA1K002"));
System.out.println("TOTAL : " + (cdb.getLogicalReadsPerSecond("DA1K001") + cdb.getLogicalReadsPerSecond("DA1K002")));
System.out.println("Sleeping 15s\n");
Thread.sleep(60000);
}
cdb.close();
pdb.close();
}
public static void test1() throws Throwable {
......@@ -42,8 +71,9 @@ public class TestRunner {
//OraMon mon1 = new OraMon("jdbc:oracle:thin:@uvp3dbkappkg:1550:VP1K03","dbsnmp","dbsnmp"); // SID eller Service Name format
//OraMon mon1 = new OraMon("jdbc:oracle:thin:@//u00154.kap.rsv.se:1526/DB1K01","dbsnmp","dbsnmp");
OraMon mon1 = new OraMon("jdbc:oracle:thin:@//u03634.kap.rsv.se:1526/DA1K001","dbsnmp","dbsnmp"); // PDB, CDB är DB1K12
//OraMon mon1 = new OraMon("jdbc:oracle:thin:@//u03634.kap.rsv.se:1526/DA1K001","dbsnmp","dbsnmp"); // PDB, CDB är DB1K12
//OraMon mon1 = new OraMon("jdbc:oracle:thin:@//u03634.kap.rsv.se:1526/DA1K002","dbsnmp","dbsnmp"); // Andra PDB på CDB DB1K12
OraMon mon1 = new OraMon("jdbc:oracle:thin:@//u03634.kap.rsv.se:1526/DB1K12","dbsnmp","dbsnmp"); // PDB, CDB är DB1K12
//OraMon mon2 = new OraMon("jdbc:oracle:thin:@host:port:sid","user","pass"); // SID format
mon1.open();
//mon2.open();
......