持续更新问题答案

1、微服务注册中心的注册表如何更好的防止读写并发冲突?

        如何解决线程安全问题的常用办法就是加锁

        JAVA中常用的synchronized可以解决问题。

        使用synchronized存在性能问题,现在相当于所有的读写操作都进行了锁定,即“串行化”

如何优化性能?使用读写锁。

读写锁是特殊的自旋锁,它把共享资源的访问者分为了读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。同时只允许一个线程对共享资源写或者多个读,但不能同时读又有写。

2、Eureka注册表多级缓存架构有了解过吗?

        Eureka想必大家都不陌生了,注册中心简单来说,其实就是各个服务将自己的IP和端口号这些信息存放到注册中心里,形成一个注册表,当服务间调用的时候,调用方就能从注册中心的注册表里面获取到要调用服务的具体IP和端口号,就可以请求那个服务了。

        Eureka的注册表拉取机制分为了两种,第一种是第一次拉取服务注册表的时候,此时需要全量拉取注册表,将所有服务的注册表信息全部存放起来,第二种是每隔30秒,增量拉取服务注册表。

在eureka client拉取注册表的时候,就会用到所谓的多级缓存机制。
        多级缓存机制中有两个缓存,一个叫只读缓存ReadOnlyCacheMap,一个叫读写缓存ReadWriteCacheMap。
        eureka client拉取注册表的时候,会先从ReadOnlyCacheMap中去获取注册表数据,如果获取不到的话再去ReadWriteCacheMap中找,如果还是找不到的话,那就只能重新从注册表中拉取了

多级缓存机制有多种过期策略:
        主动过期:当服务实例发生注册、下线、故障的时候,ReadWriteCacheMap中所有的缓存过期掉
        定时过期:readWriteCacheMap在构建的时候,指定了一个自动过期的时间,默认值就是180秒,所以你往readWriteCacheMap中放入一个数据,180秒过后,就将这个数据给他过期了
        被动过期:默认是每隔30秒,执行一个定时调度的线程任务,对readOnlyCacheMap和readWriteCacheMap中的数据进行一个比对,如果两块数据是不一致的,
那么就将readWriteCacheMap中的数据放到readOnlyCacheMap中来

3、Nacos如何支撑阿里巴巴内部上百万服务实例的访问?

4、Nacos高并发异步注册架构知道如何设计的吗?

5、Sentinel底层滑动时间窗限流算法怎么实现的?

6、Sentinel底层是如何计算线上系统实时QPS的?

7、Seata分布式事务协调管理器是如何实现的?

8、Seata分布式事务一致性锁机制如何设计的?

9、Seata分布式事务回滚机制如何实现的?

10、Nacos集群CP架构底层类Raft协议怎么实现的?

11、Nacos&Eureka&Zookeeper集群架构都有脑裂问题吗?

12、如何设计能支撑全世界公司使用的微服务云架构?

13、深入剖析Java虚拟机内存模型

14、JVM垃圾收集机制解密

15、常见JVM诊断工具调优实战

16、亿级流量电商网站JVM参数调优实战

17、日均百万级交易系统JVM调优实战

18、Java虚拟机常见面试题剖析

19、动手实战优化自己公司线上系统JVM

20、SpringIoc BeanDefinition对象详解

21、@Import注解作用详解

22、MyBatis的MapperProxy代理接口的"偷天换日"之术

23、FactoryBean与BeanFactory的本质区别

24、MyBatis多级缓存设计源码剖析

        Mybatis的二级缓存构建在一级缓存的基础上。在收到查询请求时,Mybatis首先会查询二级缓存,若二级缓存未命中,再去查询一级缓存,一级缓存没命中,再去查询数据库。
缓存命中顺序:二级缓存----->一级缓存------>数据库
与一级缓存不同,二级缓存和具体的命名空间绑定,一个Mapper中有一个Cache,相同的MappedStatement共用一个Cache,而一级缓存则是与sqlSession绑定。

要想使某条Select查询支持二级缓存,你需要保证:

  1. MyBatis支持二级缓存的总开关:全局配置变量参数 cacheEnabled=true
  2. 该select语句所在的Mapper,配置了 或节点,并且有效
  3. 该select语句的参数 useCache=true
    <select id="selectByMinSalary" resultMap="BaseResultMap" parameterType="java.util.Map" useCache="true">

    public static void main(String[] args) {
            SqlSessionFactory factory = new SqlSessionFactory();
            DefaultSqlSession sqlSession = factory.build().openSqlSession();
            Date first = new Date();
            // 获取MapperProxy代理
            BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
            Blog blog = mapper.selectBlogById(1);

            System.out.println("第一次查询: " + blog+ (System.currentTimeMillis() -first.getTime())+"ms");
            System.out.println();
            Date second = new Date();
            blog = mapper.selectBlogById(1);
            System.out.println("第二次查询: " + blog+(System.currentTimeMillis() -second.getTime())+"ms");

        }
    第一次查询耗时405ms,而第二次查询耗时不足1ms,这是因为第一次查询后,MyBatis会将查询结果存储到SqlSession对象的缓存中,当后来有完全相同的查询时,直接从缓存中将结果取出。

