forked from burakbayramli/books
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchapdeploymonitor.tex
1000 lines (842 loc) · 42.3 KB
/
chapdeploymonitor.tex
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\movetooddpage
\chapter{Sonuç Ortamı} \label{deploymonitor}
\thischapterhas{
\item Sonuç ortamına kod göndermek
\item İşlemde olan bir kurumsal programı kontrol etmek
}
\versal{K}\textsc{urumsal} uygulamızı yazıp, test ettikten sonra, uygulamamızı
işleme açmak için işler kodlarını sonuç ortamına göndermemiz
gerekir. Kitabımızda tavsiye edilen sonuç ortamı, işletim sistemi olarak, Unix
(Linux, Solaris) sistemleridir. O zaman kurumsal uygulamamızı Unix üzerindeki
bir JBoss üzerine göndermek için, bazı yöntemler kullanmamız gerekecektir. Bu
yöntemlere deployment başlığı altında bakacağız.
Kod gönderildikten sonra (ciddi sonuç ortamlarında) diğer bir problem ile karşı
karşıya geliriz. Bir kurumsal uygulamayı sonuç ortamında gerçek kullanıcı yükü
altında işletmek, test ortamında işletmekle aynı değildir. Komut satırından elle
başlattığımız bir program, eğer çökerse ne olacaktır? Modern bir kurumsal
uygulamanın üzerindeki gereklilikler düşünülürse (haftanın 7 günü ve her günün
24 saati ayakta kalmasının beklediğimiz sistemler) onlarca Unix makinasının
oluşturduğu bir küme ortamında, sadece \PVerb!run.sh! ile başlattığımız
servislerin izlenemez, ve takip edilemez bir halde olduğu sonucuna varırız. Bu
sorunu izleme (monitoring) başlığı altında çözeceğiz.
\section{Kod Gönderimi} \label{deploymonitor:deploy}
Bazı seminerlerimde kullandığım bir fiziksel mimari örneği vardır: ``Bu sitenin
kullandığı fiziksel mimari, küme hâlinde çalışan 20 tane Unix makinası
içeriyor'' diyerek bazı donanım istatistiklerini dinleyiciye sunarım. Bunu duyan
katılımcılardan biri bazen şu soruyu sorar: ``Biz 4 makinayı zor idare ediyoruz,
bu adamlar 20 makinayı nasıl idare ediyorlar?''.
Bahsedilen sayı hakikaten büyük bir sayıdır. Fakat örneği verilen türden bir
yapıyı idare eden admin'in kullandığı o ufacık tekniği duyunca, sorunun
cevabının aslında ne kadar basit olduğunu anlarsınız . Meselâ
\PVerb!kitapdemo.sar! adlı Web paketimizi, \PVerb!host1!, \PVerb!host2!, ... ,
\PVerb!host100! olarak isimlendirilmiş 100 tane makinanın
\PVerb!/usr/local/jboss/server/all/deploy! dizini altına kopyalamamız
gerektiğini düşünün (her makinada JBoss'un aynı yere kurulmuş olduğunu farz
ediyoruz). Bu kopyalama işlemini, eğer düzeninizi iyi kurmuşsanız, şu şekilde
yapabilirsiniz (\PVerb!sh! scripting dili ile)
\begin{lstlisting}[language=Java, caption=sendcode.sh]
LIMIT=100
for ((a=1; a <= LIMIT ; a++))
do
scp kitapdemo.sar "remoteuser@host\$a:/usr/local/jboss/server/all/deploy"
done
\end{lstlisting}
Ya da Windows BAT ortamında
\begin{lstlisting}[language=Java, caption=sendcode.bat]
@echo off
FOR /L %%n IN (1,1,100) DO call :copying %%n
goto end:
:copying
scp kitapdemo.sar remoteuser@host%1:/usr/local/jboss/server/all/deploy
:end
\end{lstlisting}
İste bu tek script ile paketimizi 100 makinayı tek seferde kopyalamış
olduk. Peki bu nasıl oldu?
\subsection{SSH ve SCP}
Bir makinadan diğerine hem şifresiz hem de güvenli bir şekilde girip, orada
komut işletmek, ya da oraya dosya kopyalamak için iki program vardır:
\PVerb!ssh! ve \PVerb!scp!. Kullanmak için komut satırından (\PVerb!ssh! için)
\begin{lstlisting}[language=Java, frame=none]
ssh host1 -l remoteuser
\end{lstlisting}
komutunu kullandığınızda \PVerb!host1! adlı makinaya \PVerb!remoteuser!
kullanıcısı üzerinden login etmiş olursunuz. Ya da uzak makinada bir komut
işletip sonucunu kendi makinanıza almak isterseniz (meselâ ikinci makinada
listeleme komutu olan \PVerb!ls! işletelim), şunu yaparız
\begin{lstlisting}[language=Java, frame=none]
ssh host1 -l remoteuser ls
\end{lstlisting}
Eğer uzak makinaya bir dosya kopyalamak istersek
\begin{lstlisting}[language=Java, frame=none]
scp file.txt remoteuser@host1:/tmp
\end{lstlisting}
Bu komut ile uzaktaki makinaya {\em sanki yerel dizinlerimiz arasında dosya
kopyalıyormuş kadar rahat} bir şekilde bir dosya kopyalayabiliyoruz. Girişte
bahsettiğimiz basit teknik işte budur. \PVerb!ssh! ve \PVerb!scp! bir kez
kurulduktan sonra, uzaktaki makina, yerel makinanızın bir uzantısı hâline
gelir. Bir makinayı uzaktan idare etmek demek, ya bir dosya değişimi, ya da bir
komut işletmek demek olduğu için, bu iki programı kullanarak uzaktaki bir
makinada yapamayacağımız şey yoktur.
\begin{figure}[!hbp]
\center{
\scalebox{0.40}{
\includegraphics{./images/scp.eps}
}
}
\end{figure}
\subsubsection{Şifresiz Kullanımı Kurmak}
Eğer \PVerb!ssh!'i hiçbir ek ayar yapmadan kullanırsanız, (ilk kurduğumuz
haliyle) her kullanışınızda size bir şifre sorulacaktır. Aynı şekilde
\PVerb!scp! komutu da böyle davranır. Fakat, biz meselâ yüz tane makina için
arka arkaya \PVerb!scp! ya da \PVerb!ssh! kullanmamız gerekeceği için, şifre
isteme işlemini iptal edip, güvenlik kontrolünü kullanıcıya sorulmayan {\em
başka bir şekilde} yapmamız gerekiyor. Bu yöntem de, açık / gizli (public /
private) anahtarlar kullanarak yapılan güvenlik kontrolüdür.
Windows üzerinde \PVerb!ssh! ve \PVerb!scp!'nin işler kodlarını kurmayı,
\ref{install:sshscp} bölümünde bulabilirsiniz. Linux üzerinde \PVerb!ssh! ve \PVerb!scp!
genellikle otomatik olarak kurulur, eğer kurulmamışsa, Linux kurulum
disklerinizde bu programı bulabilirsiniz, ya da admin'inize bu programları
kurdurabilirsiniz.
Açık / gizli anahtar kurulumunu yapmak için şunları yapın: İlk önce kod
gönderimi ya da uzaktan idareyi yapan yerel makinamızı tanıtan bir gizli
anahtar, bir de açık anahtar üretmemiz gerekiyor.
\begin{lstlisting}[language=Java, frame=none]
\$ ssh-keygen -t rsa
\end{lstlisting}
Sorulan sorular için hiç cevap girmeden ENTER'e basarak geçin. Bu bittikten
sonra, \PVerb!\$HOME/.ssh/! dizininiz icinde 2 dosya göreceksiniz. Bu dosyalar
\PVerb!id_rsa.pub! ve \PVerb!id_rsa! dosyaları olacaktır. \PVerb!HOME!
değişkeninin nerede olduğunu komut satırından Unix/Cygwin'de \PVerb!echo \$HOME!
ile öğrenebilirsiniz. Windows'da dosyaların nereye yazıldığı OpenSSH tarafından
zaten \PVerb!ssh-keygen! sonunda size bildirilecektir.
Biraz önce üretilen dosyalardan \PVerb!id_rsa!, gizli anahtarınızdır. Dosya
\PVerb!id_rsa.pub! ise açık anahtarınızdır. Şimdi, \PVerb!id_rsa.pub!
kayıdındaki açık anahtarı, uzaktan erişeceğiniz servis bilgisayarına FTP ya da
\PVerb!scp! ile gönderin (\PVerb!scp! kullanırsanız, -şimdilik- şifre girmeniz
gerekecek tabii ki). Sonra, uzaktaki bilgisayardaki kullanacağınız kullanıcı
hesabına girin, hesabın üst seviyesinde \PVerb!\$HOME/.ssh/! dizini altına
\PVerb!id_rsa.pub! kayıdını bırakın. Sonra, servis sisteminde
\begin{lstlisting}[language=Java, frame=none]
cat > \$HOME/.ssh/id_rsa.pub >> authorized_keys
\end{lstlisting}
komutunu calıştırın. Kuruluş işlemi bundan ibarettir. Bu son işlemden sonra
artık uzaktan işlettiğiniz \PVerb!ssh! ve \PVerb!scp! işlemleri şifresiz bir
şekilde işinizi yapmanıza izin verecektir.
Açık anahtarımızı servis makinasına eklemek için, Unix \PVerb!cat! komutu ile
\PVerb!>>! işlecini kullandığımıza dikkat edelim. Bu demektir ki, birden fazla
\PVerb!.pub! dosyasına tek bir \PVerb!authorized_keys! dosyasına ekleyebiliriz
(ve birden fazla kullanıcıyı desteklebilmek için bunu yapmamız gerekir). Böylece
aynı makinaya erişen birden fazla erişen kişi, \textbf{aynı} servis makinasına
ve aynı kullanıcıya değişik açık anahtarlar ile erişebilir.
Eğer \PVerb!ssh! kullanımınızda problem çıkarsa (probleme göre) şunları
yapabilirsiniz:
\begin{itemize}
\item Servis tarafındaki \PVerb!authorized_keys! dosyasının güvenliğinin açık
olmaması gerekir. Eğer dosyanın Unix bazında güvenliği çok açıksa,
\PVerb!sshd! bağlanmaya çalışan \PVerb!ssh! ya da \PVerb!scp! komutunu bir
şifre girmeye zorlayacaktır. \PVerb!authorized_keys! dosyasının yeterince
kapalı hale getirmek için
\begin{lstlisting}[language=Java, frame=none]
chmod 600 authorized_keys
\end{lstlisting}
ve bir üst seviyedeki \PVerb!.ssh! dizini üzerinde
\begin{lstlisting}[language=Java, frame=none]
chmod 700 .ssh/
\end{lstlisting}
komutlarını kullanmak gerekebilir.
\item SSH bağlanamama durumu var ise, problem sunucu bilgisayarında
\PVerb!sshd! programının işlemesi olabilir. \PVerb!ps -eaf | grep sshd! ile
bunu kontrol edebilirsiniz.
\item Bağlanan bilgisayarlarda Cygwin'e özel bir problem (Windows'da)
şudur. Cygwin ssh programı (OpenSSH), gizli anahtarın üzerindeki erişim
haklarının "kullanıcıya özel" olmasını istiyor. Bu normal tabii çünkü bu
anahtar gizli, ve her kullanıcı tarafından okunamaması lâzımdır. Hata şöyle
olacaktır:
\begin{lstlisting}[language=Java, frame=none]
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/cygdrive/h/.ssh/id_rsa' are too open.
It is recommended that your private key files are NOT accessible
by others.
This private key will be ignored.
\end{lstlisting}
Hiç problem degil (diye düşünüyoruz) \PVerb!chmod! kullanırsak iş biter
(bölüm \ref{unix:tools:files:chmod}). Tek problem, Windows ve Unix'in
erişim hakları yöntemlerinin birbiri ile uyuşmamasıdır. \PVerb!chmod!'u
çalıştırdığınızda, komut bir şey yapmış gibi geri gelecek, fakat dosyada
bir değişiklik olmayacaktır. Unix dosya haklarının Cygwin'de ``simule''
edilmesi için, \PVerb!cygwin.bat! içine (\PVerb!CYGWIN/bin/! altında) şunu
eklemek lazımdır.
\begin{lstlisting}[language=Java, frame=none]
set CYGWIN=tty ntea
\end{lstlisting}
Bundan sonra
\begin{lstlisting}[language=Java, frame=none]
chmod 0600 id_rsa
\end{lstlisting}
komutu düzgün işleyecektir.
\end{itemize}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section[Uygulama İşleyişini Kontrol Etmek][UYGULAMA İŞLEYİŞİNİ KONTROL ETMEK]{Uygulama İşleyişini Kontrol Etmek}
Kurumsal uygulamamızı oluşturan servis programlarımızın uzun süre ayakta
kalmasını ve işlem yapabilmesini isteriz. Eğer işletim sistemi hatası, donanım
pürüzleri gibi hatalar yüzünden servis süreçlerinde çökme olursa, sektörde
yaygın bir metot çökmüş olan servisin otomatik olarak ayağa kaldırılmasıdır. Bu
işi yapan en ünlü ticari program olan AutoSys, çöken bir programı tekrar
başlatmak, çökme birkaç kez tekrar ederse olursa belli bir eşik değerinden sonra
tekrar başlatmayı bırakıp durumu sorumlu bir kimseye e-mail ile bildirmek, ya da
zamanlı (scheduled) bir şekilde belli zamanlarda bir programı işletmek gibi
önemli görevleri yerine getirebilir.
Kitabımızda bedava / açık yazılım yelpazesinden bulunup kullanılabilen çözümleri
tavsiye ettiğimiz için, ticari bir ürün olan AutoSys yerine bizim yazdığımız iki
Perl script'ini tavsiye edeceğiz. Bu script'ler AutoSys'in süreç izleme
özelliğini taşıyan ufak programlar olacaklardır. AutoSys'in zamanlı çalıştırma
özellikleri yerine de, Unix \PVerb!cron! programını (bölüm \ref{unix:cron})
kullanabilirsiniz.
\subsection{Blok Eden Servis Script'leri} %%%%%%%%%%%%%%%%%%%%%%%%%%%
Blok eden servis programlarından kastımız, başlangıç komutu verilince kendini ön
plana alan türden servis programlarıdır. Bu tür programların çökme durumunu
kontrol etmek istiyorsak, servisi başlatmak için başlatıcı programı
(\PVerb!run.sh! gibi) elle başlatmak yerine, bir takip edici program üzerinden
``başlattırtmamız'' gerekmektedir. Bu kontrollü başlatımdan sonra, eğer kontrol
edilen program herhangi bir sebeple geri gelirse, kontrol eden program bir çökme
durumu olduğunu algılayabilecektir.
Alttaki \PVerb!jobRunner.pl! adlı Perl script'ini bu amaçla kullanabiliriz.
\begin{lstlisting}[language=Perl, caption=jobRunner.pl]
#!/usr/bin/perl
use Net::SMTP;
\$argCount=\$#ARGV + 1;
die "Usage: perl t.pl <maxRestartCount> <wait> " .
"<jobname> <progname>\n" if (\$argCount != 4);
\$maxRestartCount = \$ARGV[0];
\$wait = \$ARGV[1];
\$jobName = \$ARGV[2];
\$jobProg = \$ARGV[3];
print "\$wait";
# run the program
\$code = system(\$jobProg);
# if first run fails, we come here
\$restartCount = 0;
while (1) {
\$restartCount++;
if (\$restartCount == 3) {
print "Cannot restart any more... Exiting\n";
alert(\$jobName);
exit(-1);
} else {
print "Exiting with code \$code\n";
print "Waiting for cleanup \n";
sleep(\$wait);
print \$code . "... restarting \n";
\$code = system(\$jobProg);
}
}
sub alert(\$){
my \$jobName = shift;
my \$from = '[email protected]';
my \$to = '[email protected]';
my \$subject = "Process \$jobName Failed";
\$smtp = Net::SMTP->new('mail.company.com');
\$smtp->mail(\$from);
\$smtp->to(\$to);
\$smtp->data();
\$smtp->datasend("To: \$to\n");
\$smtp->datasend("Subject: \$subject\n");
\$smtp->datasend("Tried to restart \$jobName \$maxRestartCount times\n");
\$smtp->datasend("It Failed\n");
\$smtp->dataend();
\$smtp->quit;
}
\end{lstlisting}
\PVerb!jobRunner.pl! programının seçeneklerini komut satırından \PVerb!perl
jobRunner.pl! komutunu işleterek görebiliriz. Bu seçeneklerin açıklaması
şöyledir:
\begin{itemize}
\item \textbf{maxRestartCount}: \PVerb!jobRunner.pl!'in başlatmış olduğu ve
kontrol ettiği program çökünce, en fazla kaç {\em sefer daha} tekrar ayağa
kaldırılması gerektiğini kontrol eder. Eğer bir program
\PVerb!maxRestartCount! kere çökmüş ise, \PVerb!jobRunner.pl! belirtilen
admin kişisine bir e-mail ile durumu bildirecek, ve programın
\PVerb!maxRestartCount! kere çökmüş olduğunu haber verecektir. Program bir
daha başlatılmayacaktır.
\item \textbf{wait}: Çökme ile tekrar başlatılma arasında kaç saniye
beklenmesi gerektiğini belirler.
\item \textbf{jobname}: Programı başlatan kişinin atadığı bir isim. Herhangi
bir kelime olabilir.
\item \textbf{progname}: İşletilecek programın başlangıç komutu. JBoss
örneğinde bu \PVerb!sh run.sh! olacaktır. Tüm path (full path) burada
belirtilir.
\end{itemize}
\PVerb!jobRunner.pl! kontrolünde meselâ JBoss başlatmak için tipik bir kullanım
şöyle olabilir.
\begin{lstlisting}[language=Java, frame=none]
perl jobRunner.pl 3 10 JBossServer1 ``sh /usr/local/jboss/bin/run.sh''
\end{lstlisting}
\textbf{Not}: Bu şekilde çalıştırdığımız servis programını durdurmak için,
programın kendisini değil, onu başlatan ve idare eden \PVerb!jobRunner.pl!
programını öldürmemiz gerektiğini unutmayalım. Başlatıcı programı görmek için
Unix üzerinde \PVerb!ps -eaf | grep perl! ile alacağımız listede, bu Perl
script'ini \PVerb!kill -9! ile durdurabiliriz. Unix süreç kontrolü ve
listelemesi için \ref{unix:process} bölümüne bakabiliriz.
\subsection{Deamon Programları}
Apache gibi ``başlangıç programları kendini arka plana (background process)
atan'' türden programlar için, kontrolü bir {\em port bazlı} yapabilen idare bir
script'ini kullanmamız gerekiyor. Çünkü kendini arka plana atan script'ler,
başlatıcı çağırdıktan sonra hemen geri dönerler ve bu da \PVerb!jobRunner.pl!
gibi bir program için aldatıcı olacaktır (programın çökmüş olduğunu
zannedecektir). O zaman, kontrol edilen programın çöküp çökmediğini önplandan
geri gelip gelmemek değil, belli bir port üzerinde dinleyici olup olmadığını
anlayarak kontrol edebiliriz. Sistemde bir port'un kullanılma durumunu
\PVerb!netstat! ile kontrol edebiliriz. \PVerb!netstat! hakkında ayrıntılı detay
için \ref{unix:netstat} bölümüne bakabilirsiniz.
\begin{lstlisting}[language=Perl, caption=deamonRunner.pl]
#!/usr/bin/perl
use Net::SMTP;
\$argCount=\$#ARGV + 1;
die "Usage: perl t.pl <maxRestartCount> <wait> " .
"<port> <jobname> <progname>\n" if (\$argCount != 5);
\$maxRestartCount = \$ARGV[0];
\$wait = \$ARGV[1];
\$port = \$ARGV[2];
\$jobName = \$ARGV[3];
\$jobProg = \$ARGV[4];
# if first run fails, we come here
\$restartCount = 0;
while (1) {
if (\$restartCount == \$maxRestartCount) {
print "Cannot restart any more... Exiting\n";
alert(\$jobName);
exit(-1);
} else {
sleep(\$wait);
print \$code . "... checking port \$port \n";
@netstatout = `netstat -ano`;
foreach \$line(@netstatout) {
@tokens = split(':|\s',\$line);
if (\$tokens[7] =~ /\$port/) {
\$found = 1;
}
}
if (\$found != 1) {
\$restartCount++;
\$code = system(\$jobProg);
}
}
}
sub alert(\$){
my \$jobName = shift;
my \$from = '[email protected]';
my \$to = `[email protected]';
my \$subject = "Process \$jobName Failed";
\$smtp = Net::SMTP->new('mail.company.com');
\$smtp->mail(\$from);
\$smtp->to(\$to);
\$smtp->data();
\$smtp->datasend("To: \$to\n");
\$smtp->datasend("Subject: \$subject\n");
\$smtp->datasend("Tried to restart \$jobName \$maxRestartCount times\n");
\$smtp->datasend("It Failed\n");
\$smtp->dataend();
\$smtp->quit;
}
\end{lstlisting}
\PVerb!deamonRunner.pl! seçenekleri \PVerb!jobRunner.pl! ile neredeyse aynıdır,
tek fark, belli aralıklarla kontrol edilmesi gereken bir port parametresidir. Bu
parametrenin üzerinde dinleyici olma durumu \PVerb!netstat -ano! ile belli
aralıklarla kontrol eden script, eğer o port dinlenmiyorsa, dinleyen programın
çöktüğünü kabul edilecek ve tekrar başlatmak için gerekli komutu
uygulayacaktır. Tipik bir \PVerb!deamonRunner.pl! kullanımı şöyledir:
\begin{lstlisting}[language=Java, frame=none]
perl jobRunner.pl 3 10 80 Apache1 ``/usr/local/apache/bin/apachectl start''
\end{lstlisting}
Bu komuta göre, Apache programının varlığı port 80'e bakılarak her 10 saniyede
bir kontrol edilecek, eğer program çökmüş ise tekrar başlatılacaktır. Bu tekrar
başlatma işlemi en fazla 3 kere tekrarlanacak, 3 kereden sonra tekrar başlatmak
denenmeyecek, durum görevli admin kişisine bir e-mail ile bildirilecektir.
\section[Uygulamadan İstatistik Almak][UYGULAMADAN İSTATİSTİK ALMAK]{Uygulamadan İstatistik Almak}
Sürecimizin işleyiş durumunu kontrol eden yukarıdaki script'ler sayesinde, eğer
izlenen bir süreç çökmüş ise, onu tekrar başlatarak sistemin devamını sağlamak
mümkün olacaktır. İşleyiş hakkında daha detaylı bilgiler istersek, bu bilgileri
uygulama içinden paylaşmamız, bir şekilde dış dünyaya afişe etmemiz ve belli
aralıklarla bu bilgileri güncellememiz gerekmektedir. İşleyiş bilgilerini dış
dünyaya afişe edersek, bu bilgileri (tercihen) görsel bir idare programı
sayesinde izleyebilir, bir ekranda gösterebilir, hattâ ilginç olan şartlar
üzerinde alarm şartları tanımlamak suretiyle yetkili bir admin kişisinin
(şartlar ihlâl edildiğinde) e-mail ile bilgilendirilmesini sağlayabiliriz.
J2EE dünyasında bir uygulamanın iç istatistiklerini paylaşmak ve idare
bilgilerini dış dünyaya göstermek için JMX teknolojisi kullanılır. JMX,
\textbf{J}ava \textbf{M}anagement E\textbf{X}tensions (Java İdare Uzantıları)
cümlesinin kısaltılmışıdır. Bu teknoloji sayesinde bir uygulama, belli bir
standarta uyan bir MBean class'ını (bir bean) dış dünyaya gösterebilir. Aslında
JMX ile MBean afişe etmek, dağıtık nesne teknolojisi ile nesnemizi JVM dışından
erişime açmaya çok benzer, ama iki fark (üstünlük) vardır: Bir: JMX ile
dışarıdan bağlanan müşteri, MBean'lerinizin metotlarını dinamik şekilde
gezebilir. İki: JMX teknolojisi, idare amaçlı teknolojiler arasında piyasada
tutmuş bir teknolojidir, bu yüzden birçok ticari ve açık yazılım ürün
istatistiklerini JMX üzerinde paylaşmak amacıyla hazır MBean'ler yazıp
ürünlerine dahil etmişlerdir. Böylece uygulamamız, bu hazır MBean'leri oldukları
gibi alıp, kendi MBean'lerimiz ile beraber yanyana afişe edebilir. Hibernate
\PVerb!org.hibernate.jmx.StatisticsService! MBean'i bu şekilde hazır yazılmış
bir istatistik nesnesidir.
\subsection{JMX ile MBean Yazmak} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{deploymonitor:jmx}
Dış dünyaya bilgi vermek için, Kendi MBean'imizi yazmayı öğrenmemiz
gerekiyor. İki türlü MBean stili vardır, statik MBean ve dinamik MBean. Statik
MBean ile uygulama sırasında {\em ismi} değişmeyecek parametreleri
sunabiliriz. Meselâ uygulamamızın önbellek büyüklüğü, veri tabanı bağlantı
havuzundaki aktif bağlantılar, ya da sistemdeki aktif kullanıcı sayısı gibi
parametrelerin ne olduğu önceden bilinen parametrelerdir, ve uygulama sırasında,
ya da makinadan makinaya değişmezler.
Dinamik MBean'ler ise, işleyiş anında ya da makinadan makinaya değişebilecek
parametreleri afişe etmek için kullanılır. Meselâ uygulamamızın üzerinde koştuğu
makinanın disklerinin kullanım ölçüleri (IO read/write) gibi bir istatistik
dinamik MBean gerektirir, çünkü uygulamamız kurulduktan ve kullanıma başladıktan
sonra bir makinaya ek disk, ek işlemci gibi donanım uzantıları yapmak mümkündür;
Eğer istatistik paylaşma yöntemimiz sabit disk isimleri üzerinden bilgi topluyor
(ve JMX ile paylaşıyor) olsaydı, yeni disk'ler eklendikten sonra bu ek birimler
dış dünya tarafından görülemez olacaktı.
\subsubsection{Statik MBean}
Statik MBean tanımlamak için sonu \PVerb!MBean! ile biten bir interface, ve bu
interface'i gerçekleştiren bir class gerekecektir. Örnek olarak, bir Web
uygulamasına yapılan toplam ziyaretleri gösteren bir MBean yazalım: Esas
değerleri taşıyan sayaç, \PVerb!VisitCounter! adlı bir Singleton class'ı olsun.
\begin{lstlisting}[language=Java, frame=none]
public class VisitCounter {
private static VisitCounter instance = null;
private VisitCounter() { }
public static VisitCounter instance() {
if (instance == null) {
instance = new VisitCounter();
}
return instance;
}
public int visitCount = 0;
public synchronized void incrementCount() {
visitCount++;
}
public int getVisitCount() { return visitCount; }
}
\end{lstlisting}
Sayaç nesnesi üzerinde arttırma işlemini çağıran bir Web filtresi
olacaktır. Ayrıca Java Servlet belirtimine (specification) göre bir Filtre, Web
isteği başlamadan önce ve sonra işletilebilen bir kod parçasıdır. Biz filtremizi
her \PVerb!*.do! çağrısı için aktif olacak şekilde ayarlayalım.
\begin{lstlisting}[language=Java, caption=VisitCounterFilter.java]
public class VisitCounterFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException,
ServletException
{
chain.doFilter(request, response);
VisitCounter.instance().incrementCount();
}
public void destroy() { }
}
\end{lstlisting}
\begin{lstlisting}[language=Java, caption=web.xml]
<filter>
<filter-name>VisitCounterFilter</filter-name>
<filter-class>
org.mycompany.kitapdemo.util.VisitCounterFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>VisitCounterFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
\end{lstlisting}
Sayaç değerlerini dış dünyaya göstermek için, JMX üzerinden kullanabileceğimiz
bir statik MBean yazalım.
\begin{lstlisting}[language=Java, frame=none]
public interface UserStatMBean {
public int getTotalRequestCount();
}
\end{lstlisting}
\begin{lstlisting}[language=Java, frame=none]
public class UserStat implements UserStatMBean {
VisitCounter counter = null;
public UserStat() {
counter = VisitCounter.instance();
}
public int getTotalRequestCount() {
return counter.getVisitCount();
}
}
\end{lstlisting}
Bu MBean'i bir MBeanServer\PVerb!MBeanServer! ile kayıt ettirdiğimiz zaman, dış
dünya \PVerb!totalRequestCount! adlı istatistiği görebilecektir. MBean kayıt
ettirmek için, projenin başlangıç kodları işlettiği yerde (Web uygulamaları için
\PVerb!AppStartup! class'ı) şu şekilde kodlar işletmemiz gerekir.
\begin{lstlisting}[language=Java, frame=none]
public class AppStartup implements AppStartupMBean {
public void start() throws Exception {
...
MBeanServer mbeanServer =
(MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);
LocateRegistry.createRegistry(new Integer(jmxPort).intValue());
UserStat userStat = new UserStat();
ObjectName userStatName = new ObjectName("UserStat:type=UserStat");
mbeanServer.registerMBean(userStat, userStatName);
...
}
}
\end{lstlisting}
Çağrı \PVerb!findMBeanServer! ile JBoss'un \PVerb!MBeanServer!'ına erişmiş
oluyoruz. Bu server, MBean'lerin kayıt edildiği ve merkezi bir giriş noktası
sağlayan noktadır. Eğer yeni bir \PVerb!MBeanServer! yaratmak istesek,
\begin{lstlisting}[language=Java, frame=none]
MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer();
\end{lstlisting}
kullanırdık. Metot \PVerb!findMBeanServer! kullanmakla, JBoss'un içinde olan tüm
diğer MBean'lerin de kayıt ediliği merkezi noktayı almış oluyoruz.
JBoss'un kontrol ettiği MBean'leri görmek için, tarayıcınızdan
\PVerb!/jmx-console! adresine gidebilirsiniz. Şekil
\ref{deploymonitor:jmx:jmxconsole} üzerinde görüldüğü gibi \PVerb!UserStat! adlı
yeni MBean'imiz diğer MBean'ler yanında servis'e eklenmiştir. MBean
bağlantısının üzerine tıklayarak içindeki öğe (attribute) değerlerini
görebiliriz.
\begin{figure}[!hbp]
\center{
\scalebox{0.45}{
\includegraphics{./images/jmxconsole_mbean.eps}
}
}
\caption{\label{deploymonitor:jmx:jmxconsole} UserStat MBean'i JmxConsole'da}
\end{figure}
\subsubsection{Dinamik MBean}
Öğeleri değişken yapıda olan MBean yazmak için, statik MBean teknolojisini
kullanamayız. Burada dinamik MBean'ler imdadımıza yetişiyor. Dinamik MBean
yazmak için genellikle kullanılan düzen (pattern), değişken öğeleri, eklenip
çıkarmasına izin verdiği ve anahtar bazlı veri tutabildiği için bir
\PVerb!HashMap! üzerinde tutmaktır. İşlem anında öğe olması istenen değerler,
dinamik bir şekilde \PVerb!HashMap!'e anahtar olarak verilir.
Bu \PVerb!HashMap!'i JMX üzerinden dış dünyaya göstermek için, MBean içinde
anında bir dönüşüm yapmamız gerekmektedir. Bu dönüşüm, \PVerb!HashMap! anahtar
(key) değerini MBean öğe ismine, \PVerb!HashMap! değerini ise MBean öğe değeri
hâline getirmelidir. Bu dönüşüm örneğini \PVerb!StrutsHibPerformance! projesi
altındaki \PVerb!org.mycompany.kitapdemo.service.OsStatistics! MBean class'ı
üzerinde görüyoruz.
Bu kodda, \PVerb!HashMap! üzerinden dinamik MBean yaratmak için kullanılan kod
parçası (``dinamik kısım'' comment'leri altında listelenen bölüm) oldukça
basmakalıp kodlardır. Bu kodları, dinamiklik eklemek istediğimiz diğer bir
MBean'e olduğu gibi ekleyebilir, ya da tekrar kullanımı (reusability) arttırmak
amacıyla, dinamiklik kodlarını bir üst class içinde tutup MBean'imizden miras
alabiliriz.
\PVerb!OsStatistics! class'ının ihtiyacı olan değerler, işletim sisteminde
gelmektedir. Bu değerler mikroişlemci kullanım yüzdeleri, ne kadar boş bellek
olduğu gibi işletim sisteminin takip ettiği bilgilerdir, ve komut satırında
bunları görmek için \PVerb!vmstat! komutunu kullanıyoruz. \PVerb!OsStatistics!,
\PVerb!vmstat!'in çıktısına erişmek için \PVerb!Runtime.getRuntime().exec()!
metotu ile \PVerb!vmstat!'i işletmekte, ve geri gelen metin bazlı çıktıyı
tarayarak içinden ilgilendiği değerleri çekip çıkarmaktadır. \PVerb!vmstat!
hakkında detayları \ref{perf:stats:vmstat} bölümünde bulabilirsiniz.
Dinamik MBean'imiz JBoss'a gönderildikten ve ilk değerlerini topladıktan sonra,
\PVerb!/jmx-console! ekranından Şekil \ref{deploymonitor:jmx:osstatistics}
üzerindeki gibi gözükecektir.
\begin{figure}[!hbp]
\center{
\scalebox{0.55}{
\includegraphics{./images/jmxconsole_mbean_osstatistics.eps}
}
}
\caption{\label{deploymonitor:jmx:osstatistics} Dinamik MBean Ekranı}
\end{figure}
Görüldüğü gibi, \PVerb!mem_cache!, \PVerb!mem_swpd! gibi değerler, direk
\PVerb!vmstat! çıktısından gelmektedir. \PVerb!mem_swpd!, \PVerb!swpd! öğesinin
başına \PVerb!mem_! eklenmek suretiyle yaratılmıştır. Öğelerin başına
\PVerb!mem! eklenmesinin sebebi, ileride \PVerb!OsStatistics! MBean'ine
\PVerb!iostat! gibi bir Unix komutunun çıktısını da eklersek, parametrelerin
birbirine karışmaması içindir.
\PVerb!OsStatistics! kodlarında belli aralıklarla istatistik değerlerinin
güncellenmesi için \PVerb!OsStatistics! içinde olan bir Thread mevcuttur. Bu
Thread'i \PVerb!OsStatictics! nesnesini kayıt ettiğimizde başlatmamız gerekir.
Bunun için uygulama başlangıç kodları içinde (\PVerb!StrutsHibPerformance!
projesi için \PVerb!AppStartup!) \PVerb!osStatistics.startThread()! metotunu
çağırmamız yeterlidir. Başlangıç kodlarının tamamı şöyle gözükür.
\begin{lstlisting}[language=Java, frame=none]
mbeanServer = ...
OsStatistics stats = new OsStatistics();
stats.startThread();
ObjectName name = new ObjectName("OsStatistics:type=OsStatistics");
mbeanServer.registerMBean(stats, name);
\end{lstlisting}
İstatistik değerlerinde, alınma stili olarak \PVerb!UserStat! ile
\PVerb!OsStatistics! arasında bir fark vardır. \PVerb!UserStat!, kendine yapılan
tüm \PVerb!get! çağrılarını başka bir merkezi nesneye aktararak (delegate)
gerçek değerlerin ``o başka yerde'' güncellenmesini
bekliyordu. \PVerb!OsStatistics! ise, kendi değerlerini kendi toplamakta, kendi
işlemekte ve kendi muhafaza etmektedir. Bu fark, iki değişik MBean güncelleme
yöntemini sahneye çıkartması için böyle hazırlanmıştır, ve MBean'lerin
dinamikliği ya da statikliği ile bir alâkası yoktur. Statik bir MBean üzerinde
de değerleri toplayan, işleyen ve muhafaza eden kodlar yazabilirsiniz.
Hazır yazılmış açık yazılım ya da ticari paketlerin MBean'lerini paylaşmak için
o paketlerin belgelerine bakınız. Meselâ Hibernate belgelerinde Hibernate
istatistik MBean'ini paylaşmak için şunların yapılması söylenmiştir.
\begin{lstlisting}[language=Java, frame=none]
mbeanServer = ....
Hashtable tb = new Hashtable();
tb.put("type", "statistics");
tb.put("sessionFactory", "kitapdemo");
ObjectName on = new ObjectName("hibernate", tb);
StatisticsService hibstats = new StatisticsService();
hibstats.setSessionFactory(HibernateSession.getSessionFactory());
mbeanServer.registerMBean(hibstats, on);
\end{lstlisting}
Tüm bu paylasımları yapan örnek \PVerb!AppStartup! kodlarını,
\PVerb!StrutsHibPerformance! projesinde bulabilirsiniz.
\subsection{JmxMonitor} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
MBean değerlerini \PVerb!jmx-console! üzerinden göstermek bir yararlı bir gözlem
yöntemidir. Fakat gerçek dünyada işlemekte olan bir sistemde, bize sunulan
istatistiklere sadece çıplak gözle bakmaktan daha fazla yeteneklere ihtiyacımız
vardır. Düşünelim ki, \PVerb!OsStatistics!'den gelen makinamının kullanılmayan
bellek kapasitesi (\PVerb!mem_free!) belli bir değer altına düşerse,
haberimizin olmasını istiyoruz. Ya da, statik MBean örneği olarak yazdığımız
\PVerb!UserStat! nesnesindeki \PVerb!totalRequestCount!, belli bir değeri
geçtiğinde bir alarm durumu olmalı ve admin e-mail ile haberdar edilmelidir. Bu
tür izleme işlemlerini nasıl yapacağız?
JmxMonitor\footnote{http://jmxmonitor.sourceforge.net} açık yazılım projesi, bu
tür ihtiyaçları karşılamak için yazılmıştır. Eğer bir uygulamada afişe edilmiş
MBean'ler var ise, bu MBean'ler üzerindeki her öğe için, JmxMonitor'de bu öğeyi
gözleyen, ve kullanıcının tanımladığı bir ve ya daha fazla eşik değerini
(threshold) ya da eşitlik şartlarına uyan durumları üzerinde bir alarm şartı
tanımlayabiliriz. Alarm şartları ortaya çıkarsa JmxMonitor e-mail ve HTML
önyüzden durumu admin'e bildirilecektir (JmxMonitor kullanıcısının admin
görevlisi olduğunu farz ediyoruz).
JmxMonitor kodları içine hiçbir MBean isminin gömülmesi (hardcode)
gerekmez. JmxMonitor, JMX teknolojisinin Java Reflection benzeri dinamik keşif
özelliğini kullanarak, önce bir \PVerb!MBeanServer! üzerindeki tüm MBean'leri
alır daha sonra bu MBean'lerin tüm ögelerini dinamik olarak keşfeder. MBean ve
öğe listesi kullanıcıya sunulur ve kullanıcı, öğelerin arasından
ilgilendiklerini seçerek üzerlerinde eşik ya da eşitlik şartları tanımlar.
Bu potansiyel alarm şartları ana ekran üzerinde listelenir, ve ileri bir
zamanda, eğer uyan bir eşitlik ya da geçilen bir eşik şartı olursa, ana ekranda
bu alarm yanıp sönmeye başlayacaktır. Ayrıca admin'e e-mail ile durum
bildirilir.
JmxMonitor Web bazlı bir uygulamadır. Web uygulamasının içinden
(\PVerb!JmxMonitorStartup!) başlatılan ve alarm değerlerini kontrol eden bir
Thread, belli aralıklarla sürekli kontrol yapıyor olacaktıor . Ayrıca JmxMonitor
Adaptor düzenini (pattern) kullanarak, istatistik toplamak için kullandığı
bağlantı teknolojisini değiştirmesi de mümkündür. Meselâ paket içinden çıkan
adaptör \PVerb!JmxFacadeJdk15! class'ıdır, fakat JmxMonitor'u uzatmak isteyen
bir programcı, soket üzerinden bilgi toplayan bir adaptör yazabilir. Bu socket
adaptörü, servis tarafından yine socket üzerinden bilgi afişe eden bir makina,
port ikilisine bağlanacak, ve beklediği format'taki değerleri alarak admin'e
eşik ve eşitlik seçimi için sunacaktır. Kendi yazdığınız (custom) adaptörün
\PVerb!JmxFacade! interface'ini gerçekleştirmesi gerekmektedir. Buna göre
her adaptörün;
\begin{enumerate}
\item Verilen makina ve port ikilisine bağlanması mümkün olmalıdır
(\PVerb!connect)!
\item İstatistik sunan servisteki tüm ``ana birimler'' ve bu birimler ``alt
birimlerinin'' listesi alınabilir olmalıdır (\PVerb!retrieveAllObjectNames!)
\item Her ölçümün ``gerçek değerini'' almak mümkün olmalıdır
\PVerb!getLatestValue!)
\end{enumerate}
Altta bir adaptörün sahip olması gereken metotlar gözükmektedir. Her adaptöre
uymayan (üstteki metotlar haricinde) metotlardan bazıları, şartlara göre boş
bırakılabilir.
\begin{lstlisting}[language=Java, frame=none]
public interface JmxFacade {
public Machine getMachine();
public void connect(Machine machine) ..
public Map retrieveAllObjectNames() ..
public String getLatestValue(ObjectName name, String attribute) ..
public void refreshValues() ..
}
\end{lstlisting}
\subsubsection{Servis Tarafı}
JmxMonitor'un \PVerb!JmxFacadeAdaptor15! adaptörü ile bir \PVerb!MBeanServer!'a
erişebilmesi için, o servisin JMX MBean'lerini RMI üzerinden sunması
gerekir. MX4J paketi bu tür bir RMI köprüsünü sunmaktadır. Kullanmak için
\PVerb!AppStartup! içinde bulduğumuz ya da yenisini yarattığımız
\PVerb!MBeanServer! üzerinde bu köprünün nasıl kullanılacağını belirtmemiz
gerekecektir.
\begin{lstlisting}[language=Java, frame=none]
public class AppStartup implements AppStartupMBean {
public void start() throws Exception {
...
mbeanServer = ... // MBeanServer'ı al ya da yarat
...
final String localRmiRegistryHost = "localhost";
final String localRmiRegistryPort = "42004";
final String jmxHost = "localhost";
final String jmxPort = "44334";
final String jmxUrl = "/kitapdemo";
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi://"
+
localRmiRegistryHost
+
":"
+
localRmiRegistryPort
+
"/jndi/rmi://"
+
jmxHost
+
":"
+
jmxPort
+
jmxUrl);
(JMXConnectorServerFactory.
newJMXConnectorServer(url,null,mbeanServer)).start();
...
...
\end{lstlisting}
Bu başlatım komutu ile bizim atadığımız bir RMI URL'i olan bir JMX servisi
yaratmış oluyoruz. Uzaktan bağlanmak isteyenler JMX RMI çağrısını şöyle bir
URL'i oluşturarak gerçekleştireceklerdir:
\begin{lstlisting}[language=XML, frame=none]
service:jmx:rmi://localhost:42004/jndi/rmi://localhost:44334/kitapdemo
\end{lstlisting}
Bu URL'in işleyip işlemediğini anlamak için en çabuk test şudur: JDK 1.5 içinde
paketten çıkan JConsole adında bir uygulama mevcuttur. Bu uygulama, aynı
JmxMonitor gibi RMI üzerinden dinamik olarak MBean'leri keşfeder ve gösterir
(fakat JmxMonitor gibi alarm şartları koymanıza izin vermez). Bu uygulamayı
\PVerb!JDK_1_5/bin/jconsole! komutunu kullanarak başlatabiliriz. İlk çıkan bağlantı
diyalog kutusunda, \PVerb!Advanced! tab'ine giderek, üstte görülen URL'i (tabii
servisimizi de başlattıktan sonra) gireriz. Şekil
\ref{deploymonitor:jmxmonitor:jconsole} üzerindeki ekran görülecektir.
\begin{figure}[!hbp]
\center{
\scalebox{0.55}{
\includegraphics{./images/jconsole.eps}
}
}
\caption{\label{deploymonitor:jmxmonitor:jconsole} JConsole}
\end{figure}
Dikkat edersek, uygulamamızdan afişe ettiğimiz \PVerb!UserStat!,
\PVerb!OsStatistics! ve Hibernate istatikleri dinamik olarak keşfedilmiş ve
listelenmiştir.
\subsubsection{JmxMonitor Kurmak}
JmxMonitor, altyapı olarak kitabımızda sunulan \PVerb!StrutsHibxx! projeleri ile
aynı teknik mimariye sahiptir. Bu sebeple indirmesi, kurulması için yapılması
gerekenler, \ref{install:samples:web} bölümündekiler ile aynıdır. Ek olarak,
başlangıç verilerini yüklemek için \PVerb!JMXMONITOR/src/sql/init_data.sql!
script'ini MySQL (ya da diğer) veri tabanınız üzerinde işletmeniz gereklidir.
Bundan sonra, JBoss servisinizi başlatın ve \PVerb!localhost:8080/jmxmonitor!
adresini ziyaret edin. JmxMonitor ile bir \PVerb!MBeanServer!'a bağlanmak için,
o servisin makina ismi ve port numarasına girmemiz gerekiyor. Bu alanlar için
örnek bazı değerler Şekil \ref{deploymonitor:jmxmonitor:main} üzerindeki gibi
gözükecektir.
\begin{figure}[!hbp]
\center{
\scalebox{0.55}{
\includegraphics{./images/jmxmonitor_1.eps}
}
}
\caption{\label{deploymonitor:jmxmonitor:main} Giriş Ekranı}
\end{figure}
Alanlar için girilmesi gereken değerleri şöyle bulmamız gerekir: Bir
\PVerb!MBeanServer!'a bir RMI köprüsü uyguladığımızda (daha önce
\PVerb!AppStartup! içinde örneğini gösterdiğimiz gibi), şu parametreleri
kullanmıştık
\begin{lstlisting}[language=Java, frame=none]
final String localRmiRegistryHost = "localhost";
final String localRmiRegistryPort = "42004";
final String jmxHost = "localhost";
final String jmxPort = "44334";
final String jmxUrl = "/kitapdemo";
\end{lstlisting}
Bu parametrelerden \PVerb!jmxUrl!, JmxMonitor'ün URL alanına, \PVerb!jmxPort!,
port alanına, \PVerb!jmxHost!'un ise host alanına girilmesi gerekmektedir. Bu
değerleri girip, \PVerb!Add Machine! düğmesine tıklarsak, JmxMonitor bu servisi
listesine ekleyecektir (Şekil \ref{deploymonitor:jmxmonitor:servisadded}).
\begin{figure}[!hbp]
\center{
\scalebox{0.55}{
\includegraphics{./images/jmxmonitor_2.eps}
}
}
\caption{\label{deploymonitor:jmxmonitor:servisadded} Servis Eklendi}
\end{figure}
Listelenen bir servis üzerine tıklarsak, JmxMonitor servise RMI üzerinden
bağlanmaya çalışacak, ve bir sonraki ekranda (Şekil
\ref{deploymonitor:jmxmonitor:mbeanlist}) bu servisin tüm MBean'lerinin
listesini bize sunacaktır.
\begin{figure}[!hbp]
\center{
\scalebox{0.55}{
\includegraphics{./images/jmxmonitor_3.eps}
}
}
\caption{\label{deploymonitor:jmxmonitor:mbeanlist} MBean Listesi}
\end{figure}
Aynı JConsole örneğinde olduğu gibi, kendi yazmış olduğumuz MBean'leri de bu
ekranda görmemiz mümkündür. Bu MBean'lerden biri için bir alarm şartı tanımlamak
için, meselâ \PVerb!OsStatistics! MBean'inindeki bir öğe için, ilk önce öğelerin
listesini görmemiz gerekiyor. Öğe listesini almak için
\PVerb!OsStatistics! bağlantısını tıklamamız lâzım.
\begin{figure}[!hbp]
\center{
\scalebox{0.55}{
\includegraphics{./images/jmxmonitor_4.eps}
}
}
\caption{\label{deploymonitor:jmxmonitor:attrlist} MBean İçindeki Öğeler}
\end{figure}
Şekil \ref{deploymonitor:jmxmonitor:attrlist} üzerinde tıklamadan sonra tüm
öğeleri görüyoruz. Bu öğelerden biri üstünde bir alarm şartı yaratmak istersek,
öğenin üzerindke tıklamamız gerekecek. Örnek olarak \PVerb!OsStatistics!
altındaki \PVerb!mem_free! öğesi üzerinde alarm yaratalım, tıklamadan sonra,
Şekil \ref{deploymonitor:jmxmonitor:alarmadd} üzerindeki ekranı görürüz.
\begin{figure}[!hbp]
\center{
\scalebox{0.55}{
\includegraphics{./images/jmxmonitor_5.eps}
}
}
\caption{\label{deploymonitor:jmxmonitor:alarmadd} Alarm Ekleme Ekranı}
\end{figure}
Bu ekranda alarmın \PVerb!mem_free! gerçek değeri 640000 altında düşerse, bir
alarm oluşmasını istiyoruz. O zaman \PVerb!Comparator! yâni karşılaştırıcı
olarak \PVerb!<! işaretini seçeriz, ve değer olarak 640000 değerini
\PVerb!Threshold! yâni eşik değeri kutusuna gireriz. Alarm eklendikten sonra
Şekil \ref{deploymonitor:jmxmonitor:alarmadded} üzerinde görulen ekrana
geliriz. Eklenmiş alarmı silmek için, alarmın yanındaki \PVerb!Delete!
bağlantısına tıklayabilirsiniz.
\begin{figure}[!hbp]
\center{
\scalebox{0.55}{
\includegraphics{./images/jmxmonitor_6.eps}
}
}
\caption{\label{deploymonitor:jmxmonitor:alarmadded} Alarm Eklendi}
\end{figure}
Bu şekilde devam ederek birden fazla alarm eklememiz mümkündür. Alarm eklememiz
bitince, ana sayfaya dönebiliriz. Ana sayfaya dönünce eklediğimiz alarmların
sayfanın altında listelendiğini göreceğiz (Şekil
\ref{deploymonitor:jmxmonitor:mainwithalarm}).
\begin{figure}[!hbp]
\center{
\scalebox{0.55}{
\includegraphics{./images/jmxmonitor_7.eps}
}
}
\caption{\label{deploymonitor:jmxmonitor:mainwithalarm} Ana Sayfaya Dönüş -
Alarm Gösteriliyor}
\end{figure}
Artık yapmamız gereken tek işlem, izlemekte olduğumuz makina ve port ikilisi
üzerinde yapılacak izleme/gözetlemeyi işlemini aktif hâle getirmektir. Böylece
JmxMonitor, üzerinde alarm olan öğelerin en son değerlerini periyodik bir
şekilde alarak, eşik veya eşitlik şartlarına uyup uyulmadığını kontrol
edebilecektir. Gözetlemeyi aktif hâle getirmek için, makina ve port ikilisi
yanındaki \PVerb!Active! seçeneğine tıklarız. Aktif hâle getirdiğimiz birimin
işareti, yeşile dönecektir (Şekil \ref{deploymonitor:jmxmonitor:activated}); Bu
renk, o makina ve port'un izlenmeye başladığına bir işarettir. Eğer izlemeyi
durdurmak istiyorsak, \PVerb!DeActivate! seçeneğini kullanabiliriz.
\begin{figure}[!hbp]
\center{
\scalebox{0.55}{
\includegraphics{./images/jmxmonitor_8.eps}
}
}
\caption{\label{deploymonitor:jmxmonitor:activated} Aktif Olan bir
Makina/Port İkilisi}
\end{figure}