Pokazywanie postów oznaczonych etykietą TDI. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą TDI. Pokaż wszystkie posty

poniedziałek, maja 05, 2014

TDI Unit Test extensions for Tibco BW

Have you ever wanted to do unit testing with Tibco BW, modfiy "read-only" global variables, mock calls of database activities etc?

Now you can replace any activity with static data or other process call, transparently to existing process code.

You can create unit test processes, enumerate them, run using OnStartup mode, gather test data. You can integrate your tests with your Continuous Integration infrastructure.

TDI TestUnit extensions for Tibco BW is a must have tool for an agile company.

Grab it for free. File tdi-core.jar should be put into bw/5.x/hotfix/lib folder, tdi-palettes.jar should go into bw / 5.x / lib / palettes.

wtorek, listopada 19, 2013

TDI can measure XML tree creation times per node

New build of TDI in profiler mode measures creation times per XML tree node. Presented time is an average with nanosecond accuracy, with given nesting level in XML tree.


środa, października 31, 2012

TDI4BW

TDI integrates with Tibco BW Engine and sees all executed processes and all data. It gathers basic runtime process statistics, can gather selected data flowing through processes (using XPath selectors called markers) and can gather detailed performance information per activity.
TDI can be integrated with Tibco BW in two ways:
  • TRA mode - modification of .tra file (independent from deployment, any deployed BW component can have TDI enabled; may be performed by IT Operations to analyze problems in production environment or to build BAM solution)
  • OnStartup mode - addition of OnStartup process (must be put into EAR file and deployed with whole project, usually used for analyzing single project during Friendly User Test/Trial Run)

Configuration can be done via params_table.

================================================================================
 Parameter           | Description               
================================================================================
 EXTRACT_NUMBERS^      values: *true,false;    Data extracted from XPath markers 
   is normalized: duplicates are removed, string and numbers representing the
   same values can be converted to numbers; extraction is greedy: q123456789
   will be converted to number 123456789
   
 TDI_CONFIG_FILE      value: path to config.env file with configuration props
   File is read at startup. TDI will also check for config.env file inside
   its jar file.
 
 TSI_ADDRESS          value: URL to Tibco Service Improvement endpoint receiving
   data from TDI, it can be URL in schema  host:port to use default HSQL db,
   it can be Oracle JDBC connection string 'jdbc:oracle:thin:HR/HR@host:1521:XE'
   or Cassandra URL 'cassandra:host:9160' or 'void' (no data upload).
   
 PROFILER^             values:yes,*no;   Flag to enable or disable profiler. 
   Profiler gathers statistics in the form: activityName -> execution time / 
   evaluation time + timestamp of start
   
 LOGGER^               values:yes,*no;    Flag to enabling logging of data from
   WriteToLog and Log4J activities; Data will be put the same way as from marker
   
 IGNORE_ERROR_TEXT^    value:*TDI_IGNORE_ERROR;   TDI sees all errors, both
   handled with error transition and unhandled. Some 'Generate Error' activities
   may be used in logging libraries/projlibs and so they should be ignored. This
   is exact text match - value can be in activity name, XML elements names or
   inside nodes' data.
   
 STALLED_JOB_TIME    value:*300000;  When job runs longer than given time
   it will be marked and reported as hung/stalled.
   
 WORK_INTERVAL       value:*10000;     Time interval between iterative event
   delivery to endpoint gathering data.
   
 PING_TIME           value:*60000;    Time interval between iterative ping event
   delivery to endpoint gathering data. Ping means that Tibco BW component is
   alive.
   
 MARKERS^             value: follow schema MARKER_$Name:$Value, where $Name can
   be string for non-indexed marker and number 1-4 for indexed marker. $Value
   is simple XPath expresion for selecting XML nodes, in which values devops
   are interested to. Example: MARKER_1://orders/orderId. When data matches
   marker expression the exact node value is stored as a marker value and
   also whole message is store in separate object.
 
 SKIP_MK_MESSAGE^     value:true,*false;   Skip gathering whole messages when
   one of its elements matches marker.
   
 CONN_POOL_LIFETIME   value:0-86400000;    Cache connection for given time.
   Zero means that connection pooling is disabled and connection is created
   for every event delivery.
   
