面试题之常见解决方案

  • 秒杀系统设计

     1.解决超卖问题
       使用version方式的分布式锁,这样当并发的情况下,根据version字段作为条件来控制并发
     2.解决限流问题
       a.漏桶算法,有固定大小的容器,请求来了先缓存在容器中,然后以恒定速度进行处理,多余溢出的丢弃(单机限流)
       b.Google的Guava工具包中就提供了一个限流工具类——RateLimiter--RateLimiter是基于“令牌通算法”来实现限流,
         (单机限流)
       c.Sentinel方式(分布式限流)
       d.基于redis方式(分布式限流)
       详情请看[限流方案](https://www.cnblogs.com/luoxn28/p/11793251.html)
    
  • 分表分库生成ID

    1.专门建一张表,用来根据数据库自增id,来获取到一个全局id,然后分配给不同的表
      (库压力大,导致分库分表; 数据量大,导致分表)
    2.uuid方案,不太建议使用,导致主键长,本身都分库了,需要提高检索速度
    3.snowflake算法(雪花算法)
    
  • 数据库读写分离

  • 数据库读写分离问题

  • 线程池拒绝策略

    条件: coreSize线程使用完毕,任务队列已经满了,maxsize也使用完
    1.默认 AbortPolicy 直接抛出异常拒绝,被拒绝的任务丢失
    2.DiscardPolicy 不关心,不处理,实现是空方法
    3.CallerRunsPolicy 由调用的线程来处理拒绝任务,会阻塞调用线程
    4.DiscardOldestPolicy 丢弃老的任务,新拒绝任务进行retry
    
    测试代码:
    public class RejectPolicyTest {
          
          
    
    public static void main(String[] args) {
          
          
    
        LinkedBlockingQueue<Runnable> runnables = new LinkedBlockingQueue<>(10);
    
    
        //AbortPolicy拒绝策略
        /*ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5,
                0L, TimeUnit.MILLISECONDS,
                runnables);*/
    
    
        //DiscardPolicy拒绝策略
        /*ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5,
                0L, TimeUnit.MILLISECONDS,
                runnables, Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy());*/
    
    
        //CallerRunsPolicy拒绝策略
        /*ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5,
                0L, TimeUnit.MILLISECONDS,
                runnables, Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());*/
    
    
        //DiscardOldestPolicy拒绝策略
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 2,
                0L, TimeUnit.MILLISECONDS,
                runnables, Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());
    
    
        for(int i=0;i<20;i++){
          
          
    
            try {
          
          
    
                Object1 object1 = new Object1();
    
                threadPoolExecutor.execute(new Runnable() {
          
          
                    @Override
                    public void run() {
          
          
                        try {
          
          
                            Thread.sleep(10000);
                        } catch (InterruptedException e) {
          
          
                            e.printStackTrace();
                        }
    
                        System.out.println();
    
                        System.out.print("当前处理线程:"+Thread.currentThread().getName()+"==");
    
                        System.out.print("当前剩余任务:"+runnables.size()+"==");
    
                        System.out.print("当前处理任务:"+object1);
    
                        System.out.println();
                    }
                });
    
            }catch (Exception e){
          
          
                e.printStackTrace();
                System.out.println("任务"+(i)+"被拒绝");
            }
    
            System.out.println("添加任务"+i+"成功");
        }
    
        //threadPoolExecutor.shutdown();
    
    }}
    class Object1 {
          
          
    
    private static int j=0;
    
    private int i=0;
    
    public Object1() {
          
          
        this.i = j++;
    }
    
    @Override
    public String toString() {
          
          
        return "Object1{" +
                "i=" + i +
                '}';
    }
    }
    
    • 如何给大表加个字段
    1.几百万的表不算大表直接加字段索引就好了
    2.千万级别的表,创建个临时表B,加索引字段直接在B表加好,然后将原表A的数据直接靠到B表
      注意是分批拷贝过来,差不多要十多分钟,拷贝前记录一个时间t1. 拷贝完后, 在t1时间后肯定还有新数据
      进来,这个时候找出这些数据,一次性拷贝过来就好.
    3.停服务
    
    问题:方案2拷贝新数据的期间还有新数据进来怎么办
         我的方案是最后新数据拷贝量很少, 可以加表锁,然后拷贝,renametable,释放表锁
    

猜你喜欢

转载自blog.csdn.net/weixin_38312719/article/details/107074246