Spring Aop 源码学习
liunx 性能分析
uptime
1 | $uptime |
load average: 1.98,2.15,2.21
一分钟内的负载,5分钟内的负载,15分钟内的负载。
为了进一步理解系统负载,需要做一些假设。假设系统负载如下:23:16:49 up 10:49, 5 user, load average: 1.00, 0.40, 3.35
在单核系统中意味着:
- CPU 被充分利用(100%);最近的 1 分钟有 1 个进程在运行。
- CPU 有 60% 处于空闲状态;在最近的 5 分钟没有进程等待 CPU 时间。
- CPU 平均过载了 235%;最近的 15 分钟平均有 2.35 个进程在等待 CPU 时间。
在双核系统中意味着: - 有一个 CPU 处于完全空闲状态,另一个 CPU 被使用;最近的 1 分钟没有进程等待 CPU 时间。
- CPU 平均 160% 处于空闲状态;最近的 5 分钟没有进程等待 CPU 时间。
- CPU 平均过载了 135%;最近的 15 分钟有 1.35 个进程等待 CPU 时间。
top -H -p pid
cpu 负载监控,实时查看占用cpu高的线程
vmstat
系统负载监控
iostat
磁盘利用率监控
netstat -anp | grep ‘ip/prot’
查看网络连接信息
lsof -p pid
- 使用lsof -p pid 命令查看进程打开的文件,如果大部分文件都是同一类型的文件,说明可能未关闭文件流。找到打开文件的代码,关闭文件流即可。
- 如果不存在未关闭文件流的问题,且业务本身就需要处理大量文件,则修改
/etc/security/limits.conf
文件如下内容;1
2* hard nproc 10240
* soft nproc 10240
压测分析步骤
- 优化服务器本省的TCP信息
- tcp 端口的释放时间
- 查看内存,cpu,硬盘的IO
- 内存 Free -h 查看 buffers/cache 的值,buffers/cache 表示实际占用的值
- iostat
- top
- 分析服务器当前的并发数,文件打开数
netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’
Liunx 内核优化
vim /etc/security/limits.conf
soft nproc 10240
hard nproc 16384
soft nofile 60240
hard nofile 65536
hard core unlimited
vim /etc/security/limits.d/90-nproc.conf
soft nproc 50240
root soft nproc unlimited
vim /etc/sysctl.conf
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 60
net.ipv4.tcp_keepalive_time = 600
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_timestsmps = 0
net.ipv4.tcp_max_syn_backlog = 65536
net.core.netdev_max_backlog = 32768
net.core.somaxconn = 32768
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_wmem = 8192 436600 873200
net.ipv4.tcp_rmem = 32768 436600 873200
net.ipv4.tcp_mem = 94500000 91500000 92700000
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_fin_timeout = 30
Liunx 最大文件数
命令:ulimit -a
open files (-n) 1024
“open files” 参数选项后面的数值就是当前系统的支持的最大打开文件数
Kafka LogStash ES
Kafka LogStash ES
java 程序日志通过 logback,将日志写入kafka,在通过logstash采集kafka中数据,将数据写入ES中,最后通过 Kibana 查询程序日志。
中文编码
问题: 程序日志中文写入 kafka,最后在Kibana中以Unicode的方式显示。
解决方法:
1 | input { |
pom.xml
1 |
|
logback.xml
1 |
|
Spring Cloud Config
Spring Cloud Config
application.yml 和 bootstrap.yml 区别
加载顺序
- bootstrap.yml 先加载
- application.yml 后加载
bootstrap.yml 用于应用程序上下文的引导阶段。
bootstrap.yml 由父 Spring ApplicationContext 加载。
父ApplicationContext被加载到使用application.yml 的之前
配置区别
bootstrap.yml 和 application.yml 都可以用来配置参数
- bootstrap.yml 可以理解为系统级别的一些参数配置,这些参数一般是不会变动的。
- application.yml 可以用来定义应用节级别的,如果搭配 spring-cloud-config 使用application.yml 里面定义的文件可以实现动态替换。
使用Stpring Cloud Config Server时,应在bootstrap.yml 中指定: - spring.application.name
- spring.cloud.config.server.git.url
- 一些加密/解密信息
application 的加载原理
启动上下文
Spring Cloud 会创建一个Bootstrap Context
,作为Spring应用的Application Context
的父上下文。初始化的时候,Bootstrap Context
复制从外部源加载配置属性并解析配置。 这两个上下文共享一个从外部获取的Environment
.Bootstrap
属性有高优先级,默认情况下,它们不会被本地配置覆盖。Bootstrap context
和 Application Context
有着不同的约定,所有新增了一个bootstrap.yml
文件,而不是使用application.yml
。保证Bootstarp Context
和 Application Context
配置的分离。
应用上下文层次结构
如果你通过 SpringApplicaion
或者 SpringApplicationBuilder
创建一个Application Context
,那么会为spring应用的Application Context
创建父上下文Bootstrap Context
。在Spring里有个特性,子上下文会继承父类的property sources
,会新增额外的property sources
。额外的property sources
有:
- “bootstrap”: 如果在Boostrap Context 扫描到PropertySourceLocator并且有属性,则会添加到CompositePropertySource.Spring Cloud COnfig 就是通过这种方式来添加属性,详情请查看源码 ConfigServicePropertySourceLocator。
- “applicationConfig:[classpath:bootstrap.yml]” (如果有 spring.profiles.active=production,则例如 applicationConfig:[classpath:/bootstrap.yml]#product): 如果你是用bootstrap.yml 来配置Bootstrap Context,他比application.yml 优先级别要低,它将添加到子上下文,作为Spring Boot 应用程序的一部分。
由于优先级规则,Bootstrap Context 不包含从Bootstrap.yml 来的数据,但可以用它作为默认设置。
你可以很容易的扩展任何你建立的上下文层次,可以使用它提供的接口,或者使用 SpringApplicationBuillder包含的方法(parent(),child(),sibling())。 Bootstrap Context 将是最高级别的父类。扩展的每一个Context都有自己的 bootstrap property source(有可能是空的)。扩展的每一个Context 都有不同 spring.application.name。 同一层层次的父子上下文原则上也有着不同的名称,因此,也会有不同的Config Server配置。子上下文的属性在相同名字的情况下将覆盖父上下文的属性。
注意:SpringApplicationBuilder允许共享Environment到所有层次,但是不是默认的。 因此,同级的兄弟上下文不在和父类共享一些东西的时候不一定有相同的profiles或者property sources。
修改Bootstrap属性配置
源码位置: BootstrapApplicationLister
1 | String configName = environment.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}"); |
bootstrap.yml 是有spring.cloud.bootstrap.name(默认:“bootstrap”) 或者 spring.cloud.bootstrap.location(默认空)。这些属性行为与spring.config.* 类似,通过它的Environment来配置引导ApplicationContext。如果有一个激活的profile(来源与 spring.profiles.active 或者 Environment 的Api构建),例如 bootstrap-development.properies 就是配置了 profile为development的配置文件。
覆盖远程属性
property sources 被bootstrap context添加到应用通常远程的方式,比如“Config Server”。默认情况下,本地的配置文件不能覆盖远程配置,但是可以通过启动命令参数来覆盖远程配置。如果需要本地文件覆盖远程文件,需要在远程配置文件里设置 spring.cloud.config.allowOverride=true
(这个配置不能在本地被设置)。一旦设置了这个权限,你可以配置更加细粒度的配置来配置覆盖的方式。
1 | spring.cloud.config.overrideNoe = true #覆盖任何本地属性 |
源文件详见 PropertySourceBootstrapProperties
自定义启动配置
bootstrap context 是依赖 /META-INF/spring.factories 文件里面的 org.springframework.cloud.bootstrap.BootstrapConfiguration 条目下面,通过逗号分隔的Spring @Configuration 类来建立的配置。任何main application context 需要自动注入的Bean可以在这里通过这种方式获取。这也是 ApplicationContextInitializer 建立@Bean的方式。可以通过 @Order来更改初始化序列,默认是”last”。
1 | # spring-cloud-context-1.1.1.RELEASE.jar |
你添加的自定义BootstrapConfiguration类没有错误的@ComponentScanned到你的主应用上下文,他们可能是不需要的。使用一个另外的包不被@ComponentScan或者@SpringBootApplication注解覆盖到。
bootstrap context 通过 spring.factories 的配置类初始化所有的Bean都会在SpringApplication启动前加入到它的上下文里去。
自定义引导配置来源: Bootstrap Property Sources
默认的property source
添加额外的配置是通过配置服务(Config Server),你也可以自定义添加 property soruce
通过实现 PropertySourceLocator
接口来添加。你可以使用它加配置属从不同的服务,数据库或者其他。
demo:
1 | @Configuration |
Environment 被 ApplicationContext建立,并传入 property sources(可能不同的profile有不同的属性),所以,你可以从Environment寻找找一些特别的属性。比如spring.application.name,它是默认的Config Server property source。
如果你建立了一个jar包,里面添加了一个 META-INF/spring.factories文件:org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator
。那么“CostomProperty” 的
参考资料
(SpringCloud入门之常用的配置文件 application.yml和 bootstrap.yml区别)[https://www.cnblogs.com/BlogNetSpace/p/8469033.html]
(Spring Boot)[https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/htmlsingle/]
(Spring Boot)[https://github.com/spring-projects/spring-boot]
Spring Cloud 中间组件
spring 技术内幕学习笔记
Spring Aop:
Spring 集成了AspectJ做为Aop的一个特定实现,同时还在JVM动态代理/CGLIB的基础上,实现了一个AOP框架,作为Spring集成到其他模块的工具,比如 TranscationProxyFactoryBean
声明式事务处理,就是通过AOP集成到Spring中的。在这个模块中,Spring AOP 实现了一个完整的建立AOP代理对象,实现AOP拦截器,直至实现各种Advice通知的过程。
Spring CacheManager
Spring 中提供了很多存储器,例如: SimpleCacheManager , EhCacheCacheManager, GuavaCacheManager, CompositeCacheManger。处理核心的Spring框架之外,Spring Date 提供提供了Redis缓存管理器。RedisCacheManager。
Spring Boot 中通过 @EnableCaching
注解自动化配置合适的缓存管理器。
默认情况下Spring Boot 根据以下顺序自动检测缓存提供者:
- Generic
- JCache (JSR-107)
- EhCache 2.x
- Hazelcast
- Infinispan
- Redis
- Guava
- Simple
若我们手动配置RedisTemplate后,Spring Boot 就无法自动给RedisCacheManager设置redisTemplate,所以需要自己配置RedisCacheManager。
1 | RedisConfig.java |
Spring 提供了以下注解来声明缓存规则
@Cacheable triggers cache population 表明Spring在调用方法之前,首先应该在缓存中查找方法的返回值,,如果这个值能够找到,就会返回这个值。否则的话,这个方法就会被调用,返回值会放到缓存中
@CacheEvict triggers cache eviction 表明Spring应该在缓存中清除一个或多个条目
@CachePut updates the cache without interfering 表明Spring应该将方法的返回值放到缓存中,在方法的调用前并不会检查,方法始终都会被调用
@Caching regroups multiple cache operations to be applied on a method
@CacheConfig shares some common cache-related setting at class-level 可以在类层级配置一些公用的缓存配置
@Cacheable 和 @CachePut 共有属性:
属性 | 类型 | 描述 |
---|---|---|
value | String[] | 要使用的缓存名称 |
condition | String | SpEL 表达式,如果得到的值是false的话,不会将缓存应用到方法调用上 |
key | String | SpEL表达式,用来计算自定义的缓存key |
unless | String | SpEL表达式,如果得到的值是true的话,返回值不会放到缓存之中 |
使用 CacheManager 的有点:
CacheManager 是所有缓存管理器的父级,定义了一些通用接口。
具体的缓存实现可以继承CacheManger,并自行实现功能。通过这个方法可以进行拆分解耦,当替换其他缓存插件时,不需要修改代码,只需要修改配置文件就行。
Redis 在项目中的使用
- 开启Redis事务
@Transactional
与stringRedisTemplate.setEnableTransactionSupport(true);
需要同时启用。 - 查询不存在的数据,需要将一组空数据写入Redis,防止数据库被穿透。
- 查询数据时,需要使用 lock ,来防止所有请求都走数据库,而不走Redis,大流量,大并发的情况下。
Redis 集群
Redis 集群只有 db0,不支持 select db操作,不支持 Redis 事务操作。
代码分析
Elastic Stack
Elastic Stack 入门教程
ElasticSearch 与 Kibana
Beats 轻量型数据采集器
- Filebeat
- Packetbeat
Logstash
处理流程
Input => Filter => Output
File grok stdout
Redis mutate elastisearch
Beats drop redis
Kafka date kafka
使用 logstash 收集 nginx log 数据
ElasticSearch
Packetbeat 监听端口,采集log
logstash
1 | input { |
packetbeat
1 |