-------------------------------------------------------------------------------
   Parameters marked ^ are reloaded in runtime during ping,
   others are loaded once at startup.

   
================================================================================
 File               | Description
================================================================================   
 tdi.jar/auto.cfg     URL for endpoint storing data, see parameter TSI_ADDRESS
 
 tdi.jar/config.env   File for storing configuration

 tdi.jar/bootstrap.sql for initial Oracle database configuration for TDI,
  put ojdbc5.tdi in the same path as tdi.jar
 
 tdi.jar/licence.txt  Licence checked on startup, TDI is free for non-production
   usage

niedziela, lutego 19, 2012

TDI NoSQL

TDI podłączone do kilkuset komponentów Tibco BusinessWorks obsługujących procesy dotykające kilkunastu milionów klientów potrafi dość szybko i skutecznie zapełniać terowego Oracle-a. Regularne czyszczenie tablespace-a 1TB jest uciążliwe, a poza tym szkoda kasowanych danych - za okres 12 miesięcy można by odczytać ciekawe trendy. Do gry wkracza rozwiązanie marketingowo nazwane Long Term NoSQL Storage.


czwartek, stycznia 05, 2012

Opis tabelek TDI

CREATE TABLE "TDI"."EVENTS_TABLE"
  (
    "ID"      NUMBER(*,0), -- identyfikator z sekwencji
                           -- ustawiany przez trigger
    "VERSION" NUMBER(*,0), -- kolumna pod Grailsy
    "HOST"    VARCHAR2(200 BYTE), -- maszyna z agentem
    "REPO"    VARCHAR2(200 BYTE), -- nazwa repozytorium
                                  -- Tibco BW
    "PROC"    VARCHAR2(2000 BYTE), -- nazwa procesu BW
    "CR"      NUMBER(*,0), -- ilość stworzonych procesów
                           -- danego typu od momentu
                           -- startu instancji BW
    "FN"      NUMBER(*,0), -- ilość zakończonych
                           -- procesów danego typu
                           -- od momentu startu 
                           -- instancji BW
    "RN"      NUMBER(*,0), -- ilość aktualnie
                           -- działających procesów
                           -- danego typu
    "FL"      NUMBER(*,0), -- FlowLimit dla danego
                           -- typu procesu
    "TC"      NUMBER(*,0), -- Engine.ThreadCount
    "ST"      NUMBER(*,0), -- czas startu procesu
    "D"       NUMBER(*,0), -- opóźnienie w starcie
                           -- procesu na silniku BW
    "EN"      NUMBER(*,0), -- czas zakończenia procesu
    "WT"      NUMBER(*,0), -- sumaryczny czas spania procesu
    "EC"      NUMBER(*,0), -- error count
    "TYPE"    VARCHAR2(200 BYTE), -- typ komunikatu: 
                                  -- stats, ping, error
    "JTS"     NUMBER(*,0), -- JMSTimestamp jeśli 
                           -- aktywność JMS startuje proces
    "JEXP"    NUMBER(*,0), -- JMSExpiration
    "JDC"     NUMBER(*,0), -- JMSXDeliveryCount
    "METRICS" CLOB, -- pozostałe metryki JMS, WS, inne
    "EM" CLOB, -- error messages
    "ST3M"  NUMBER(*,0), -- czas startu podzielony przez 3m
    "ST30M" NUMBER(*,0), -- czas startu podzielony przez 30m
    "ST4H"  NUMBER(*,0), -- czas startu podzielony przez 4h
    "ST1D"  NUMBER(*,0), -- czas startu podzielony przez 1d
    "MARKERS_DEFS" CLOB, -- definicje markerów (pole wypełniane
                         -- tylko raz, na starcie)
    "MARKERS" CLOB, -- wartości dla markerów
    "MARKERS_MSGS" CLOB, -- całe komunikaty, których
                         -- wybrane pole pasuje do markera
    "MK1" VARCHAR2(2000 BYTE), -- wartość markera 1
    "MK2" VARCHAR2(2000 BYTE), -- wartość markera 2
    "MK3" VARCHAR2(2000 BYTE), -- wartość markera 3
    "MK4" VARCHAR2(2000 BYTE), -- wartość markera 4
    "MK5" VARCHAR2(2000 BYTE), -- wartość markera 5
    "MK6" VARCHAR2(2000 BYTE), -- wartość markera 6
)

