当前位置:   article > 正文

底层原理计划--Java连环问之美人计_refreshscore不能实时更新

refreshscore不能实时更新

Rocketmq了解
why
1、 解耦:以前那些A服务调用BCDEF服务,万一一个服务挂了怎么办?要不要重发?解决耦合性
2、 异步:有些类型的报告生成时间太长了,让用户一直卡着在不太好吧。异步后,BCDEF自己去执行写库的时间,消息队列中间件自己本身执行快。
3、 削峰:节假日退出活动,用户访问量增多,如果说系统一秒钟可以处理500请求,这一秒超过500请求怎么办,mq让系统平缓处理突然增加的请求。用时间换空间。让用户请求过来,我们消费者在根据先进先出原则依次消费消息。
4、 解耦、异步、削峰是mq主要的优点,mq的缺点是要保证mq可用的,不然也会影响业务。增加了系统的复杂性和开发时间。还有一致性问题。
What
Rocketmq是阿里巴巴开源的消息队列中间件,模仿kafka开发,有生产者、消费者、主题、tag等属性构成,优点是解耦、异步、削峰,提高请求速度,减少响应事件,是高并发解决方案之一。
性能:kafka>rokcketmq>rabbitmq 阿里支撑,双十一就是用的rocketmq,阿里系都在用,性能高,可靠性好,可用性高
功能:rocketmq>kafka 功能完善,基本都有开源功能:延迟时间、事务消息、消息重试
使用:用起来好用,易用,开源框架工具类多

How
生产发送消息
生产者、消费者怎么实现的?原理是什么?
发送消息(同步、异步(源码在同步基础上加了普通线程池,成功、失败不同处理方案)、单向)
同步:请求成功了才会执行下一个线程,可以保证发送消息的顺序和可靠性
异步:在同步的基础上增加线程池操作,不能保证顺序和可靠性,但是可以保证速度
单向:直接发送,不要求响应了。

消费
https://blog.csdn.net/weixin_27252001/article/details/112730756
push:
理下流程:

创建消费对象,设置相关参数。
首先 new DefaultMQPushConsumer 对象,并指定一个消费组名。
然后设置相关参数,例如 nameSrvAdd、消费失败重试次数、线程数等
通过调用 setConsumeFromWhere 方法指定初次启动时从什么地方消费,默认是最新的消息开始消费。
通过调用 setAllocateMessageQueueStrategy 指定队列负载机制,默认平均分配。
通过调用 registerMessageListener 设置消息监听器,即消息处理逻辑,最终返回 CONSUME_SUCCESS(成功消费)或 RECONSUME_LATER(需要重试)。

2、设置消费的方式是pull还是push,消费的模式是集群还是广播
pull
首先根据 MQConsumer 的 fetchSubscribeMessageQueues 的方法获取 Topic 的所有队列信息
然后遍历所有队列,依次通过 MQConsuemr 的 PULL 方法从 Broker 端拉取消息。
对拉取的消息进行消费处理
通过调用 MQConsumer 的 updateConsumeOffset 方法更新位点,但需要注意的是这个方法并不是实时向 Broker 提交,而是客户端会启用以线程,默认每隔 5s 向 Broker 集中上报一次。

https://blog.csdn.net/weixin_41098980/article/details/79880957
1.集群消费方式
一个ConsumerGroup中的Consumer实例平均分摊消费生产者发送的消息。例如某个Topic有九条消息,其中一个Consumer Group有三个实例(可能是3个进程,或者3台机器),那么每个实例只消费其中的3条消息,Consumer不指定消费方式的话默认是集群消费的,适用于大部分消息的业务
2.广播消费方式
一条消息被多个Consumer消费,几十这些Consumer属于同一个ConsumerGroup,消息也会被ConsumerGroup中的每个Consumer消费一次,广播消费中的ConsumerGroup概念可以认为在消息划分层面没有意义,适用于一些分发消息的场景,比如我订单下单成功了,需要通知财务系统,客服系统等等这种分发的场景,可以通过修改Consumer中的MessageModel来设置消费方式为广播消费

//广播
BROADCASTING(“BROADCASTING”),
//集群
CLUSTERING(“CLUSTERING”);

创建的消费者订阅消息
consumerBean.subscribe(consumer.getTopic(), consumer.getTag(),
SpringUtil.getBean(consumer.getBeanName()));

源码
String messageModel = properties.getProperty(“MessageModel”, “CLUSTERING”);
this.defaultMQPushConsumer.setMessageModel(MessageModel.valueOf(messageModel));
MQ 消息重试只针对集群消费方式生效;广播方式不提供失败重试特性,即消费失败后,失败消息不再重试,继续消费新的消息。
https://blog.csdn.net/dancheren/article/details/71325437
Action.CommitMessage不重试
Action.ReconsumeLater重试

