目录

0.跟本文相关的面试题

​编辑

1.查看JVM进程:

2.Linux查看进程的线程信息

(1). ps指令:

(2). pstree指令

(3). top指令

(4)top查看CPU使用率(重要)

3.查看JVM 的gc信息

(1) 第一种方式

(2) 第二种方式

4.查看设置JVM参数:

(1).查看JVM所有参数:

(2).查看JVM单一参数:

(3).设置堆转储文件:

5.K8s集群环境

6.FGC效果实现:

1.实现FGC效果

2.怎样防止出现FGC?

7. jmeter并发压力测试

1.线程组设置:

2.Http Request

3.Http Header Manager

4.Response Code断言

5.结果查看:

6. 聚合报告:

5.JVM FGC查询

8.几点性能测试思路

1.性能测试4点想法:

2.简述:

参考文章:


0.跟本文相关的面试题

JVM参数设置:

1.查看JVM进程:

C:\Users\ThinkPad>jps
33360 Launcher
4532
18696 MainClientBootStrap
21864 Launcher
18380 MainServerBootStrap
19212 Jps

2.Linux查看进程的线程信息

参考文章:Linux查看进程的线程信息_慕城南风的博客-CSDN博客_linux查看线程

(1). ps指令:

在ps命令中,“-T”选项可以查看线程信息。下面的命令列出了由进程号为<pid>的进程中的所有线程。

ps -T -p <pid>

SID”栏表示线程ID,而“CMD”栏则显示了线程名称。

[root@zhihuiyingxiao-dev-68499-04i2g ~]# ps -T -p 20754PID  SPID TTY          TIME CMD
20754 20754 ?        00:00:00 java
20754 20755 ?        00:00:17 java
20754 20756 ?        00:00:30 java
20754 20757 ?        00:00:30 java
20754 20759 ?        00:02:11 java
20754 20760 ?        00:00:00 java
20754 20761 ?        00:00:02 java
20754 20762 ?        00:00:00 java
20754 20774 ?        00:02:13 java
20754 20800 ?        00:15:19 java
20754 20801 ?        00:17:50 java
20754 20802 ?        00:03:39 java
20754 20803 ?        00:00:07 java
20754 20804 ?        00:00:00 java
20754 20805 ?        00:00:11 java
20754 20806 ?        00:01:07 java
20754 20807 ?        00:00:01 java
20754 20808 ?        00:15:17 java
20754 20809 ?        00:00:12 java
20754 20810 ?        00:00:02 java
20754 20811 ?        00:01:04 java
..................................

(2). pstree指令

// 打印所有进程及其线程
pstree -p
// 打印某个进程的线程数
pstree -p {pid} | wc -l

(3). top指令

top命令可以实时显示各个线程情况。要在top输出中开启线程查看,请调用top命令的“-H”选项,该选项会列出所有Linux线程。在top运行时,你也可以通过按“H”键将线程查看模式切换为开或关。

加了-H参数后,top的每一行就不是显示一个进程,而是一个线程。 

top -H

要让top输出某个特定进程<pid>并检查该进程内运行的线程状况:

top -H -p <pid>

(4)top查看CPU使用率(重要)

参看下面这篇文章:

linux下用top命令查看cpu利用率超过100%_huangshanchun的博客-CSDN博客_top命令查看cpu使用率

下图中我们看到了什么?CPU使用率达到176.4%+51.8%+......???不要害怕,这是所有CPU的使用率加起来得到的值。

运行top后按大键盘1看看,可以显示每个cpu的使用率,top里显示的是把所有使用率加起来。

按下1后可以看到我的机器的CPU是16核的。%Cpu0,%Cpu1 ---> %Cpu15。

这里我们也可以查看一下CPU信息:在命令行里输入:

cat /proc/cpuinfo

3.查看JVM 的gc信息

(1) 第一种方式

(2) 第二种方式

参考文章:JVM查看gc情况_本本的香菜的博客-CSDN博客_jvm查看gc

jstat -gcutil pid interval(ms)

S0: 新生代中Survivor space 0区已使用空间的百分比

S1: 新生代中Survivor space 1区已使用空间的百分比
E: 新生代已使用空间的百分比
O: 老年代已使用空间的百分比
M: 方法区已使用空间的百分比