CREATE TABLE "TDI"."USAGE_TABLE"
  (
    "ID"      NUMBER(*,0), -- identyfikator z sekwencji
                           -- ustawiany przez trigger
    "VERSION" NUMBER(*,0), -- kolumna pod Grailsy
    "HOST"    VARCHAR2(200 BYTE), -- maszyna z agentem
    "REPO"    VARCHAR2(200 BYTE), -- nazwa repozytorium BW
    "CPU" FLOAT(63), -- zużycie CPU w procentach
    "MEM" FLOAT(63), -- zużycie pamięci w procentach
    "GC" FLOAT(63), -- zużycie CPU przez Garbage Collector
                    -- w procentach
    "ST"    NUMBER(*,0), -- czas zdarzenia pomiaru 
    "ST3M"  NUMBER(*,0), -- czas zdarzenia pomiaru 
                         -- podzielony przez 3m
    "ST30M" NUMBER(*,0), -- czas zdarzenia pomiaru
                         -- podzielony przez 30m
    "ST4H"  NUMBER(*,0), -- czas zdarzenia pomiaru
                         -- podzielony przez 4h
    "ST1D"  NUMBER(*,0) -- czas zdarzenia pomiaru
                        -- podzielony przez 1d
)

sobota, września 03, 2011

TDI obsługuje markery!