RocketMq
是推模型还是拉模型push pull
rocketmq不管是推模式push还是拉模式pull底层都是拉模式pull,推模式push也是在拉模式pull上做了一层封装.。
push 和 pull 的优缺点:

push

优点:

1.push模式采用长轮询阻塞的方式获取消息,实时性非常高,用户体验好

2.rocketMq处理了获取消息的细节,使用起来比较简单方便

缺点:

1.当消费者能力远远低于生产者能力的时候,会产生一定的消费者消息堆积,消息堆积会占用消费者服务的资源,主要在于内存资源

解决方案:

rocketMq针对push模式提供了流量控制,有三种,单个队列消息数量(默认1000),单个队列内存中的大小(默认100M), 消息跨度(2000), 通过这三种控制,可以有效的控制消息对消费者的影响,各位可以根据自己项目的实际情况进行调整。

pull

优点:

1.想消费多少就消费多少,想怎么消费就怎么消费,哈哈,灵活性较大,不存在过多占用消费者资源的问题

缺点:

1.实时性很低

2.拉取消息的间隔不好设置,太短则borker压力大,太长则实时性很低。

在实际生产环境中,笔者一直使用的push消息模式,pull模式这里随手写下,不做重点描述啦!

消息中间件mq场景问题
业务场景:秒杀 ——> 下单 ——> 支付
这三个核心流程中,真正并发量大的是秒杀功能,下单和支付功能实际并发量很小。
所以,我们在设计秒杀系统时,有必要把下单和支付功能从秒杀的主流程中拆分出来,
特别是下单功能要做成mq异步处理的。而支付功能,比如支付宝支付,是业务场景本身保证的异步。

1、 消息丢失问题
网络超时导致消息发送失败,丢失了
解决:增加一张消息发送表
发送成功了,更新为已处理,
没有成功的再发一遍

如果写入成功了,发送到mq又失败了呢

使用job,增加重试机制

2、 消费重复消费问题
增加一张消息处理表
消费者读到消息之后,先判断一下消息处理表,是否存在该消息,如果存在,表示重复消费,则直接返回。如果不存在,则正常操作,接着将消息写入消息处理表中,再返回

3、 垃圾消费问题
业务场景:秒杀 ——> 下单 ——> 支付
这三个核心流程中,真正并发量大的是秒杀功能,下单和支付功能实际并发量很小。
所以,我们在设计秒杀系统时,有必要把下单和支付功能从秒杀的主流程中拆分出来,
特别是下单功能要做成mq异步处理的。而支付功能,比如支付宝支付,是业务场景本身保证的异步。

4、延时消费问题
问题背景:用户秒杀成功,下单之后,30分钟之内未进行支付,该订单会被自动取消,回退库存。
实现方法可以用job,但job有个问题,需要每隔一段时间处理一次,实时性不是很好我们还可以用延时队列,rocketMq自带了延时队列的功能
具体实现:下单时消息生产者会生成一张订单,此时的状态为待支付,然后向延时队列中发送一条消息,当到达延时时间,消息消费者读取消息之后,会查询该订单的状态是否为待支付。如 果是待支付状态,则更新订单状态为取消状态。如果不是待支付,说明该订单已经支付过了,则直接返回;
注意点: 用户完成支付之后,会修改订单状态为已支付。

Mq常见的问题:
生产者发送消息丢失、重复消费消息、消息延迟时间

Rocketmq源码解决了消息重试、延迟时间

生产者消息丢失怎么处理

怎么防止重复提交1、提交的时候:生产唯一key先不执行业务sql, 去判断有没有存在一样的key;
或者status状态2、提交前:判断是否符合条件

Redis了解多少?(à缓存一套,–>分布式锁)
Why
1、数据高并发读写
2、海量数据读写
3、不经常改变,但是对MySQL查询压力大的
4、想要使用分布式锁的解决方案,还有缓存 ;
What
nosql 非关系型数据库
Redis是一款内存高速缓存数据库。Redis全称为:Remote Dictionary Server (远程数据服务),使用C语言编写,Redis是一个key-value存储系统(键值存储系统),支持丰富的数据类型,
如:
String
string
int
float
字符串最大空间不超过512m
规范 项目名:业务名:类型:id

List
与java linkedlist类似,双向链表,支持正向反向检索
有序
可重复
插入,删除快
查询一般
应用场景:朋友圈点赞列表、评论列表

Set
与hashset类似
无序
元素不可重复
查找快
支持交集、并集、差集(相对来说SQL实现比较复杂,所以用redis更简洁)