YGC: 从应用程序启动到当前,发生Yang GC 的次数

YGCT: 从应用程序启动到当前,Yang GC所用的时间【单位秒】

FGC: 从应用程序启动到当前,发生Full GC的次数

FGCT: 从应用程序启动到当前,Full GC所用的时间

GCT: 从应用程序启动到当前,用于垃圾回收的总时间【单位秒】

4.查看设置JVM参数:

(1).查看JVM所有参数:

jinfo pid
C:\Users\ThinkPad>jinfo 18380
Attaching to process ID 18380, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.291-b10
Java System Properties:java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.291-b10
sun.boot.library.path = C:\Program Files\Java\jdk1.8.0_291\jre\bin
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = ;
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
sun.os.patch.level =
sun.java.launcher = SUN_STANDARD
user.script =
user.country = CN
user.dir = H:\eclipse-workspace\netty-learning
java.vm.specification.name = Java Virtual Machine Specification
java.runtime.version = 1.8.0_291-b10
java.awt.graphicsenv = sun.awt.Win32GraphicsEnvironment
os.arch = amd64
java.endorsed.dirs = C:\Program Files\Java\jdk1.8.0_291\jre\lib\endorsed
line.separator =java.io.tmpdir = C:\Users\ThinkPad\AppData\Local\Temp\
java.vm.specification.vendor = Oracle Corporation
user.variant =
os.name = Windows 10
sun.jnu.encoding = GBK
java.library.path = C:\Program Files\Java\jdk1.8.0_291\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\MySQL\MySQL Server 8.0\bin\;F:\java\apache-maven-3.8.4\bin;C:\Program Files\Git\cmd;C:\Program Files\Java\jdk1.8.0_291\bin;C:\Program Files\Java\jdk1.8.0_291\jre\bin;F:\Program Files\nodejs\;C:\ProgramData\chocolatey\bin;C:\Users\ThinkPad\AppData\Local\Programs\Python\Python39\Scripts\;C:\Users\ThinkPad\AppData\Local\Programs\Python\Python39\;C:\Program Files\MySQL\MySQL Shell 8.0\bin\;C:\Users\ThinkPad\AppData\Local\Microsoft\WindowsApps;;C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.4\bin;;C:\Users\ThinkPad\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\ThinkPad\AppData\Roaming\npm;.
sun.nio.ch.bugLevel =
java.specification.name = Java Platform API Specification
java.class.version = 52.0
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
os.version = 10.0
user.home = C:\Users\ThinkPad
user.timezone = Asia/Shanghai
java.awt.printerjob = sun.awt.windows.WPrinterJob
file.encoding = UTF-8
java.specification.version = 1.8
user.name = ThinkPad
java.class.path = C:\Program Files\Java\jdk1.8.0_291\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\rt.jar;H:\eclipse-workspace\netty-learning\target\classes;F:\java\maven-repo\io\netty\netty-all\4.1.20.Final\netty-all-4.1.20.Final.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.3.1\lib\idea_rt.jar
java.vm.specification.version = 1.8
sun.arch.data.model = 64
sun.java.command = com.bruce.dubboLearn.provider.MainServerBootStrap
java.home = C:\Program Files\Java\jdk1.8.0_291\jre
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.windows.WToolkit
java.vm.info = mixed mode
java.version = 1.8.0_291
java.ext.dirs = C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
sun.boot.class.path = C:\Program Files\Java\jdk1.8.0_291\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\rt.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\sunrsasign.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_291\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_291\jre\classes
java.vendor = Oracle Corporation
file.separator = \
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64VM Flags:
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=266338304 -XX:MaxHeapSize=4229955584 -XX:MaxNewSize=1409810432 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=88604672 -XX:OldSize=177733632 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.3.1\lib\idea_rt.jar=50717:C:\Program Files\JetBrains\IntelliJ IDEA 2021.3.1\bin -Dfile.encoding=UTF-8

(2).查看JVM单一参数:

#jinfo -flag MaxHeapSize 18380-XX:MaxHeapSize=4229955584

(3).设置堆转储文件:

