Pull 模式的另外一个好处是 consumer 可以自主决定是否批量的从 broker 拉取数据。Push 模式必须在不知道下游 consumer 消费能力和消费策略的情况下决定是立即推送每条消息还是缓存之后批量推送。如果为了避免 consumer 崩溃而采用较低的推送速率, 将可能导致一次只推送较少的消息而造成浪费。Pull 模式下, consumer 就可以根据自己的消费能力去决定这些策略。
Pull 有个缺点是,如果 broker 没有可供消费的消息,将导致 consumer 不断在循环中轮询,直到新消息到 t 达。为了避免这点,Kafka 有个参数可以让 consumer 阻塞知道新消息到达(当然也可以阻塞知道消息的数量达到某个特定的量这样就可以批量发送)。
lock、unlock、tryLock(限时等待)
-XX:+UseBiasedLocking
-XX:+DoEscapeAnalysis
-XX:+EliminateLocks
public ThreadPoolExecutor(
int corePoolSize, //线程数量
int maximumPoolSize, //最大线程数量
long keepAliveTime, //空闲线程存活时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列
ThreadFactory threadFactory, //线程工厂
RejectedExecutionHandler handler //拒绝策略)
Runtime.getRuntime().availableProcessors()
ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue
在Java8中,可以为接口添加 静态方法 和 默认方法
在Java8中,注解方面新增了 可重复注解 和 类型注解
底层结构有变化、JDK1.8中HashMap的底层结构是:数组+链表+红黑树
Lambda表达式、Stream API
Spring FrameWork 一共涉及到5种编程模型、面向对象的编程模型(接口、对象、设计模式)、面向切面的编程模型(动态代理、字节码提升)、注解驱动的编程模型、事件驱动的编程模型、模块驱动的编程模型
spring-core(资源管理、泛型处理)、spring-beans(依赖注入)、spring-context(注解驱动、事件驱动、模块驱动)、spring-webmvc(Servlet)、spring-aop(动态代理、字节码提升)
Spring管理Bean的容器
BeanFactory是一种Spring IOC的容器
FactoryBean是创建Bean的一个工厂方法
ApplicationContext是BeanFactory的一个子接口,在BeanFactory上进行了很多扩展、比如扩展了消息国际化(MessageSource)、环境可配置(EnvironmentCapable)、应用事件发布(ApplicationEventPublisher)和资源模式解析(ResourcePatternResolver)等
IOC容器中允许按照名字或类型获取Bean
@Autowired根据类型进行注入、@Resource根据名字注入
@Primary 和 @Quelifier 消除歧义 配合@Autowired使用
@Primary(优先)、@Quelifier(限定)有参数的构造方法装配
没有在SpringIoC容器初始化时就执行了Bean的实例化和依赖注入。
读取和解析配置元信息(通过BeanDefinition可以注册)、启动Spring上下文、实例化Bean、依赖注入(初始化Bean)、(Bean生存期)关闭Spring上下文(销毁Bean)
BeanNameAware , BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean
把请求的URL和控制器的方法相对应
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
面向切面编程(目标增强、约定大于配置)、主要用在日志、事务、安全等方面,底层原理是动态代理
Hibernate是全映射框架,在以管理系统为主的时代,它的模型化十分有利于公司业务的分析和理解,但是在近年兴起的移动互联网时代,这样的模式却走到了尽头。Hibernate的模式重模型和业务分析,移动互联网虽然业务相对简单,但却更关注大数据和大并发下的性能问题。全表映射规则下的Hibernate已无法满足SQL优化和互联网灵活多变的业务。
StatementHandler(数据库会话器)、ParameterHandler(参数处理器)、ResultHandler(结果处理器)
#定义Mapper的XML路径
mybatis.mapper-locations=
#定义别名扫描的包,需要与@Alias联合使用
mybatis.type-aliases-package=
#MyBatis配置文件,当你的配置比较复杂的时候,可以使用它
mybatis.config-location=
#配置MyBaits插件(拦截器)
mybatis.configuration.interceptors=
#具体类需要与@MappedJdbcTypes联合使用
mybatis.type-handlers-package=
#级联延迟加载属性配置
mybatis.configuration.aggressive-lazy-loading=
#执行器(Executor〕,可以配置SIMPLE、REUSE、BATCH,默认为SIMPLE
mybatis.executor-type=
<dependency>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-coreartifactId>
<version>1.3.7version>
dependency>
ehcache.xml
<Cache name="simpleCache" 缓存的名字
maxElementsInMemory="10000" 内存中最大的对象数
eternal="false" 对象是否永久存活
timeToIdleSeconds="120" 当缓存闲置n秒后销毁
timeToLiveSeconds="120" 当缓存存活n秒后销毁
overflowToDisk="true" 当大小超过memory的大小时,可以缓存到本地硬盘
maxElementsOnDisk="10000000" 硬盘上最大的对象数
diskPersistent="false" 是否在硬盘上持久化保存
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU" 内存清除对象的方式
/>
# 隔离级别数字配置的含义
#-1 据库默认隔离级别
# 1 未提交读
# 2 读写提交
# 4 可重复读
# 8 串行化
# tomcat数据源默认隔离级别
spring.datasource.tomcat.default-transaction-isolation=2
JPA是一种规范,是JSR-220规范的一部分。
Redis 提供两种持久化机制 RDB 和 AOF 机制
持久化机制 | 含义 | 优点 | 缺点 |
---|---|---|---|
RDB(Redis DataBase) | 把数据写入一个临时文件, 持久化结束后, 用这个临时文件替换上次持久化的文件, 达到数据恢复。 | RDB模式 是让主进程继续处理命令,使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 Redis 的高性能 | RDB模式 是隔一段时间进行一次持久化,如果持久化之前 Redis 发生了故障, 会发生数据的丢失。所以这种方式更适合数据要求不严格的时候 |
AOF(Append-Only File) | 把每次Redis命令追加写入日志文件中 | 跟 RDB模式 相比,当发生故障时,丢的少了 | AOF 文件比 RDB 文件大, 且恢复速度慢。 |
策略 | 含义 |
---|---|
volatile-lru | 从已设置过期时间的数据集中挑选最近最少使用的数据淘汰 |
volatile-ttl | 从已设置过期时间的数据集中挑选将要过期的数据淘汰 |
volatile-random | 从已设置过期时间的数据集中随机选择数据进行淘汰 |
allkeys-lru | 从所有数据集中挑选最近最少使用的数据淘汰 |
allkeys-random | 从所有数据集中随机选择数据进行淘汰 |
no-enviction | 永不回收策略 |
使用策略规则:
1、如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低, 则使用 allkeys-lru
2、如果数据呈现平等分布, 也就是所有的数据访问频率都相同, 则使用allkeys-random
# 配置连接池属性
spring.redis.jedis.pool.min-idle=5
spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.max-wait=2000
# 配置Redis服务器属性
spring.redis.port=6379
spring.redis.host=192.168.11.131
spring.redis.password=123456
# Redis连接超时时间,单位毫秒
spring.redis.timeout=1000
# 日志配置为DEBUG级别,这样日志最为详细
logging.level.root=DEBUG
logging.level.org.springframework=DEBUG
logging.level.org.org.mybatis=DEBUG
#缓存配置
spring.cache.type=REDIS
spring.cache.cache-names=redisCache
Redis Sentinal 着眼于高可用, 在 Master 宕机时会自动将 Slave 提升为Master, 继续提供服务。
Redis Cluster 着眼于扩展性, 在单个 redis 内存不足时, 使用 Cluster 进行分片存储。
Redis 集群有16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽, 集群的每个节点负责一部分 hash 槽。
@EnableCaching //启动类上添加开启缓存注解
@Cacheable //需要缓存的方法上添加
@CacheEvict //Delete时也清除缓存
# 禁用前缀
spring.cache.redis.use-key-prefix=false
# 允许保存空值
#spring.cache.redis.cache-null-values=true
# 自定义前缀
#spring.cache.redis.key-prefix=
# 定义超时时间,单位毫秒
spring.cache.redis.time-to-live=600000
waitforconfirms
在消息生产时, MQ 内部针对每条生产者发送的消息生成一个 inner-msg-id, 作为去重的依据( 消息投递失败并重传), 避免重复的消息进入队列;
在消息消费时,要求消息体中必须要有一个 bizId( 对于同一业务全局唯一,如支付 ID、订单 ID、帖子 ID 等) 作为去重的依据, 避免同一条消息被重复消费。
spring.rabbitmq.listener.simple.prefetch = 1
信息成为死信的原因:
# RabbitMQ服务器地址
spring.rabbitmq.host=localhost
# RabbitMQ端口
spring.rabbitmq.port=5672
# RabbitMQ用户
spring.rabbitmq.usernarne=admin
#RabbitMQ密码
spring.rabbitmq.password=l23456
#是否确认发送的消息已经被消费
spring.rabbitmq.publisher-confirms=true
# RabbitMQ的消息队列名称,由它发送字符串
rabbitmq.queue.msg=spring-boot-queue-msg
# RabbitMQ的消息队列名称,由它发送用户对象
rabbitmq.queue.user=spring-boot-queue-user
spring.rabbitmq.listener.direct.acknowledge-mode=manual
spring.rabbitmq.listener.direct.prefetch=100
@RabbitListener(queues = 队列名)
@RabbitHandler
public void receiveDeadMsg(String msg, Channel channel, Message messages) throws Exception {
try {
业务代码...
// 回发ack,第二个参数multiple,表示是否批量确认,具体请百度,不赘述
channel.basicAck(messages.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
// 回发Nack,且重回队列为false,防死循环
channel.basicNack(messages.getMessageProperties().getDeliveryTag(), false, false);
}
}
大部分消息系统在 broker 端的维护消息被消费的记录:也就是一个消息被分发到 consumer 后 broker 就马上进行标记或者等待 customer 的通知后进行标记。这样也可以在消息在消费后立马就删除以减少空间占用。
一条消息发送出去之后就立即被标记为消费过的, 一旦 consumer 处理消息时失败了( 比如程序崩溃) 消息就丢失了。
为了解决这个问题, 很多消息系统提供了另外一个个功能: 当消息被发送出去之后仅仅被标记为已发送状态, 当接到 consumer 已经消费成功的通知后才标记为已被消费的状态。
这虽然解决了消息丢失的问题,但产生了新问题,首先如果 consumer 处理消息成功了但是向 broker 发送响应时失败了,这条消息将被消费两次。第二个问题时, broker 必须维护每条消息的状态, 并且每次都要先锁住消息然后更改状态然后释放锁。这样麻烦又来了, 且不说要维护大量的状态数据, 比如如果消息发送出去但没有收到消费成功的通知, 这条消息将一直处于被锁定的状态,
Kafka 采用的策略就是分区。把 Topic 分成了若干分区,每个分区在同一时间只被一个 consumer 消费。即使用 offset 来标记每个分区消费状态。
spring.security.user.name=myuser
spring.security.user.password=l23456