Marker to selektor XPath pozwalający wyciągnąć z dowolnego procesu pasujące do selektora dane. Włączając TDI w wielu różnych komponentach wchodzących w interakcję ze sobą i definiując marker przykładowo jako '//orderNumber', możemy w bazie danych zalogować a następnie prześledzić całą historię przepływów dotyczących danego numeru zamówienia (selektor // wyszukuje element, który może być zlokalizowany w dowolnym miejscu drzewa XML).

Jak włączyć TDI? Plik tdi.jar powinien znajdować się w katalogu lib BW lub aplikacji. W pliku tra zmieniamy java.start.class=com.tibco.pe.PEMain na java.start.class=tdi.com.tibco.pe.PEMain (potrzebne do wpięcia się do tego samego interfejsu, z którego korzysta Hawk; TDI nie modyfikuje bajtkodu ani żadnych plików). Markery włączamy w pliku config.env (lub innym zdefiniowanym we właściwości TDI_CONFIG_FILE):
MARKERS=MARKER_ORDERID://orderNumber MARKER_TASKID://SalesTaskId. Dostęp do bazy danych można definiować właściwością TSI_ADDRESS, domyślna wartość to localhost:8192. Oprócz transportu bazodanowego SQL można wybrać Apache HBase i HTTP/SOAP. TDI (Tibco Discrete Instrumentation) to część zbierająca dane, TSI (Tibco Services Improvement) to część zajmująca się analizą, predykcją, heurystycznymi wskazówkami QoS.

Definiując marker //JMSMessageId można stworzyć wkład dla narzędzia Tibcovery i uzyskać dokładną mapę EAI.

Jeszcze parę iteracji i TDI będzie mogło konkurować z Wily Introscope.

piątek, lipca 15, 2011

Co robi Sleep w Tibco BusinessWorks?

Sleep w BW powoduje oddanie wątku wykonującego aktualny proces do puli Engine.ThreadCount. Czas powrotu procesu do działania jest niedeterministyczny, silnik BW szuka pierwszego wolnego wątku z puli, aby przydzielić mu wykonywanie procesu od aktywności następującej po Sleep. Bardziej deterministyczne pauzowanie procesu można osiągnąć przez Java Code Thread.sleep() lub (dla małych wartości) LockSupport.parkNanos().



Kiedy jeszcze nastąpi przełączenie wątku (oprócz aktywności blokujących)? Kiedy wątek silnika w pojedynczym procesie wykona 20 aktywności (Engine.StepCount).

REKLAMA: TDI - najlepszy profiler do Tibco BW, do kupienia u dobrych dostawców usług EAI.

W Windows 7 domyślna rozdzielczość kroku zegara to 15.6ms, ale można ją polepszyć dochodząc do 1ms. Umie to wykorzystać Java 1.7:

public class TimerResolution {
  public final static void main(String[] args) {
    TreeMap<Long,Long> map = new TreeMap<Long,Long>();
    for (int i=0; i < 15000; i++) {
      long t0 = System.currentTimeMillis();
      try {
        LockSupport.parkNanos(1000000);
      }
      catch (Exception e) {}
      long dt = System.currentTimeMillis()-t0;
      map.put(dt, i);   
    }
    int mid = map.size()/2;
    Iterator<Entry<Long, Long> it = map.entrySet().iterator();
    for (int i = 0; i < mid; i++)
      it.next();
    System.out.println("Timer resolution: "+
      it.next().getKey()+" ["+map.size()+"]");
  }
}

Timer resolution: 3 [4]

To samo z System.nanoTime()/1000
i Thread.currentThread().setPriority(Thread.MAX_PRIORITY):

Timer resolution: 995 [255]

niedziela, czerwca 12, 2011

GUI do TDI

sobota, czerwca 11, 2011

TDI mierzy przełączenie wątków w BW



Procesy i wszystkie aktywności Tibco BusinessWorks nie mają jednej puli wątków wykonawczych. Osobne i niezależne wątki tworzone są dla obsługi aktywności: JMS Receiver, JMS Requestor, HTTP/SOAP/Adapter request-reply, Rendezvous, Sleep/Wait. W wątku procesu wykonywane są jedynie dwa rodzaje aktywności: wysyłanie komunikatów JMS i zapytania JDBC. Implikacje są takie, że działającemu procesowi przed wcześniej wymienioną aktywnością może być zabrany wątek wykonawczy. Po zakończeniu aktywności procesowi jest przydzielany pierwszy wolny wątek z puli o rozmiarze Engine.ThreadCount. Za długi czas trwania procesu może być odpowiedzialne przełączanie wątków.
Wywołania WebService-ów obsługuje pula wątków bw.plugin.http.client.ResponseThreadPool o domyślnym rozmiarze 10.

środa, marca 09, 2011

Statystyki z Tibco

Statystyki procesów Tibco są w czasie zbliżonym do rzeczywistego pakowane do bazy danych. Powinien to być Oracle na bardzo silnej maszynie. Dane obrabiane są przez aplikację webową. Parę wykresów dla benchmarku EMS:


Wartości odstające od reszty to procesy z aktywnościami JMSQueueSend. Wysyłanie komunikatów odbywa się równolegle z ich odbieraniem. Wśród dużych wartości można wyodrębnić dwie grupy - bo mamy procesy wysyłające wiadomości 16k i 128k.


Średni czas między wysłaniem komunikatu JMS a odebraniem go przez proces to 100ms.


W różnicy JMSExpiration i czasu zakończenia procesu nie widać nic niepokojącego.



Jeśli tabelkę ze statystyką procesu uzupełnimy o kolumny: czas startu dzielony przez 3 minuty, 30 minut, 4 godziny, 1 doba, na których mamy indeksy to będziemy mogli zrobić szybką analizę po oknach czasowych.