Zset
也叫sortedset
可排序set 与treeset类似
元素不重复
查询速度快
应用:排行榜

Hash
value是无序字典
类似java hashmap
CRUD单个字段更容易

Redis跟memcache不同的是,储存在Redis中的数据是持久化的,断电或重启,数据也不会丢失。
与MySQL数据库不同的是,Redis的数据是存在内存中的。它的读写速度非常快,每秒可以处理超过10万次读写操作。因此redis被广泛应用于缓存。
Redis缓存提高查询效率

How
可以自己封装redis工具类,SpringDataRedis企业用的多,Spring提供的Redis Client, StringRedisTemplate是用于操作Reids的API工具。
Jedis 通常一般的设置缓存、过期时间、修改、删除。比较全面的Redis命令的支持

Ressdion
依赖lock4j-redisson-spring-boot-starter 或 redisson、redisson-spring-boot-starter

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TaskApplication.class)
public class ExceptionTest {

//way of first
//redisson-spring-boot-starter-3.13.6.jar
@Autowired
private RedissonClient redissonClient;

// //way of second
// //lock4j-redisson-spring-boot-starter-2.2.2.jar
// @Resource
// private LockTemplate lockTemplate;

//way of first
@Test
public void redisTest() {
RLock lock = redissonClient.getLock(“this_is_key”);
try {
lock.lock();
//模拟业务
Thread.sleep(5000);
} catch (Exception e) {
log.warn(“e:{}”, e);
} finally {
lock.unlock();
}
}

// //way of second
// @Test
// public void secondTest(){
// LockInfo lockInfo = null;
// try {
// lockInfo = lockTemplate.lock(“this_is_second_key”, 5000L, 0);
//
// Thread.sleep(5000);
// } catch (Exception e) {
// log.warn(“e:{}”, e);
// }
//
// lockTemplate.releaseLock(lockInfo);
// }
}

//请求超时时间小于等于0L,框架会用默认的请求超时时间,第四个参数决定lock方法用框架里面的自旋锁。设置超时时间。请求时间和过期时间是不一样的概念。
lockInfo = lockTemplate.lock(key, 50000,
0L, RedissonLockExecutor.class);

有些小伙伴认为,稍微把锁过期时间设置长一些就可以啦。其实我们设想一下,是否可以给获得锁的线程,开启一个定时守护线程,每隔一段时间检查锁是否还存在,存在则对锁的过期时间延长,防止锁过期提前释放。

当前开源框架Redisson解决了这个问题。我们一起来看下Redisson底层原理图吧:只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用Redisson解决了「锁过期释放,业务没执行完」问题。