除了可以设置在内存溢出的时候进行堆转储,还可以设置在发生FUll GC的时候进行堆转储。

https://www.jianshu.com/p/0088673d8f0e

5.K8s集群环境

在k8s集群环境下,Pod内存资源是怎样分配的?堆内存占多少呢?

假设Pod有2G的内存资源,如果不设置JVM堆内存大小,那么JVM堆的默认大小是Pod资源的 1/4,也就是说如果Pod内存资源是2G,那么JVM堆大小是500M左右;如果Pod是4G,那么JVM堆大小是1G。

Pod内存资源是2G,如果将JVM堆大小设置为1G,那么程序是启动不了的,因为Pod作为一个虚拟机,并不是所有的内存资源都可以给JVM使用的。

[root@shuziyingxiao-prod-05912-hpi30 ~]# kubectl exec -it wit-crm-58f7bb9b75-dcqjk -n wit - -- /bin/sh
/ #
/ # jps
8 app.jar
11085 Jps
/ #
/ # jinfo -flag MaxHeapSize 8
-XX:MaxHeapSize=536870912
/ #
/ # jstat -gcutil 8 2000S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   47.92   0.00  69.32  84.04  87.84  81.24   9816   70.244    10    5.398   75.64347.92   0.00  69.83  84.04  87.84  81.24   9816   70.244    10    5.398   75.64347.92   0.00  69.85  84.04  87.84  81.24   9816   70.244    10    5.398   75.64347.92   0.00  71.56  84.04  87.84  81.24   9816   70.244    10    5.398   75.64347.92   0.00  71.72  84.04  87.84  81.24   9816   70.244    10    5.398   75.64347.92   0.00  71.73  84.04  87.84  81.24   9816   70.244    10    5.398   75.64347.92   0.00  71.82  84.04  87.84  81.24   9816   70.244    10    5.398   75.64347.92   0.00  73.33  84.04  87.84  81.24   9816   70.244    10    5.398   75.64347.92   0.00  73.69  84.04  87.84  81.24   9816   70.244    10    5.398   75.64347.92   0.00  73.70  84.04  87.84  81.24   9816   70.244    10    5.398   75.64347.92   0.00  73.90  84.04  87.84  81.24   9816   70.244    10    5.398   75.643

6.FGC效果实现:

1.实现FGC效果

怎样写代码,实现FGC的效果呢?

这里给出一个例子:

