Таким образом, ваша распределенная архитектура выглядит примерно так, как показано на рисунке ниже, и вы только что получили от бизнеса требование, чтобы убедиться, что 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; @Test public 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 Марко Кастильего из блога « Удалить дубликаты и исправление дурных имен» .