25、Spring生成代理对象的常用套路

        Jdk Proxy基于接口生成代理对象,只能赋值给接口的引用(默认使用jdk)。

        Spring进一步封装 CGLIB,基于实现类生成代理对象,既可以赋值给接口的引用,也可以赋值给实现类的引用

        JDK提供的Proxy,和spring进一步封装的CGLIB。二者生成的代理没有任何区别,生成的都是代理对象。只是生产方式不同,前者是基于接口生成代理,后者基于实现类生成代理对象

如何切换spring框架中默认生成代理的方式

<aop:config proxy-target-class=”true|false”></aop:config>

True代表使用目标类生成代理

False代表使用jdk的proxy接口生成代理(默认)

Proxy(代理):静态代理和动态代理

作用:起到传递会话的作用,中断整个会话。

好处:在完成核心业务的同时,做一些附加的操作。

目标类(target):被代理类称之为目标类。

开发代理的原则:和目标类功能一致且实现相同的接口。

静态代理:
开发一个代理类,手动的为每个业务类添加代理方法,能够完成代理的功能。

动态代理:
通过JDK提供的proxy这个类,动态为现有的业务生成代理类。
Proxy.newProxyInstance(loader,interfaces,h); //返回值就是动态代理对象

参数一loader:loader当前线程类加载器

参数二interfaces:生成代理类的接口类型

参数三h:通过代理对象调用方法是会优先进入参数三中的invoke方法

26 .mysql聚簇索引和非聚簇索引的区别是什么?

27.mysql如何实现高效的读写分离和分库分表?

28.mysql的原子性和持久性是如何实现的?

29.mysql 当前读、快照读,到底读的是什么?

30.Redis能够胜任存储工作

redis提供了非常丰富的集群模式:主从哨兵cluster,满足服务高可用的需求。同时,redis提供了两种持久化方式:aofrdb,常用的是rdb。

通过bgsave指令,主进程会fork出新的进程,回写磁盘。bgsave相当于做了一个快照,由于它并没有WAL日志和checkpoint机制,是无法做到实时备份的。如果机器突然断电,那就很容易丢失数据。

幸运的是,redis是内存型的数据库,主丛同步的速度是非常快的。如果你的集群维护的好,内存分配的合理,那么除非机房断电,否则redis的SLA,会一直保持在非常高的水平。

31.Reids应用场景

32.Redis的分布式锁

Redis的分布式锁,是一种轻量级的解决方案。虽然它的可靠性比不上Zookeeper之类的系统,但Redis分布式锁有着极高的吞吐量。

下面是一小段简单的分布式样例代码
public String lock(String key, int timeOutSecond) {
    for (; ; ) {
        String stamp = String.valueOf(System.nanoTime());
        boolean exist = redisTemplate.opsForValue().setIfAbsent(key, stamp, timeOutSecond, TimeUnit.SECONDS);
        if (exist) {
            return stamp;
        }
    }
}
public void unlock(String key, String stamp) {
    redisTemplate.execute(script, Arrays.asList(key), stamp);
}

删除操作的lua为。

local stamp = ARGV[1]
local key = KEYS[1]
local current = redis.call("GET",key)
if stamp == current then
    redis.call("DEL",key)
    return "OK"
end

33.redis分布式限流

使用计数器去实现简单的限流,在Redis中是非常方便的,只需要使用incr配合expire指令即可。
 
incr key
expire key 1

这种简单的实现,通常来说不会有问题,但在流量比较大的情况下,在时间跨度上会有流量突然飙升的风险。根本原因,就是这种时间切分方式太固定了,没有类似滑动窗口这种平滑的过度方案。

同样是redisson的RRateLimiter,实现了与guava中类似的分布式限流工具类,使用非常便捷。下面是一个简短的例子:

 RRateLimiter limiter = redisson.getRateLimiter("xjjdogLimiter");
 // 只需要初始化一次
 // 每2秒钟5个许可
 limiter.trySetRate(RateType.OVERALL, 5, 2, RateIntervalUnit.SECONDS);
 
 // 没有可用的许可,将一直阻塞    
 limiter.acquire(3);

34.redis可以实现简单的队列

在生产者端,使用LPUSH加入到某个列表中;在消费端,不断的使用RPOP指令取出这些数据,或者使用阻塞的BRPOP指令获取数据,适合小规模的抢购需求。

Redis还有PUB/SUB模式,不过pubsub更适合做消息广播之类的业务。

在Redis5.0中,增加了stream类型的数据结构。它比较类似于Kafka,有主题和消费组的概念,可以实现多播以及持久化,已经能满足大多数业务需求了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值