Redis高级
缓存雪崩:由于原有缓存失效,新缓存未到期间(比如;我们设置缓存时采用相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库cpu和内存造成巨大压力,严重的造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。

Redis为什么可以加锁
因为redis是一个单独的中间件,不同客户端可以往同一个redis或者集群中加锁,这样就能保证加锁的地方或者是资源相同的。并且由于redis也是单线程的,同时也支持lua脚本,可以保证并发安全的问题,所以可以很简单的实现分布式锁的功能。

开发流程一套
Req----à一系列复杂的关系--------àresp 跨服务
查询数据库----》nosql:redis缓存,存储es目的搜索查询
----》mysql
主服务controller----》业务服务
接口层面加了feign
熔断 – 打断调用链提早结束不正常的调用
降级 – 使某一个节点暂时退出系统减少接收请求量,等它恢复
容错机制
同一个意思
Server—àapi 业务调用req
业务服务调用
Network、saas-admin–à业务服务-----》商户服务----》底层服务common framework

集群和微服务、分布式
(对系统分而治之,解决因为并发访问过大带来的系统复杂性(例如:业务,开发,测试,升级,可靠性) 微服务设计的特点(单一职责,独立进程,开发测试效率高,可靠性高,升级难度小,但是会带来一定的维护成本)
Maven清理clean 编译complite 安装install 部署deploy
集群:多个服务器对一个服务,rocketmq消费的时候默认使用集群模式,而不是广播模式;redis用了集群,每个服务器分担一些,还有master节点、从节点。
微服务:一个服务对一个功能类别业务,一个服务器对一个任务、服务,一个服务可以有多个实例
分布式:分布式系统是若干独立计算机的集合,单体架构向多体架构演变的过程。分布式属于微服务的一种。
主从复制,读写分离。
缓存一套方案,从点击浏览器来讲你的故事

多级缓存方案,
1、我们从点击浏览器开始,前端可以做一个缓存,时间间隔短直接拿缓存,步用在调后台接口
2、Nignx本地可以做缓存,页面缓存。Nginx也防止恶意请求对其他客户利益的危害和服务器的压力
https://blog.csdn.net/houxian1103/article/details/109575362
3、nignx缓存没有命中,到redis去找;还有一个在es存储搜索数据库。
4、redis没有找到,进程是否有缓存,没有则去mysql查数据
第一个一般查到mysql数据,然后存到redis数据库中,当然对于mysql数据量多的可以主从复制,读写分离。查询的时候用读的数据库。

顺便讲一下mysql优化
索引避免失效-----一大堆随便说
避免全表扫描,-----一大堆考虑where 及order by 涉及的列上建立索引
Select * 少用
https://blog.csdn.net/biyusr/article/details/125599865

Mysql
存储引擎:mylsam/Innob/memoery….
Show engines
Myisam:全表锁,拥有较高的执行速度,不支持事务,不支持外键,并发性能差,占用空间相对较小,对事务完整性没有要求,已select、insert为主的应用基本上可以用这个引擎。

Myisam与innodb区别
Innodb支持事务,myisam不支持事务
Innodb支持外键,myisam不支持
Innodb不保存表的具体行数,执行select count(*) from table时需要全表扫描。而myisam用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;
Innodb不支持全文索引,而myisam支持全文索引,查询效率更高。

Innodb:行级锁(是一种排他锁,防止其他事务修改此行),提供了具有提交、回滚和崩溃回复能力的事务安全,支持自动增长列支持外键约束,并发能力强,占用空间是myisam的2.5倍,处理效率相对会差一点。

Innodb底层
底层是b+树数据机构,b树的每一个节点对应innndb的一个page,page大小是固定的,一般设为16k其中非叶子节点只有键值,叶子节点包含完成数据
使用场景:
经常更新的表,适合处理多重并发的更新请求。
支持事务。
可以从灾难中恢复。
外键约束,只有他支持外键。
支持自动增加列属性。
Mysql索引

什么是索引:
索引index是帮助mysql高效获取数据的数据结构。

从 功能逻辑 上说,索引主要有 4 种,分别是
普通索引index(在创建普通索引的时候,不附加任何限制条件,只是用于查询提高查询效率)、
唯一索引unique(在普通索引基础上索引必须唯一的,但可以有空值)、
主键索引primary(特殊的唯一索引,不为空的约束)、
全文索引fulltext(全文索引(也称全文检索)是目前所有引擎使用的一种关键技术,它能够利用分词技术等多种算法智能分析出文本文字中关键词的频率和重要性,然后按照一定的短发规则智能地筛选出我们想要是搜索结果,前文索引非常适合大型数据集,对于小的数据集,他的用处比较小。)
按照 物理实现方式 ,索引可以分为 2 种:
聚簇索引和非聚簇索引。

提高效率 innodb—》b+tree

索引的分类:
主键索引

索引失效的情况

1、模糊查询
模:指的是模糊查询,模糊查询使用like关键字,以%开头的话会索引失效。
like ‘%dd’ %在前
/2、数据类型强转
型:指的是数据类型强转,数据类型错误也会使索引失效。
强转虽然查询成功 where id = ‘11111’
/3、运算
数:运:指的是运算,对索引列使用加减乘除运算,会导致索引失效.
4、函数
指的是函数,对索引列使用内部函数会索引失效,
Sum count avg ….
5、使用is not null
is not null

6/条件中有or
Select id from t where num = 10 or num =20

优化:
Select id from t where num = 10
union all
select id from t where num = 20

7/ where的判断条件如果对字段进行了null值判断,将导致数据库放弃索引而进行全表查
Select id from t where num is null
可以num上设置默认值0,确保num列没有null值,这样查询
Select id from t where num = 0

8/ where 子句中使用!=或<>操作符
where —> < !=

9 in和not In慎用,否则会导致全表扫描
Select id from t where num in(1,2,3)

优化
Select id from t where num between 1 and 3

根据上面的知识;可知id相同,由上至下依次执行,分析结果可知:
先查询t表就是teacher表中name字段为a的记录,由于name字段没有索引,所以全表扫描(type:ALL),一共有3条记录,扫描了3行(rows:3),1条符合条件(filtered:33.33 1/3);
再查询tc即teacher_card表使用主键和之前的t.tc_id关联;由于是关联查询,并且是通过唯一索引(主键)进行查询,仅能返回1或0条记录,所以type为eq_ref。

system 该表只有一行, const 类型的特例。
const 最多匹配一行,在查询开始时读取,因为只有一行,所以被认为恒定不变的(constants),因为只读一次,所以非常快。
出现在基于主键或唯一键的等值查询

eq_ref 表关联时如果表关联字段是主键或唯一索引字段,会是该情况。这是最好的表联接类型。
ref 用于 = 匹配,但是关联字段不是主键或唯一键
fulltext 使用FULLTEXT 索引执行联接。
ref_or_null 这种连接类型类似于 ref,但是MySQL还会额外搜索包含NULL值的行。此联接类型优化最常用于解析子查询
如:SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;

index_merge 使用索引合并优化。参考:8.2.1.3, “Index Merge Optimization”.
unique_subquery 在in子查询中类似 eq_ref。如:value IN (SELECT primary_key FROM single_table WHERE some_expr)
index_subquery 类似于 unique_subquery。但子查询非唯一
range 指定范围查询。ref 列是 NULL。操作符 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, or IN()
index 类似 ALL,但只有索引树被扫描。两种情况:1.索引覆盖,这时 Extra列显示 Using index。 2.以索引排序全表扫描
ALL 全表扫描
Mysql锁
1、 全局锁,对整个数据库实例加锁
2、 表级锁
3、 行锁

死锁:在并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源,就会导致这几个线程都进入无限等待状态,称为死锁。

Mysql事务
四大特性:
原子性:一个事务要么全部成功要么全部失败
一致性:一个事务可以让数据从一致状态切换到另一种一致性状态
隔离性:一个事务不受其他事务影响,多个事务彼此隔离
持久性:一个事务一旦被提交,在数据的改变是永久的

Mysql事务的并发问题
脏读:事务在修改前后另一个事务分别查询造成前后数据不一致性。
不可重复读:同样是两个事务,事务a查询一条数据,事务b修改了这条数据,特别注意,这里事务b执行了提交,但是事务a还没有提交或回滚,这种事务并发问题称为不可重复读。
不可重复读: 一个事务读取到其他事务已提交的数据导致前后两次读取数据不一样的情况
幻读: 一个事务前后两次读取的数据不一致,是因为其他事务插入数据导致的事务并发情况

MySQL 的默认隔离级别是可重复读,不是读已提交
隔离性从低到高分别是:读未提交、读已提交、可重复读、可串行化
并发性跟隔离性恰好相反,从低到高是:可串行化、可重复读、读已提交、读未提交
这也非常好理解,隔离性越高,说明锁的粒度越细,并发性自然就会降低

Mysql执行计划

Expain执行计划
返回结果行数占百分比,估算出找到所需记录
显示该表的索引字段关联哪张表的哪个字段
索引的长度
实际使用到的索引
查询可能使用的索引

Type
系统表 system
唯一性索引 eq_ref
非唯一性 ref
全文索引 fulltext
可以出现null的情况 ref_or_null
索引合并 index_merge
主键进行等值匹配 unique_subquery
访问子查询表使用普通索引 index_subquery
只检索给定范围的行,使用一个索引来选择行 range
Index类型只遍历索引树
遍历所有匹配行 all

Linux
查看磁盘
查看当前目录
Df -h

具体查看文件夹占用情况
Du -sh

查看日志
Tail -333f a.log
Cat -n filename | grep “关键字”
Vi a.log

Ps命令 查看静态进程统计信息
Top 查看进程动态信息

钉钉通知、短信通知怎么实现的?
钉钉群:钉钉机器人密钥、消息体(对象模板,和具体动态要配的值)、钉钉机器人Hook地址
短信通知:短信签名、短信模板code、短信模板变量对应的实际值、接收人手机号码、业务code

定时器怎么实现的?锁、分布式锁讲一下?
每天晚上0点
@Scheduled(cron = "0 0 0 */1 * * ")

悲观锁
写多读少,认为别人会来访问,所以一开始就上锁,悲观心态,最后释放
synchronized、Lock,ReentrantLock
在Java中,Synchronized和Lock等独占锁的实现机制就是基于悲观锁思想。在数据库中也经常用到这种锁机制,如行锁,表锁,读写锁等,都是在操作之前先上锁,保证共享资源只能给一个操作(一个线程)使用

乐观锁
读多写少,认为一般情况下,其他线程不会一起进来,一开始没有上锁,只有当其他线程写的时候再上锁,乐观心态
CAS算法,例如AtomicInteger类的原子自增底层是通过CAS实现的

自旋锁
一个线程在执行了还没有结束,其他线程访问了实际上在执行一个空的多线程
//请求超时时间小于等于0L,框架会用默认的请求超时时间,第四个参数决定lock方法用框架里面的自旋锁。设置超时时间。请求时间和过期时间是不一样的概念。
lockInfo = lockTemplate.lock(key, 50000,
0L, RedissonLockExecutor.class);

重入锁
可重入锁当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的 ,可避免死锁
锁实现:关键字synchronized,ReentrantLock锁实现

Redis分布式锁用的多

线程
线程安全的集合
Vector hashtable ===》synchronized

使用Collections包装成线程安全,本质上是将原本的集合在执行之前加上了synchronized(){}的对象锁,将对象先锁定再来运行。

===》synchronized

Synchronize lock区别 synchronized jvm 自动释放锁
Lock工具类,要unlock手动释放锁
线程池了解多少?
WHY
铺位评估批量操作、以及导入1000个店铺,如果不用线程池,就用单线程,那么执行起来是很慢的,会卡住页面,给用户的体验感不太好。
我们用线程池来提高效率,多种线程同时进行。
优点提高了效率,提高响应时间,因为线程池中的线程是可以复用的,我们只用少量的线程去执行大量的任务,这就大大减小了线程生命周期的开销。而且线程通常不是等接到任务后再临时创建,而是已经创建好时刻准备执行任务,这样就消除了线程创建所带来的延迟,提升了响应速度,增强了用户体验。
线程池使用已经创建好的线程进行循环任务处理,就避免了大量线程的频繁创建与销毁的时间成本

缺点短时间内多任务执行消耗cpu,直到执行完,开发难度维护难度加大。CPU 资源管理。

What
1、 优点
降低资源消耗
提高响应速度
提高线程可关联性
2、 核心参数
CorePoolSize核心线程数
核心线程数 推荐cpu核数+1
核心线程会一直存在,即使没有任务执行;当线程数小于核心线程数,即使有空闲线程,也会一直创建线程直 到达到核心线程数;
Workqueue工作队列
maxPoolSize最大线程数
keepAliveTime线程空闲时间
unit空闲线程存活时间单位
threadFactory线程工厂
handler拒绝策略
3、 降低资源消耗

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动。

线程池的应用场景:有大量的数据请求,需要多执行流并发/并行处理这些任务。

线程池就是线程的池子,有很多线程,但是数量不会超过池子的限制。需要用到多执行流进行任务出路的时候,就从池子中取出一个线程去处理,线程池就类似于一个实现了消费者业务的生产者与消费者模型
How
newScheduledThreadPool
周期性线程池,创建一个定长线程池,支持定时及周期性任务执行。
创建一个固定大小的线程池,线程池内线程存活时间无限制,线程池可以支持定时及周期性任务执行,如果所有线程均处于繁忙状态,对于新任务会进入DelayedWorkQueue队列中,这是一种按照超时时间排序队列结构。

使用周期性执行任务场景

newScheduledThreadPool 创建一个线程池,安排计划执行(定期)
private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
scheduledExecutorService.execute(() -> {
}

======不一样的线程池
我看到rocketmq异步发送消息的时候使用了线程池来提高效率。
 this.defaultAsyncSenderExecutor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors(), 60000L, TimeUnit.MILLISECONDS, this.asyncSenderThreadPoolQueue, new ThreadFactory() {
            private AtomicInteger threadIndex = new AtomicInteger(0);
  • 1
  • 2
  • 3
  • 4

另一个常用的线程池
Pulic static ExecutorService newCachedThreadPool() {
Return new ThreadPoolExectuor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());

}

是一个可以无限扩大的线程池
比较适合处理执行时间比较小的任务
CorePoolSize为0,maximumPoolSize为无限大,线程数量可以无限大;

java线程池工作过程
1、 线程池刚创建的时候,里面没有一个线程任务队列是作为参数传过来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
2、 当调用execute()方法添加一个任务时,线程池会做一下判断:
1 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务;
2 如果正在运行线程数量大于或等于corepoolsize,那么将这个任务放入队列;(等待)
3 如果这时候队列满了,而且正在运行的线程数量小于maximumpoolsize那么还是要创建非核心线程立刻运行这个任务
4 如果队列满了,而且正在运行线程数量大于或等于maximumpoolsize,那么线程池会抛出异常rejectexecutionException
当一个线程完成任务时,它会从队列中取下一个任务来执行。
3、 当一个线程无事可做,超过一定的时间(keep Alive Time)时,线程池会判断,如果当前运行的线程数大于corepoolsize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到corepoolsize的大小。
线程池的实现原理与作用:
线程池通过一个线程安全的阻塞任务队列加上一个或一个以上的线程实现,线程池中的线程可以从阻塞队列中获取任务进行任务处理,当线程都处于繁忙状态时可以将任务加入阻塞队列中,等到其它的线程空闲后进行处理
可避免大量线程频繁创建或销毁所带来的时间成本,也可避免在峰值压力下,系统资源耗尽的风险;并且可以同一对线程池中的线程进行管理,调度监控
ElasticSearch了解
Why
会解决一些mysql不太好写的sql语句,如搜索多模糊查询。
然后,重要特性可以提高查询效率,为搜索而生。
查询效率比mysql更快,有些搜索业务mysql、redis都不太好实现,elasticserach比较好实现
What
基于Luncene的搜索服务器。用Java开发的,主要解决mysql性能低、功能有限的问题。
ElasticSearch优点:
1、是一个分布式、高扩展、高实时的搜索与数据分析引擎。
2、基于Restful web接口
3、应用于 1 海量数据查询 2 日志数据分析 3 实时数据分析

提高并发场景搜索效率,并采用ik中文分词器强化了分词搜索的功能。
How
Get方法

<elasticsearch.version>5.5.0</elasticsearch.version>
<es.rest.client>5.6.0</es.rest.client>

org.springframework.data spring-data-elasticsearch 3.0.5.RELEASE

@Autowired
private ElasticsearchOperations esTemplate;

JSONObject obj = new JSONObject();
obj.put(“id”,123);
obj.put(“name”,“你好”);
//id为主键,一定要加在里面

核心
AggregatedPage aggregatedPage= (AggregatedPage) esTemplate.queryForPage(nativeSearchQuery,JSONObject.class);

我们公司自己封装了es工具类,基本的增删改查批量等,主要看你写的json传参是否复杂,就可以解决复杂的查询问题。
倒排索引
Ik分词器
通过分词策略,形成词和文章的映射关系表,这种词典+映射表就是倒排索引,o(1)时间复杂度提高了查询效率

Cat 12,123,444,333,4444
Deep 333,322,334,566,555
Ddd 33322,444,555,666,54
Spring IOC依赖注入和AOP面向切面编程
直译过来就是控制反转,控制反转是把传统上由程序代码直接操控对象(new对象)的调用权交给ioc容器,由容器来实现对象的创建,依赖,销毁,初始化等等
BeanFactory就用了工厂模式,实际上多个产品可以交给工厂去处理。

Aop实现日志,注解@Aspect切面,前置通知@Before,环绕通知@Around,后置通知@After, @Pointcut切点目标哪些包切面到

日志:切面
/**

  • @description: 系統操作日志切面,用户对系统操作进行记录
    **/
    @Slf4j
    //作用是把当前类标识为一个切面供容器读取
    @Aspect
    @Component
    public class SysOperatorLogAspect extends CommonController {

@Resource
private ISysOperatorLogRemoteService sysOperatorLogService;
@Resource
private EncodeDecodeService encodeDecodeService;
@Resource
private Environment environment;

/**

  • Advice(通知、切面): 某个连接点所采用的处理逻辑,也就是向连接点注入的代码, AOP在特定的切入点上执行的增强处理。
  • @Before: 标识一个前置增强方法,相当于BeforeAdvice的功能.
  • @After: final增强,不管是抛出异常或者正常退出都会执行.
  • @AfterReturning: 后置增强,似于AfterReturningAdvice, 方法正常退出时执行.
  • @AfterThrowing: 异常抛出增强,相当于ThrowsAdvice.
  • @Around: 环绕增强,相当于MethodInterceptor.
  • JointPoint(连接点):程序运行中的某个阶段点,比如方法的调用、异常的抛出等。
  • Pointcut(切入点): JoinPoint的集合,是程序中需要注入Advice的位置的集合,指明Advice要在什么样的条件下才能被触发,在程序中主要体现为书写切入点表达式。
  • Advisor(增强): 是PointCut和Advice的综合体,完整描述了一个advice将会在pointcut所定义的位置被触发。
  • @Aspect(切面): 通常是一个类的注解,里面可以定义切入点和通知
  • AOP Proxy:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类。
    */
    @Pointcut(value = “@annotation(com.shuwei.sscm.saas.admin.annotate.SysLogAnnotate)”)
    public void annotateCut() {
    }

//标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有
@Before(value = “annotateCut()”)

mybatis和mybatis-plus有什么区别?
是mybatis加强版,内置的Mapper,通用的Service
封装了一些crud方法,提高开发效率
负载均衡
是通过svc 你看k8s配置文件里有个service
K8S通过Ingress,把K8S集群中的服务,通过Http和https路由暴露给外部用户。 路径等信息通过Ingress的资源文件配置。

负载均衡是我们的项目经理在nacos+k8s搭建负载均衡,目的是各个服务器分担服务的一个压力,做到压力均衡化。

https://nacos.io/zh-cn/docs/use-nacos-with-kubernetes.html
Nacos配置中心
WHY
没有配置之前,修改一个东西要修改代码。管理起来很乱。效率低下。扩展难。Ip密码等存储不安全
WHAT
动态配置服务可以让您以中心化、外部化和动态化的方式管理所有的环境应用配置和服务配置,可以动态通过修改配置文件中的值,从而影响服务应用结果或者服务的运行。
动态配置消除了配置变更时更新部署应用和服务的需要,让配置管理变得更高效和敏捷。
配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。

HOW
https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
· 通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-config 实现配置的动态变更。

1/ spring-cloud-starter-alibaba-nacos-config

2/ 在bootstap.yml配置nacos server地址
之所以需要配置 spring.application.name ,是因为它是构成 Nacos 配置管理 dataId字段的一部分
name: @artifactId@ 动态生成
saas-network-pc-test.yml
3、通过springcloud注解@RefreshScore实现配置自动更新
@RestController
@RequestMapping("/config")
@RefreshScope
public class ConfigController {

@Value("${useLocalCache:false}")
private boolean useLocalCache;

@RequestMapping("/get")
public boolean get() {
return useLocalCache;
}
}
WHERE
Yml properties

Nacos注册中心
2、 为什么要将服务注册到nacos?

为了更好的查找这些服务。

2、Nacos服务是如何判定服务实例的状态?
通过发送心跳包,5秒发送一次,如果15秒没有回应,则说明服务出现了问题,
如果30秒后没有回应,则说明服务已经停止。

服务(Service)是 Nacos 世界的一等公民

Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用 原生SDK、OpenAPI、或一个独立的Agent TODO注册 Service 后,服务消费者可以使用DNS TODO 或HTTP&API查找和发现服务。

还可以进行健康检查
Why
服务多了,需要统一的管理
为了更好地查找这些服务

What
1.核心知识点
服务注册中心的选型(社区活跃度,稳定性,功能,性能,学习成本) 基于nacos实现服务的注册(添加依赖,服务配置,启动服务并检查) 基于RestTemplate实现服务的简易调用(服务消费方调用服务提供方)

How
https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
1、 添加依赖
spring-cloud-starter-alibaba-nacos-discovery
2、 配置服务提供者,从而服务提供者可以通过nacos的服务注册发现功能将其服务注册安东nacos server上
3、 Application.yml配置nacos server地址

或者
server:
port:

spring:
application:
name: @artifactId@
cloud:
nacos:
discovery:
server-addr:
register-enabled: true
namespace:
metadata:

客户端向 nacos 服务器上报心跳包的时间间隔

preserved.heart.beat.interval: 5000

客户端不发送心跳后,从健康到不健康的时间

preserved.heart.beat.timeout: 5000

不发送心跳后,被 nacos下掉该实例的时间

preserved.ip.delete.timeout: 5000
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yml
namespace:

4、 通过注解@EnableDiscoveryClient开启服务注册发现
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {

public static void main(String[] args) {
	SpringApplication.run(NacosProviderApplication.class, args);
}

@RestController
class EchoController {
	@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
	public String echo(@PathVariable String string) {
		return "Hello Nacos Discovery " + string;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

}

5、 配置服务消费者,从而服务消费者可以通过nacos的服务注册发现功能从nacos sever上获取到它要调用的服务。

6、 通过注解@EnavleDiscoveryClient开启服务注册发现功能。给RestTemplate实例添加@LoadBlanced注解,开启

Where
Network服务

Feign
基于Feign的远程服务调用
为什么使用feign?(基于Feign可以更加友好的实现服务调用,简化服务消费方对服务提供方方法的调用)
FeignClient注解的作用是什么?(告诉Feign Starte,在项目启动时,为此注解描述的接口创建实现类-代理类)
Feign方式的调用,底层负载均衡是如何实现的?(Ribbon)k8s
EnableFeignClients注解的作用是什么?(描述配置类,例如启动类)
Spring
1、 通过注解注入的一般形式
@Bean
@Configuration
2、 通过构造方法注入bean

3、 通过set方法注入bean

4、 通过属性去注入bean
@Autowired

SpringAip工作过程
1、 Spring创建IOC容器
先扫描包中所有由@Service和@Componet修饰的类,并为他们创建对象,放在spirng IOC容器中

2、 寻找切面类
Spring在创建完对象后,开始寻找@Aspect修饰的切面类并获取切面类中的所有方法。
3、 寻找切面类的方法中带有表达式的部分
接下来,Spring找到所有由合法表达式修饰的方法
4、 查找有相应方法的类
5、 创建动态对象
6、 最后,Spring根据上一步找到的被代理了以及切面类创建动态对象并放入Spring IOC容器中

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/643278
推荐阅读
相关标签
  

闽ICP备14008679号