package com.example.demo.controller;import com.example.demo.util.CreateUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("hello")
public class TestController {@GetMapping("world")public String getResponse(){Object[] objects = new Object[600*1024];for (int i=0; i< 600*1024 ; i++){objects[i] = new Object();}
//        CreateUtil.add();System.out.println("hello, world, bruce!");return "hello, world - 20220505!";}
}

new一个足够大的数组,然后用new object填充,每次请求都是这样的操作。

然后打开jmeter,1000个并发线程去访问上面的API

产生FGC:

2.怎样防止出现FGC?

增加JVM堆内存,继续观察FGC情况

java -Xms1024M -Xmx1024M ...........

7. jmeter并发压力测试

1.线程组设置:

2.Http Request

3.Http Header Manager

4.Response Code断言

5.结果查看:

察看结果数,列出每个请求结果。

6. 聚合报告:

展示统计数据:

5.JVM FGC查询

在jmeter压力测试下,FGC的情况如下(不同JVM堆内存情况下,肯定是不同的)

# jinfo -flag MaxHeapSize 8
-XX:MaxHeapSize=536870912
/ #
/ # jstat -gcutil 8 200099.79   0.00  53.20  77.92  93.02  89.91   2699   26.561    19   10.513   37.0740.00   1.32  44.46  82.09  93.02  89.91   2706   26.757    19   10.513   37.269
.................................................................................0.00  99.76   4.63  95.18  93.02  89.91   2756   27.520    19   10.513   38.0320.00  25.46   0.00  74.81  93.02  89.91   2762   27.716    20   11.057   38.7732.08   0.00  27.42  74.86  93.02  89.91   2769   27.825    20   11.057   38.8822.08   0.00  91.13  74.89  93.02  89.91   2775   27.925    20   11.057   38.982
.................................................................................71.88   0.00  11.92  95.90  93.02  89.91   2897   29.400    20   11.057   40.45747.41   0.00   6.89  74.85  93.02  89.91   2901   29.517    21   11.619   41.136
.................................................................................
100.00   0.00  48.90  83.38  93.02  89.91   2949   30.187    21   11.619   41.8060.00   2.08  93.24  89.58  93.02  89.91   2956   30.352    21   11.619   41.97099.81   0.00   0.00  97.09  93.02  89.91   2963   30.521    22   11.619   42.139
.................................................................................99.45   0.00  32.35  84.58  93.02  89.91   3005   31.117    22   12.218   43.33536.08   0.00 100.00  87.78  93.02  89.91   3011   31.194    22   12.218   43.4110.00  27.15   0.00  98.47  93.02  89.91   3018   31.370    23   12.218   43.588
.................................................................................0.00  43.18  42.41  91.09  93.02  89.91   3066   31.986    23   12.804   44.79054.94   0.00  45.68  74.82  93.02  89.91   3071   32.132    24   13.350   45.48210.42   0.00  38.28  77.59  93.02  89.91   3079   32.228    24   13.350   45.578
.................................................................................0.00   6.25  87.94  94.80  93.02  89.91   3162   33.351    24   13.350   46.70199.25 100.00 100.00 100.00  93.02  89.91   3167   33.507    25   13.350   46.8580.00  11.11   4.60  75.91  93.02  89.91   3169   33.532    25   13.911   47.443
.................................................................................0.00  12.50  43.05  96.73  93.02  89.91   3263   34.767    25   13.911   48.67899.25 100.00 100.00 100.00  93.02  89.91   3268   34.859    26   13.911   48.77145.14   0.00  25.03  77.36  93.02  89.91   3273   35.003    26   14.471   49.47444.21   0.00  61.38  82.77  93.02  89.91   3279   35.223    26   14.471   49.6950.69   0.00  48.51  91.25  93.02  89.91   3285   35.307    26   14.471   49.778

8.几点性能测试思路

1.性能测试4点想法:

  1. 微服务系统里面包含多个微服务,有些用户请求可能经过多个微服务处理,在做性能测试的时候,可以使用skywalking微服务调用链路追踪工具,看看哪个微服务响应慢,然后去提升这个微服务的性能。
  2. 提升微服务性能的时候,要想办法提高每个实例的性能,就像我们前几天讨论的,先采用最简单的方式,就是增加JVM堆内存,减少FGC频率。不能简单的增加这个微服务的实例数量,毕竟提升每个实例性能,比简单的增加实例数量消耗的资源要少,不然的话,服务器资源迟早不够用。
  3. 性能测试的时候,会不会发生内存溢出这样的问题,怎么抓这样的问题? 可以通过增加JVM启动参数的方式,在发生内存溢出的时候,生成堆转储文件,我们可以对这个堆转储文件进行分析。
  4. .对于系统承载不了的请求,要用sentinel做限流 熔断 降级

2.简述:

  1. 使用skywalking监控相应慢的微服务,并对其进行优化
  2. 优化微服务的时候,要以优化单实例性能为主,减少实例数量,避免过度消耗服务器资源
  3. 内存溢出监控
  4. sentinel限流熔断降级

参考文章:

如何查看Linux的内存使用率 - Hackerman - 博客园 (cnblogs.com)

JVM调优总结--压力测试相关推荐

  1. 大型跨境电商 JVM 调优经历

    大型跨境电商 JVM 调优经历 前提: 某大型跨境电商业务发展非常快,线上机器扩容也很频繁,但是对于线上机器的运行情况,特别是jvm内存的情况,一直没有一个统一的标准来给到各个应用服务的owner.经 ...

  2. JVM从入门到精通(七):GC常用参数,Method Area,JVM调优案例分析

    GC常用参数 -Xmn -Xms -Xmx -Xss 年轻代 最小堆 最大堆 栈空间 -XX:+UseTLAB 使用TLAB,默认打开 -XX:+PrintTLAB 打印TLAB的使用情况 -XX:T ...

  3. Java面试必问JVM调优,那.NET5呢?

