面試題之常見解決方案

  • 秒殺系統設計

     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,釋放表鎖
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章