Таким образом, ваша распределенная архитектура выглядит примерно так, как показано на рисунке ниже, и вы только что получили от бизнеса требование, чтобы убедиться, что SLA для сообщений, отправляемых Производителем и затем направляющихся в нисходящие системы (потребители), должны быть быстрыми и никогда не медленнее, чем 400 миллисекунд.
Требование говорит:
Задержка сообщения, отправленного Производителем любому из Потребителей, никогда не должна превышать 400 миллисекунд.
Звучит знакомо? Для меня да, и опыт научил меня, что если я хочу защитить SLA в будущем, мне также необходимо автоматизировать тестирование, чтобы не создавать узких мест, которые затем увеличивают задержку сообщений. Но как это сделать? Производители и потребители находятся на разных машинах, а некоторые потребители не написаны на Java. Кроме того, между производителем и потребителями существует Очередь (или веб-служба, или RMI, или ESB, или другой компонент, или что-то еще), поэтому мне не легче тестировать. Ну, все компоненты пишут логи одинаково, так почему бы не использовать логи в качестве данных для тестирования ?
Например, это 2 примера журналов, один из которых отправляет сообщение производителю (идентификатор 1546366), а другой — получателю сообщения (идентификатор 1546366):
Логи производителя
|
1
|
2013-02-19 10:09:05,795 INFO [org.grep4j.demo.input.core.InputCoreMessageSender] (pool-19-thread-9) Input::MessageSender::Message(1546366) Sent Successfully |
Потребительские журналы
|
1
|
2013-02-19 10:09:06,161 INFO [org.grep4j.demo.handler.bean.mdb.SingleDestPacketHandler] (Thread-62314 (HornetQ-client-global-threads-989457197)) Handler::Packet::Message(1546366) Received::PacketId(982336426)::State(NORMAL)::Dest(CONSUMER4, 1)::DataLevel(EVENT, 7)::Op(CREATE, C)::GlobalId(1546366)::Priority(1)::Src(GUI, 1::Ids(EventId=1546366,SFBId=1546366,isBirType=false,inBir=false)) |
Вот как выглядит мой автоматический тест производительности с использованием Grep4j :
|
01
02
03
04
05
06
07
08
09
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
|
package com.gdg.grep4j.demo;import static com.gdg.grep4j.demo.profiles.Profiles.consumer1;import static com.gdg.grep4j.demo.profiles.Profiles.consumer2;import static com.gdg.grep4j.demo.profiles.Profiles.consumer3;import static com.gdg.grep4j.demo.profiles.Profiles.producer;import static com.gdg.grep4j.demo.services.TimeService.extractTime;import static org.grep4j.core.Grep4j.constantExpression;import static org.grep4j.core.Grep4j.grep;import static org.grep4j.core.fluent.Dictionary.on;import static org.hamcrest.CoreMatchers.is;import static org.hamcrest.number.OrderingComparison.lessThan;import static org.junit.Assert.assertThat;import org.grep4j.core.result.GrepResults;import org.testng.annotations.BeforeTest;import org.testng.annotations.Test;@Testpublic class MessageDistributionPerformanceTest { private static final long MAX_ACCETABLE_LATENCY = 400L; private long producerTime = 0; private GrepResults consumersResults; @BeforeTest public void triggerMessageDispatcher() { System.out.println('Producing and firing a Message(1546366) to downstream systems...'); } @BeforeTest public void extractProducerTime() { GrepResults producerResult = grep(constantExpression('Message(1546366) Sent Successfully'), on(producer)); producerTime = extractTime(producerResult.toString()); } @BeforeTest public void grepConsumerLogs() { consumersResults = grep(constantExpression('Message(1546366) Received'), on(consumer1, consumer2, consumer3)); } public void testConsumer1Latency() { long consumer1Time = extractTime(consumersResults.filterOnProfile(consumer1).toString()); assertThat((consumer1Time - producerTime), is(lessThan(MAX_ACCETABLE_LATENCY))); } public void testConsumer2Latency() { long consumer2Time = extractTime(consumersResults.filterOnProfile(consumer2).toString()); assertThat((consumer2Time - producerTime), is(lessThan(MAX_ACCETABLE_LATENCY))); } public void testConsumer3Latency() { long consumer3Time = extractTime(consumersResults.filterOnProfile(consumer3).toString()); assertThat((consumer3Time - producerTime), is(lessThan(MAX_ACCETABLE_LATENCY))); }} |
Профиль — это целевой контекст grep, в моем случае все профили — это удаленные машины (для лучшего понимания профилей см. Страницу Grep4j ).
TimeService — это простой класс обслуживания, извлекающий время из журналов.
|
01
02
03
04
05
06
07
08
09
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
|
package com.gdg.grep4j.demo.services;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.TimeZone;import java.util.regex.Matcher;import java.util.regex.Pattern;public class TimeService { private static final Pattern timePattern = Pattern .compile('([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9]) ([0-9][0-9]|2[0-3]):([0-9][0-9]):([0-9][0-9]),([0-9][0-9][0-9])'); public static long extractTime(String text) { Matcher lm = timePattern.matcher(text); if (lm.find()) { SimpleDateFormat sdf = new SimpleDateFormat( 'yyyy-MM-dd HH:mm:ss,SSS'); sdf.setTimeZone(TimeZone.getTimeZone('UTC')); String inputString = lm.group(); Date date = null; try { date = sdf.parse(inputString); } catch (ParseException e) { e.printStackTrace(); } return date.getTime(); } else { throw new IllegalArgumentException('timePattern not found'); } }} |
В нескольких простых строках кода у меня есть чрезвычайно гибкий тест (я могу проверить все, что было создано в журналах). Полный код: https://github.com/marcocast/grep4j-gdg.git.
Ссылка: Простое тестирование SLA на распределенных компонентах с помощью grep4j от нашего партнера по JCG Марко Кастильего из блога « Удалить дубликаты и исправление дурных имен» .