    JVM调优已经是普通Java工程师的必修课了,而.NET开源快5年了,CLR层面的优化到目前都不多见,甚至常用的性能调优工具都还没玩过..NET5马上来了,要想在互联网大潮中逆袭,光靠平台是不够的,开 ...

  4. java jvm调优_(第2部分,共3部分):有关性能调优,Java中的JVM,GC,Mechanical Sympathy等的文章和视频的摘要...

    java jvm调优 这是以前的文章(第3部分,共1部分)的继续:有关性能调优,Java中的JVM,GC,Mechanical Sympathy等的文章和视频的提要 . 事不宜迟,让我们开始使用我们的 ...

  5. Java 性能优化系列之3.2[JVM调优]

    实用JVM参数 1. JIT 编译参数 JIT(Just-In-Time)编译器, 可以在运行时将字节码编译成本地代码,从而提升函数的执行效率. -XX:CompileThreshold为 JIT编译 ...

  6. JVM(五)JVM调优

    文章目录 一.调优实践 1.1 规划 1.1.1 规划步骤 1.1.2 规划案例 1.2 解决JVM运行过程中出现的问题 1.2.1 用jstack定位锁相关问题 1.2.2 OOM问题的定位方式 1 ...

  7. jvm调优五:jvm调优工具和调优实战

    jvm调优工具和调优实战 jvm自带常用命令 JPS jps是用于查看有权访问的hotspot虚拟机的进程id. 当未指定hostid时,默认查看本机jvm进程id -l:输出完整jar名称 -v:输 ...

  8. Java虚拟机这一块 —— JVM 调优和深入了解性能优化

    JVM 调优和深入了解性能优化 JVM 调优的本质 GC 调优原则 调优的原则 目的 GC 调优 调优步骤 日志分析 阅读 GC 日志 -XX:+UseSerialGC -XX:+UseParNewG ...

  9. JVM从跨平台到跨专业 Ⅲ --编译期处理、类加载、JVM调优

    文章目录 编译期处理 默认构造器 自动拆装箱 泛型集合取值 可变参数 foreach 循环 switch 字符串 switch 枚举 枚举类 try-with-resources 方法重写时的桥接方法 ...

最新文章

  1. 张杰和机器人_《80后脱口秀》吐槽高考 张杰化身“机器人”
  2. Partition Tables介绍及分区表转换
  3. 深度学习利器:TensorFlow与NLP模型
  4. 《深度学习的数学》笔记【各种概念】
  5. [转]一些需要禁用的PHP危险函数和禁用方法
  6. 解决项目莫名奇妙的报错问题
  7. linux 编辑启动菜单,grub2的配置,linux启动菜单修改
  8. ptaa乘以b_PTA|团体程序设计天梯赛-练习题目题解锦集(C/C++)(持续更新中……)...
  9. springboot学习笔记-5 springboot整合shiro
  10. 技术员 Ghost Win10 x86 装机版/纯净版 201710
  11. 中兴机顶盒刷机后服务器连接失败,刷机后rec无法进入!!!求助
  12. 射频识别技术漫谈(25)——Felica简介
  13. 一个游戏程序员的学习资料
  14. 【PMP】PMBOK 笔记 第6章 项目时间管理
  15. Sina weibo新浪微博 API返回信息详解
  16. 微信文件指定应用打开并获取文件路径,以及遇到的一个坑
  17. WAF应用防火墙的功能
  18. jsp、servlet与javabean的区别180110
  19. 怎样将动图静图拼在一起?教你在线拼接图片
  20. svg文件解析(python)

热门文章

  1. 使命召唤5该服务器没有响应,使命召唤5玩不了怎么办 使命召唤5打不开解决办法...
  2. [转]医保 北京医保存折如何取钱
  3. 大数据到底是干什么用的?
  4. 关于计算机技能培训的论文,关于计算机专业学年论文范文.docx
  5. 计算某年某月的天数问题
  6. 51单片机+ESP8266实现手机控制单片机(点亮LED灯)
  7. hihocoder1258(水)(2015ACM/ICPC北京站)
  8. J2EE是什么?它包括哪些技术?
  9. Camera sensor 基本原理
  10. keepalived源码解析 —— master 是如何实现定时发送 vrrp 通告