本例介紹Pinpoint告警的相關內容,Pinpoint參考【APM】Pinpoint 安裝部署(一)
Pinpoint Web會定期檢查應用程序的狀態,並在滿足某些預配置條件(規則)的情況下觸發警報。
這些條件(默認情況下)由Web模塊中的后台批處理過程每3分鍾檢查一次(默認情況下),使用的是最后5分鍾的數據。一旦滿足條件,批處理過程就會向注冊到用戶組的用戶發送短信/電子郵件。
本例Pinpoint版本是:1.8.5,下載地址:https://github.com/naver/pinpoint/releases/tag/1.8.5
參考git文檔:https://naver.github.io/pinpoint/alarm.html
參考博客:https://skyao.gitbooks.io/learning-pinpoint/content/alarm/code_implementation.html
Pinpoint告警原理
1、下載源碼,通過源碼解析:
Pinpoint中有一個匹處理類,BatchConfiguration.java,此類會進行批任務處理
1 @Configuration 2 @Conditional(BatchConfiguration.Condition.class) 3 @ImportResource("classpath:/batch/applicationContext-batch-schedule.xml") 4 public class BatchConfiguration{ 5 static class Condition implements ConfigurationCondition { 6 @Override 7 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 8 ...... 9 Resource resource = context.getResourceLoader().getResource("classpath:/batch.properties") 10 ...... 11 final String enable = properties.getProperty("batch.enable"); 12 ...... 13 } 14 } 15 }
Condition中會讀取配置文件batch.properties中的配置項batch.enable,默認是false。因此如果要開啟批處理功能,必須設置batch.enable=true。
2、在Pinpoint中,在批處理任務配置文件(applicationContext-batch-schedule.xml)中,文件路徑為:pinpoint/web/src/main/resources/batch/applicationContext-batch-schedule.xml,可以找到定義的任務
1 <task:scheduled-tasks scheduler="scheduler"> 2 <task:scheduled ref="batchJobLauncher" method="alarmJob" cron="0 0/3 * * * *" /> 3 <task:scheduled ref="batchJobLauncher" method="agentCountJob" cron="0 0 2 * * *" /> 4 <task:scheduled ref="batchJobLauncher" method="flinkCheckJob" cron="0 0/10 * * * *" /> 5 </task:scheduled-tasks> 6 7 <task:scheduler id="scheduler" pool-size="1"/>
配置文件中,定義了執行告警Job的時間。定義了一個線程池大小為1的調度器scheduler
3、在Pinpoint中,在告警任務配置文件(applicationContext-alarmJob.xml)中,文件路徑為:pinpoint/web/src/main/resources/batch/applicationContext-alarmJob.xml,
reader:讀取數據 => 通過用戶配置的規則提供Checker,即異常校驗器。
processor:處理數據 => 用Checker進行校驗,標記異常狀態。
writer:回寫數據 => 判斷Checker是否有異常情況,有則報警。
1 <batch:job id="alarmJob"> 2 <batch:step id="alarmPartitionStep"> 3 <batch:partition step="alarmStep" partitioner="alarmPartitioner"> 4 <batch:handler task-executor="alarmPoolTaskExecutorForPartition" /> 5 </batch:partition> 6 </batch:step> 7 <batch:listeners> 8 <batch:listener ref="jobFailListener"/> 9 </batch:listeners> 10 </batch:job> 11 12 <batch:step id="alarmStep"> 13 <batch:tasklet> 14 <batch:chunk reader="reader" processor="processor" writer="writer" commit-interval="1"/> 15 </batch:tasklet> 16 </batch:step> 17 18 <bean id="alarmPartitioner" class="com.navercorp.pinpoint.web.alarm.AlarmPartitioner"/> 19 <bean id="reader" class="com.navercorp.pinpoint.web.alarm.AlarmReader" scope="step"/> 20 <bean id="processor" class="com.navercorp.pinpoint.web.alarm.AlarmProcessor" scope="step"/> 21 <bean id="writer" class="com.navercorp.pinpoint.web.alarm.AlarmWriter" scope="step"/> 22 23 <task:executor id="alarmPoolTaskExecutorForPartition" pool-size="1" />
4、在回寫數據類中AlarmWriter.java中發現,是通過注入AlarmMessageSender來發送消息
1 public class AlarmWriter implements ItemWriter<AlarmChecker> { 2 3 @Autowired(required = false) 4 private AlarmMessageSender alarmMessageSender = new EmptyMessageSender(); 5 6 @Autowired 7 private AlarmService alarmService; 8 9 ...... 10 11 // 發送消息 12 private void sendAlarmMessage(CheckerResult beforeCheckerResult, AlarmChecker checker) { 13 if (isTurnToSendAlarm(beforeCheckerResult)) { 14 if (checker.isSMSSend()) { 15 alarmMessageSender.sendSms(checker, beforeCheckerResult.getSequenceCount() + 1); 16 } 17 if (checker.isEmailSend()) { 18 alarmMessageSender.sendEmail(checker, beforeCheckerResult.getSequenceCount() + 1); 19 } 20 } 21 22 } 23 24 ...... 25 }
5、在AlarmMessageSender初始化的值是EmptyMessageSender,通過查看EmptyMessageSender發現此類只是一個空的實現,所有這里只要我們自己實現AlarmMessageSender就能發送告警消息
1 public class EmptyMessageSender implements AlarmMessageSender { 2 3 @Override 4 public void sendSms(AlarmChecker checker, int sequenceCount) { 5 } 6 7 @Override 8 public void sendEmail(AlarmChecker checker, int sequenceCount) { 9 } 10 11 }
Pinpoint告警開發
1、下載源碼,導入Idea中。
2、由於查看pom文件,發現源碼編譯構建需要用到Maven3.5,JDK1.8,Java6,Java7,Java8,Java9,在開發環境中安裝好對應的Maven版本,以及配置好JDK版本
下面是pom.xml文件中的內容,需要Maven 3.5,Maven不是3.5可以進行修改
1 <requireMavenVersion> 2 <version>3.5</version> 3 </requireMavenVersion> 4 <requireJavaVersion> 5 <version>1.8</version> 6 </requireJavaVersion> 7 <requireEnvironmentVariable> 8 <variableName>JAVA_HOME</variableName> 9 </requireEnvironmentVariable> 10 <requireEnvironmentVariable> 11 <variableName>JAVA_6_HOME</variableName> 12 </requireEnvironmentVariable> 13 <requireEnvironmentVariable> 14 <variableName>JAVA_7_HOME</variableName> 15 </requireEnvironmentVariable> 16 <requireEnvironmentVariable> 17 <variableName>JAVA_8_HOME</variableName> 18 </requireEnvironmentVariable> 19 <requireEnvironmentVariable> 20 <variableName>JAVA_9_HOME</variableName> 21 </requireEnvironmentVariable>
3、查看依賴,下載依賴jar包(部分依賴可以用相似版本替代),且對pinpoint/pom.xml文件進行修改,是項目能運行打包。
a、修改spotbugs-exclude.xml,位子,此內容有2個地方要替換
1 <!--<excludeFilterFile>${maven.multiModuleProjectDirectory}/spotbugs-exclude.xml</excludeFilterFile>--> 2 <!-- 改為 --> 3 <excludeFilterFile>${basedir}/spotbugs-exclude.xml</excludeFilterFile>
b、插件注釋掉
1 <!--<plugin>--> 2 <!--<groupId>org.apache.maven.plugins</groupId>--> 3 <!--<artifactId>maven-jxr-plugin</artifactId>--> 4 <!--<version>2.5</version>--> 5 <!--<inherited>false</inherited>--> 6 <!--<configuration>--> 7 <!--<aggregate>true</aggregate>--> 8 <!--<inputEncoding>${encoding}</inputEncoding>--> 9 <!--<outputEncoding>${encoding}</outputEncoding>--> 10 <!--<windowTitle>Pinpoint ${project.version} Cross Reference</windowTitle>--> 11 <!--<docTitle>Pinpoint ${project.version} Cross Reference</docTitle>--> 12 <!--</configuration>--> 13 <!--</plugin>-->
c、下載不下來直接注釋掉
1 <!-- 注釋 --> 2 <!--<profile>--> 3 <!--<id>klocwork</id>--> 4 <!--<build>--> 5 <!--<plugins>--> 6 <!--<plugin>--> 7 <!--<groupId>com.klocwork.ps</groupId>--> 8 <!--<artifactId>kwmaven</artifactId>--> 9 <!--<version>2.1.1</version>--> 10 <!--<configuration>--> 11 <!--<buildspec_filename>${KWINJECT_OUT_PATH}</buildspec_filename>--> 12 <!--</configuration>--> 13 <!--<executions>--> 14 <!--<execution>--> 15 <!--<phase>validate</phase>--> 16 <!--<goals>--> 17 <!--<goal>run</goal>--> 18 <!--</goals>--> 19 <!--</execution>--> 20 <!--</executions>--> 21 <!--</plugin>--> 22 23 <!--</plugins>--> 24 <!--</build>--> 25 <!--</profile>-->
d、修改bootsrap-java9.pom文件
1 <!-- <jdk.version>9</jdk.version> --> 2 <!-- 修改為 --> 3 <jdk.version>1.9</jdk.version>
4、實現和配置告警發消息類
為了使用告警功能,必須通過實現 com.navercorp.pinpoint.web.alarm.AlarmMessageSender並注冊為spring managed bean 來實現自己的邏輯以便發送短信和郵件。當告警被觸發時, AlarmMessageSender#sendEmail, 和 AlarmMessageSender#sendSms 方法將被調用。
AlarmMessageSenderImple.java 如下:
1 public class AlarmMessageSenderImple implements AlarmMessageSender { 2 3 private final Logger logger = LoggerFactory.getLogger(this.getClass()); 4 5 @Autowired 6 UserGroupService userGroupService; 7 8 @Override 9 public void sendSms(AlarmChecker checker, int sequenceCount) { 10 11 List<String> receivers = userGroupService.selectPhoneNumberOfMember(checker.getuserGroupId()); 12 logger.info(" =============准備發送消息=============== " + receivers.size()); 13 14 if (receivers.size() == 0) { 15 return; 16 } 17 List<String> smsList = checker.getSmsMessage(); 18 for (String message : smsList) { 19 logger.info("send SMS : {}", message); 20 // TODO Implement logic for sending SMS 21 for (String receiver : receivers) { 22 logger.info("send email receiver : {}", receiver); 23 } 24 } 25 } 26 27 @Override 28 public void sendEmail(AlarmChecker checker, int sequenceCount) { 29 30 List<String> receivers = userGroupService.selectEmailOfMember(checker.getuserGroupId()); 31 logger.info(" ==============准備發送郵件=============== " + receivers.size()); 32 33 if (receivers.size() == 0) { 34 return; 35 } 36 37 String message = checker.getEmailMessage(); 38 logger.info("send email : {}", message); 39 40 // TODO Implement logic for sending email 41 for (String receiver : receivers) { 42 logger.info("send email receiver : {}", receiver); 43 } 44 } 45 }
發郵件方法,可以參考:【Mail】JavaMail介紹及發送郵件(一)
發短信需要對接第三方運營商。
注冊AlarmMessageSenderImple,在applicationContext-batch.xml文件中注冊
1 <bean id="alarmMessageSenderImple" class="com.navercorp.pinpoint.web.alarm.AlarmMessageSenderImple"/>
還在可以發郵件信息做成可配置形式,在batch.properties文件中提供smtp服務器信息和發送者的地址。在AlarmMessageSenderImple中進行使用
1 pinpoint.url= #pinpoint-web server url 2 alarm.mail.server.url= #smtp server address 3 alarm.mail.server.port= #smtp server port 4 alarm.mail.server.username= #username for smtp server authentication 5 alarm.mail.server.password= #password for smtp server authentication 6 alarm.mail.sender.address= #sender's email address 7 8 ex) 9 pinpoint.url=http://pinpoint.com 10 alarm.mail.server.url=stmp.server.com 11 alarm.mail.server.port=587 12 alarm.mail.server.username=pinpoint 13 alarm.mail.server.password=pinpoint 14 alarm.mail.sender.address=pinpoint_operator@pinpoint.com
在AlarmMessageSenderImple時,注入相關參數
1 @Value("#{batchProps['alarm.mail.server.url'] ?: ''}") 2 String host; 3 @Value("#{batchProps['alarm.mail.server.port'] ?: 587}") 4 String port; 5 @Value("#{batchProps['alarm.mail.server.username'] ?: ''}") 6 String username; 7 @Value("#{batchProps['alarm.mail.server.password'] ?: ''}") 8 String password; 9 @Value("#{batchProps['alarm.mail.sender.address'] ?: ''}") 10 String mailfrom;
5、修改配置文件batch.properties
在batch.properties中將batch.enable
標志設置為true,開啟批處理功能
1 batch.enable=true
batch.server.ip
當有多個精確的Web服務器時,可以進行配置以防止並發批處理操作。僅當服務器的IP地址與中設置的值相同時,才執行批處理batch.server.ip
。(將此設置為127.0.0.1將在所有Web服務器中啟動批處理)
1 batch.server.ip=X.X.X.X
6、配置mysql,需要用到MYSQL來存儲用戶信息以告警規則等,設置MYSQL服務器並在jdbc.properties文件中配置連接信息。
在resources/sql中有2個文件,CreateTableStatement-mysql.sql和SpringBatchJobRepositorySchema-mysql.sql,用來創建表。
1 jdbc.driverClassName=com.mysql.jdbc.Driver 2 jdbc.url=jdbc:mysql://localhost:13306/pinpoint?characterEncoding=UTF-8 3 jdbc.username=admin 4 jdbc.password=admin
7、其他
a、可以在單獨的過程中啟動警報批處理 -只需使用Pinpoint-web模塊內的applicationContext-alarmJob.xml文件啟動彈簧批處理作業即可。
b、可以通過修改applicationContext-batch-schedule.xml文件中的cron表達式來更改批處理執行時間
1 <task:scheduled-tasks scheduler="scheduler"> 2 <task:scheduled ref="batchJobLauncher" method="alarmJob" cron="0 0/3 * * * *" /> 3 </task:scheduled-tasks>
c、改善警報批處理性能的方法 -警報批處理設計為可同時運行。如果您有許多注冊了警報的應用程序,則可以通過pool-size
在applicationContext-batch.xml文件中進行修改來增加執行程序的線程池的大小。
1 <task:executor id="poolTaskExecutorForPartition" pool-size="1" />
8、修改配置文件信息,配置Hbase及Zookeeper,參考:【APM】Pinpoint 安裝部署(一),然后使用Maven打包項目,打包后,將pinpoint-web-1.8.5.war,放入tomcat中運行
Pinpoint告警使用
1、打開pinpoint網頁,打開pinpoint配置
2、新增用戶信息
3、新增用戶組
4、添加用戶到用戶組
5、設置告警規則,測試可以使用TOTAL COUNT / 請求總數量超過多少就報警
6、頁面上發起請求,超過請求次數
7、通過后台查看日志,或者是郵箱,可以發現告警已經實現
告警規則
-
SLOW COUNT / 慢請求數
當應用發出的慢請求數量超過配置閾值時觸發。
-
SLOW RATE / 慢請求比例
當應用發出的慢請求百分比超過配置閾值時觸發。
-
ERROR COUNT / 請求失敗數
當應用發出的失敗請求數量超過配置閾值時觸發。
-
ERROR RATE / 請求失敗率
當應用發出的失敗請求百分比超過配置閾值時觸發。
-
TOTAL COUNT / 總數量
當應用發出的所有請求數量超過配置閾值時觸發。
以上規則中,請求是當前應用發送出去的,當前應用是請求的發起者。 以下規則中,請求是發送給當前應用的,當前應用是請求的接收者。
-
SLOW COUNT TO CALLEE / 被調用的慢請求數量
當發送給應用的慢請求數量超過配置閾值時觸發。
-
SLOW RATE TO CALLEE / 被調用的慢請求比例
當發送給應用的慢請求百分比超過配置閾值時觸發。
-
ERROR COUNT TO CALLEE / 被調用的請求錯誤數
當發送給應用的請求失敗數量超過配置閾值時觸發。
-
ERROR RATE TO CALLEE / 被調用的請求錯誤率
當發送給應用的請求失敗百分比超過配置閾值時觸發。
-
TOTAL COUNT TO CALLEE / 被調用的總數量
當發送給應用的所有請求數量超過配置閾值時觸發。
下面兩條規則和請求無關,只涉及到應用的狀態
-
HEAP USAGE RATE / 堆內存使用率
當應用的堆內存使用率超過配置閾值時觸發。
-
JVM CPU USAGE RATE / JVM CPU使用率
當應用的CPU使用率超過配置閾值時觸發。