Java面試大全(2020年版)101-200

目錄

101. myBatis的緩存

MyBatis 的緩存分爲一級緩存和二級緩存, 一級緩存放在 session 裏面,默認就有,二級緩存放在它的命名空間裏,默認是打開的,二級緩存屬性類需要實現 Serializable 序列化接口(可用來保存對象的狀態),可在它的映射文 件中配置Mybatis中有一級緩存和二級緩存,默認情況下一級緩存是開啓的,而且是不能關閉的。
一級緩存是指SqlSession級別的緩存,當在同一個SqlSession中進行相同的SQL語句查詢時,第二次以後的查詢不會從數據庫查詢,而是直接從緩存中獲取,一級緩存最多緩存1024條SQL。二級緩存是指可以跨SqlSession的緩存。Mybatis中進行SQL查詢是通過org.apache.ibatis.executor.Executor接口進行的,總體來講,它一共有兩類實現,一類是BaseExecutor,一類是CachingExecutor。前者是非啓用二級緩存時使用的,而後者是採用的裝飾器模式,在啓用了二級緩存時使用,當二級緩存沒有命中時,底層還是通過BaseExecutor來實現的。
一級緩存
一級緩存是默認啓用的,在BaseExecutor的query()方法中實現,底層默認使用的是PerpetualCache實現,PerpetualCache採用HashMap存儲數據。一級緩存會在進行增、刪、改操作時進行清除。
二級緩存
二級緩存是默認啓用的,如想取消,則可以通過Mybatis配置文件中的元素下的子元素來指定cacheEnabled爲false。我們要想使用二級緩存,是需要在對應的Mapper.xml文件中定義其中的查詢語句需要使用哪個cache來緩存數據的。這有兩種方式可以定義,一種是通過cache元素定義,一種是通過cache-ref元素來定義。但是需要注意的是對於同一個Mapper來講,它只能使用一個Cache,當同時使用了和時使用定義的優先級更高。Mapper使用的Cache是與我們的Mapper對應的namespace綁定的,一個namespace最多隻會有一個Cache與其綁定

102. myBatis實現一對一和一對多分別有幾種方式,又都是怎麼操作的呢

  • 一對一有聯合查詢和嵌套查詢 聯合查詢是幾個表聯合查詢,只查詢一次,通過在resultMap裏面配置collection節點配置一對 多的類就可以完成;嵌套查詢是先查一個表,根據這個表裏面的結果的外鍵id,去再另外一個表裏面查詢數據,也是 通過配置collection,但另外一個表的查詢通過 select 節點配置
  • 一對多有聯合查詢和嵌套查詢 聯合查詢是幾個表聯合查詢,只查詢一次,通過在resultMap裏面配置collection節點配置一對 多的類就可以完成;嵌套查詢是先查一個表,根據這個表裏面的結果的外鍵id,去再另外一個表裏面查詢數據,也是 通過配置collection,但另外一個表的查詢通過 select 節點配置;

103. myBatis裏面的動態Sql是怎麼設定的?用什麼語法?

MyBatis 裏面的動態 Sql 一般是通過 if 節點來實現,通過 OGNL 語法來實現,但是如果要寫的 完整,必須配合where,trim 節點,where 節點是判斷包含節點有內容就插入 where,
否則不插 入,trim 節點是用來判斷如果動態語句是以 and 或 or 開始,那麼會自動把這個 and 或者 or 取 掉;

104. myBatis(IBatis)的好處是什麼

ibatis 把 sql 語句從 Java 源程序中獨立出來,放在單獨的 XML 文件中編寫,給程序的維護帶 來了很大便利。ibatis 封裝了底層 JDBC API 的調用細節,並能自動將結果集轉換成 Java Bean 對象,大大簡 化了 Java 數據庫編程的重複工作。因爲 Ibatis 需要程序員自己去編寫 sql 語句,程序員可以結合數據庫自身的特點靈活控制 sql 語句,因此能夠實現比 hibernate 等全自動 orm 框架更高的查詢效率,能夠完成複雜查詢。

105. 接口綁定有幾種實現方式,分別是怎麼實現的?

  • 一種是通過註解綁定,就是在接口的方法上面加上@Select@Update 等註解裏面包含 Sql 語句來綁定。
  • 另外一種就是通過 xml 裏面寫 SQL 來綁定,在這種情況下,要指定 xml 映射文件裏面的 namespace 必須爲接口的全路徑名;

106. 什麼情況下用註解綁定,什麼情況下用xml綁定

當Sql語句比較簡單時候,用註解綁定, 當SQL語句比較複雜時候,用 xml 綁定,一般用 xml 綁定的比較多;

107. Mapper動態代理開發

只寫接口,實現類由mybatis生成
四個原則:Mapper接口開發需要遵循以下規範

  • Mapper.xml文件中的namespace與mapper接口的類路徑相同。
  • Mapper接口方法名和Mapper.xml中定義的每個statement的id相同
  • Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相
  • Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultTpe的類型相同

108. 有關mybatis接口方法中傳入參數問題

mybatis參數傳遞主要分爲以下的五種情況

  • 單個參數:可以接受基本類型,對象類型,集合類型的值。這種情況MyBatis可直接使用這個參數,不需要經過任何處理。
  • 多個參數:任意多個參數,都會被MyBatis重新包裝成一個Map傳入。Map的key是param1,param2,0,1…,值就是參數的值。
  • 命名參數(推薦使用):爲參數使用@Param起一個名字,MyBatis就會將這些參數封裝進map中,key就是我們自己指定的名字
  • POJO:當這些參數屬於我們業務POJO時,我們直接傳遞POJO
  • Map:我們也可以封裝多個參數爲map,直接傳遞
  • 總結:
    • 當參數小於5時候通常使用@Param形式
    • 參數大於5時候使用JavaBean形式

109. Mybatis是如何將sql執行結果封裝爲目標對象並返回的?都有哪些映射形式?

第一種是使用標籤,逐一定義數據庫列名和對象屬性名之間的映射關係。第二種是使用sql列的別名功能,將列的別名書寫爲對象屬性名。有了列名與屬性名的映射關係後,Mybatis通過反射創建對象,同時使用反射給對象的屬性逐一賦值並返回,那些找不到映射關係的屬性,是無法完成賦值的。

110. 如何獲取自動生成的(主)鍵值?

insert 方法總是返回一個int值 ,這個值代表的是插入的行數。如果採用自增長策略,自動生成的鍵值在 insert 方法執行完後可以被設置到傳入的參數對象中。

111. Mybatis動態sql有什麼用?執行原理?有哪些動態sql?

Mybatis動態sql可以在Xml映射文件內,以標籤的形式編寫動態sql,執行原理是根據表達式的值 完成邏輯判斷並動態拼接sql的功能。
Mybatis提供了9種動態sql標籤:trim | where | set | foreach | if | choose | when | otherwise | bind。

112. Mbatis中使用到的設計模式

Mybatis至少使用到了以下的設計模式:

  • Builder模式,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、
    XMLStatementBuilder、CacheBuilder;
  • 工廠模式,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;
  • 單例模式,例如ErrorContext和LogFactory;
  • 代理模式,Mybatis實現的核心,比如MapperProxy、ConnectionLogger,用的jdk的動態代理;還有executor.loader包使用了cglib或者javassist達到延遲加載的效果;
  • 組合模式,例如SqlNode和各個子類ChooseSqlNode等;
  • 模板方法模式,例如BaseExecutor和SimpleExecutor,還有BaseTypeHandler和所有的子類例如IntegerTypeHandler;
  • 適配器模式,例如Log的Mybatis接口和它對jdbc、log4j等各種日誌框架的適配實現;
  • 裝飾者模式,例如Cache包中的cache.decorators子包中等各個裝飾者的實現;
  • 迭代器模式,例如迭代器模式PropertyTokenizer;

113. JDBC編程有哪些不足之處,MBatis是如何解決這些問題的?

  • 數據庫鏈接創建、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用數據庫鏈接池可解決此問題。
    • 解決:在SqlMapConfig.xml中配置數據鏈接池,使用連接池管理數據庫鏈接。
  • Sql語句寫在代碼中造成代碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java代碼。
    • 解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。
  • 向sql語句傳參數麻煩,因爲sql語句的where條件不一定,可能多也可能少,佔位符需要和參數一一對應。
    • 解決: Mybatis自動將java對象映射至sql語句。
  • 對結果集解析麻煩,sql變化導致解析代碼變化,且解析前需要遍歷,如果能將數據庫記錄封裝成pojo對象解析比較方便。
    • 解決:Mybatis自動將sql執行結果映射至java對象

114. 爲什麼說Mybatis是半自動ORM映射工具?它與全自動的區別在哪裏?

Hibernate屬於全自動ORM映射工具,使用Hibernate查詢關聯對象或者關聯集合對象時,可以根據對象關係模型直接獲取,所以它是全自動的。而Mybatis在查詢關聯對象或關聯集合對象時,需要手動編寫sql來完成,所以,稱之爲半自動ORM映射工具。

115. Mybatis是否支持延遲加載?如果支持,它的實現原理是什麼?

  • Mybatis僅支持association關聯對象和collection關聯集合對象的延遲加載,association指的就是一對一,collection指的就是一對多查詢。在Mybatis配置文件中,可以配置是否啓用延遲加載lazyLoadingEnabled=true|false。
  • 它的原理是,使用CGLIB創建目標對象的代理對象,當調用目標方法時,進入攔截器方法,比如調用a.getB().getName(),攔截器invoke()方法發現a.getB()是null值,那麼就會單獨發送事先保存好的查詢關聯B對象的sql,把B查詢上來,然後調用a.setB(b),於是a的對象b屬性就有值了,接着完成a.getB().getName()方法的調用。這就是延遲加載的基本原理。當然了,不光是Mybatis,幾乎所有的包括Hibernate,支持延遲加載的原理都是一樣的。

116. 使用MyBatis的mapper接口調用時有哪些要求?

  • Mapper接口方法名和mapper.xml中定義的每個sql的id相同;
  • Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同;
  • Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同;
  • Mapper.xml文件中的namespace即是mapper接口的類路徑。

117. 簡述Mybatis的插件運行原理,以及如何編寫一個插件。

  • Mybatis僅可以編寫針對ParameterHandler、ResultSetHandler、StatementHandler、Executor這4種接口的插件,Mybatis使用JDK的動態代理,爲需要攔截的接口生成代理對象以實現接口方法攔截功能,每當執行這4種接口對象的方法時,就會進入攔截方法,具體就是InvocationHandler的invoke()方法,當然,只會攔截那些你指定需要攔截的方法。
  • 編寫插件:實現Mybatis的Interceptor接口並複寫intercept()方法,然後在給插件編寫註解,指定要攔截哪一個接口的哪些方法即可,記住,別忘了在配置文件中配置你編寫的插件。

118. 什麼是spring?

Spring 是個java企業級應用的開源開發框架。Spring主要用來開發Java應用,但是有些擴展是針對構建J2EE平臺的web應用。Spring 框架目標是簡化Java企業級應用開發,並通過POJO爲基礎的編程模型促進良好的編程習慣。

119. 使用Spring框架的好處是什麼?

  • 輕量:Spring 是輕量的,基本的版本大約2MB。
  • 控制反轉:Spring通過控制反轉實現了鬆散耦合,對象們給出它們的依賴,而不是創建或查找依賴的對象們。
  • 面向切面的編程(AOP):Spring支持面向切面的編程,並且把應用業務邏輯和系統服務分開。
  • 容器:Spring 包含並管理應用中對象的生命週期和配置。
  • MVC框架:Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品。
  • 事務管理:Spring 提供一個持續的事務管理接口,可以擴展到上至本地事務下至全局事務(JTA)。
  • 異常處理:Spring 提供方便的API把具體技術相關的異常(比如由JDBC,Hibernate or JDO拋出的)轉化爲一致的unchecked 異常。

120. 解釋AOP模塊

AOP模塊用於發給我們的Spring應用做面向切面的開發, 很多支持由AOP聯盟提供,這樣就確保了Spring和其他AOP框架的共通性。這個模塊將元數據編程引入Spring。

121. 在Spring AOP 中,關注點和橫切關注的區別是什麼?

  • 關注點是應用中一個模塊的行爲,一個關注點可能會被定義成一個我們想實現的一個功能。
  • 橫切關注點是一個關注點,此關注點是整個應用都會使用的功能,並影響整個應用,比如日誌,安全和數據傳輸,幾乎應用的每個模塊都需要的功能。因此這些都屬於橫切關注點。

122. 什麼是代理?

代理是通知目標對象後創建的對象。從客戶端的角度看,代理對象和目標對象是一樣的。

123. 談談你對spring IOC和DI的理解

IoC Inverse of Control 反轉控制的概念,就是將原本在程序中手動創建UserService對象的控制權,交由Spring框架管理,簡單說,就是創建UserService對象控制權被反轉到了Spring框架
DI:Dependency Injection 依賴注入,在Spring框架負責創建Bean對象時,動態的將依賴對象注入到Bean組件

124. BeanFactory接口和ApplicationContext接口有什區別?

  • ApplicationContext 接口繼承BeanFactory接口,Spring核心工廠是BeanFactory ,BeanFactory採取延遲加載,第一次getBean時纔會初始化Bean, ApplicationContext是會在加載配置文件時初始化Bean。
  • ApplicationContext是對BeanFactory擴展,它可以進行國際化處理、事件傳遞和bean自動裝配以及各種不同應用層的Context實現 開發中基本都在使用ApplicationContext, web項目使用WebApplicationContext ,很少用到BeanFactory
    BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(“applicationContext.xml”));
    IHelloService helloService = (IHelloService) beanFactory.getBean(“helloService”);
    helloService.sayHello();

125. Bean注入屬性有哪幾種方式?

  • spring支持構造器注入和setter方法注入
  • 構造器注入,通過 元素完成注入
  • setter方法注入, 通過 元素完成注入【開發中常用方式】

126. 什麼是AOP,AOP的作用是什麼?

面向切面編程(AOP)提供另外一種角度來思考程序結構,通過這種方式彌補了面向對象編程(OOP)的不足,除了類(classes)以外,AOP提供了切面。切面對關注點進行模塊化,例如橫切多個類型和對象的事務管理
Spring的一個關鍵的組件就是AOP框架,可以自由選擇是否使用AOP 提供聲明式企業服務,特別是爲了替代EJB聲明式服務。最重要的服務是聲明性事務管理,這個服務建立在Spring的抽象事物管理之上。允許用戶實現自定義切面,用AOP來完善OOP的使用,可以把Spring AOP看作是對Spring的一種增強

127. Spring的核心類有哪些,各有什麼作用

  • BeanFactory:產生一個新的實例,可以實現單例模式
  • BeanWrapper:提供統一的get及set方法
  • ApplicationContext:提供框架的實現,包括BeanFactory的所有功能

128. 介紹一個spring的事物管理

事務就是對一系列的數據庫操作(比如插入多條數據)進行統一的提交或回滾操作,如果插入成功,那麼一起成功,如果中間有一條出現異常,那麼回滾之前的所有操作。這樣可以防止出現髒數據,防止數據庫數據出現問題。
開發中爲了避免這種情況一般都會進行事務管理。Spring中也有自己的事務管理機制,一般是使用TransactionMananger進行管 理,可以通過Spring的注入來完成此功能。spring提供了幾個關於事務處理的類:
TransactionDefinition //事務屬性定義
TranscationStatus //代表了當前的事務,可以提交,回滾。
PlatformTransactionManager這個是spring提供的用於管理事務的基礎接口,其下有一個實現的抽象類 AbstractPlatformTransactionManager,我們使用的事務管理類例如 DataSourceTransactionManager等都是這個類的子類。

129. 怎樣用註解的方式配置spring?

  • Spring在2.5版本以後開始支持用註解的方式來配置依賴注入。可以用註解 的方式來替代XML方式的bean描述,可以將bean描述轉移到組件類的內部,只需要在相關類上、方法上或者字段聲明上使用註解即可。註解注入將會被容器在XML注入之前被處理,所以後者會覆蓋掉前者對於同一個屬性的處理結果。
  • 註解裝配在Spring中是默認關閉的。所以需要在Spring文件中配置一下才能使用基於註解的裝配模式。如果你想要在你的應用程序中使用關於註解的方法的話,請參考如下的配置。
  • <context:annotation-config/>標籤配置完成以後,就可以用註解的方式在Spring中向屬性、方法和構造方法中自動裝配變量。
    下面是幾種比較重要的註解類型:
    • @Required:該註解應用於設值方法。
    • @Autowired:該註解應用於有值設值方法、非設值方法、構造方法和變量。
    • @Qualifier:該註解和@Autowired註解搭配使用,用於消除特定bean自動裝配的歧義。
    • JSR-250 Annotations:Spring支持基於JSR-250 註解的以下註解,@Resource、@PostConstruct 和 @PreDestroy。

130. 簡述一下spring框架的優點?

  • 方便解耦,簡化開發 (高內聚低耦合)
    Spring就是一個大工廠(容器),可以將所有對象創建和依賴關係維護,交給Spring管理;Spring工廠是用於生成bean
  • AOP編程的支持
    Spring提供面向切面編程,可以方便的實現對程序進行權限攔截、運行監控等功能
    聲明式事務的支持,
  • 只需要通過配置就可以完成對事務的管理,而無需手動編程
    方便程序的測試
  • Spring對Junit4支持,可以通過註解方便的測試Spring程序
    方便集成各種優秀框架
  • Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持

131. 簡述一下IOC容器對BEAN的生命週期?

  • 通過構造器或工廠方法創建 Bean 實例
  • 爲Bean 的屬性設置值和對其他 Bean 的引用
  • 將Bean 實 例 傳 遞 給 Bean 後 置 處 理 器 的 postProcessBeforeInitialization 方法
  • 調用 Bean 的初始化方法(init-method)
  • 將 Bean 實 例 傳 遞 給 Bean 後 置 處 理 器 的 postProcessAfterInitialization 方法
  • Bean 可以使用了
  • 當容器關閉時, 調用 Bean 的銷燬方法(destroy-method)

132. 在Spring中AOP的使用場景有哪些?

  • 主要的功能是:日誌記錄,性能統計,安全控制,事務處理,異常處理等等。
  • 主要的意圖是:將日誌記錄,性能統計,安全控制,事務處理,異常處理等代碼從業 務邏輯代碼中劃分出來,通過對這些行爲的分離,我們希望可以將它們獨立到非指導業務 邏輯的方法中,進而改 變這些行爲的時候不影響業務邏輯的代碼。

133. Spring支持的事務管理類型

Spring支持兩種類型的事務管理:

  • 編程式事務管理:這意味你通過編程的方式管理事務,給你帶來極大的靈活性,但是難維護。
  • 聲明式事務管理:這意味着你可以將業務代碼和事務管理分離,你只需用註解和XML配置來管理事務。

134. Spring分佈式事務如何處理的

  • 第一種方案:可靠消息最終一致性,需要業務系統結合 MQ消息中間件實現,在實現過程中需要保證消息的成功發送及成功消費。即需要通過業務系統控制 MQ的消息狀態;
  • 第二種方案:TCC補償性,分爲三個階段 TRYING-CONFIRMING-CANCELING。每個階段做不同的處理。
    • TRYING階段主要是對業務系統進行檢測及資源預留
    • CONFIRMING階段是做業務提交,通過 TRYING階段執行成功後,再執行該階段。默認如果 TRYING階段執行成功,CONFIRMING就一定能成功。
    • CANCELING階段是回對業務做回滾,在 TRYING階段中,如果存在分支事務 TRYING失敗,則需要調用 CANCELING將已預留的資源進行釋放

135. 什麼是SpringBoot

Spring Boot是Spring社區發佈的一個開源項目,旨在幫助開發者快速並且更簡單的構建項目。大多數SpringBoot項目只需要很少的配置文件。

136. SpringBoot核心功能

  • 獨立運行Spring項目:Spring boot 可以以jar包形式獨立運行,運行一個Spring Boot項目只需要通過java -jar xx.jar來運行。
  • 內嵌servlet容器:Spring Boot可以選擇內嵌Tomcat、jetty或者Undertow,這樣我們無須以war包形式部署項目。
  • 提供starter簡化Maven配置: spring提供了一系列的start pom來簡化Maven的依賴加載,例如,當你使用了spring-boot-starter-web,會自動加入如圖5-1所示的依賴包。
  • 自動裝配Spring:SpringBoot會根據在類路徑中的jar包,類、爲jar包裏面的類自動配置Bean,這樣會極大地減少我們要使用的配置。當然,SpringBoot只考慮大多數的開發場景,並不是所有的場景,若在實際開發中我們需要配置Bean,而SpringBoot滅有提供支持,則可以自定義自動配置。
  • 準生產的應用監控:SpringBoot提供基於http ssh telnet對運行時的項目進行監控。
  • 無代碼生產和xml配置:SpringBoot不是藉助與代碼生成來實現的,而是通過條件註解來實現的,這是Spring4.x提供的新特性。

137. SpringBoot優缺點

  • 優點:
    • 快速構建項目。
    • 對主流開發框架的無配置集成。
    • 項目可獨立運行,無須外部依賴Servlet容器。
    • 提供運行時的應用監控。
    • 極大的提高了開發、部署效率。
    • 與雲計算的天然集成。
  • 缺點:
    • 如果你不認同spring框架,也許這就是缺點。

138. SpringBoot特性

  • 創建獨立的Spring項目
  • 內置Tomcat和Jetty容器
  • 提供一個starter POMs來簡化Maven配置
  • 提供了一系列大型項目中常見的非功能性特性,如安全、指標,健康檢測、外部配置等
  • 完全沒有代碼生成和xml配置文件

139. SpringBoot CLI

SpringBoot CLI 是SpringBoot提供的控制檯命令工具。

140. SpringBoot maven構建項目

spring-boot-starter-parent:是一個特殊Start,它用來提供相關的Maven依賴項,使用它之後,常用的包依賴可以省去version標籤。

141. SpringBoot幾個常用的註解

  • @RestController和@Controller指定一個類,作爲控制器的註解
  • @RequestMapping方法級別的映射註解,這一個用過Spring MVC的小夥伴相信都很熟悉
  • @EnableAutoConfiguration和@SpringBootApplication是類級別的註解,根據maven依賴的jar來自動猜測完成正確的spring的對應配置,只要引入了spring-boot-starter-web的依賴,默認會自動配置Spring MVC和tomcat容器
  • @Configuration類級別的註解,一般這個註解,我們用來標識main方法所在的類,完成元數據bean的初始化。
  • @ComponentScan類級別的註解,自動掃描加載所有的Spring組件包括Bean注入,一般用在main方法所在的類上
  • @ImportResource類級別註解,當我們必須使用一個xml的配置時,使用@ImportResource和@Configuration來標識這個文件資源的類。
  • @Autowired註解,一般結合@ComponentScan註解,來自動注入一個Service或Dao級別的Bean
  • @Component類級別註解,用來標識一個組件,比如我自定了一個filter,則需要此註解標識之後,Spring Boot纔會正確識別。

142. Springboot解決那些問題

  • 編碼更簡單
    • Spring框架由於超重量級的 XML,annotation配置,使得系統變得很笨重,難以維護
    • Springboot採用約點大於配置的方法,直接引入依賴,即可實現代碼的開發
  • 配置更簡單
    • Xml文件使用 javaConfig代替,XML中 bean的創建,使用@bean代替後可以直接注入。
    • 配置文件變少很多,就是 application.yml
  • 部署更簡單
    • 一鍵啓動,一鍵解壓; ②不需要應用服務器:Tomcat(X)weblogic(x);
    • 降低對運行環境基本要求:部署環境只需要有JDK即可,默認內置tomcat服務器
  • 監控更簡單
    • Spring-boot-start-actuator: 可以查看屬性配置;線程工作狀態;環境變量;
    • JVM性能監控

143. 什麼是SpringCloud

Spring cloud是一個基於Spring Boot實現的服務治理工具包,在微服務架構中用於管理和協調服務的。
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的開發便利性巧妙地簡化了分佈式系統基礎設施的開發,如服務發現註冊、配置中心、消息總線、負載均衡、斷路器、數據監控等,都可以用Spring Boot的開發風格做到一鍵啓動和部署

144. SpringCloud組成

  • 服務發現——Netflix Eureka
  • 客服端負載均衡——Netflix Ribbon/Feign
  • 服務網關——Netflix Zuul
  • 斷路器——Netflix Hystrix
  • 分佈式配置——Spring Cloud Config

145. SpringCloud特性

  • 分佈式/版本化配置。
  • 服務註冊和發現。
  • 路由。
  • 服務和服務之間的調用。
  • 負載均衡。
  • 斷路器。
  • 分佈式消息傳遞。

146. SpringCloud優缺點

  • Spring Cloud 來源於 Spring,質量、穩定性、持續性都可以得到保證。
  • Spirng Cloud 天然支持 Spring Boot,更加便於業務落地。
  • Spring Cloud 發展非常的快,從 2016 年開始接觸的時候相關組件版本爲 1.x,到現在將要發佈 2.x 系列。
  • Spring Cloud 是 Java 領域最適合做微服務的框架。
  • 相比於其它框架,Spring Cloud 對微服務周邊環境的支持力度最大。
  • 對於中小企業來講,使用門檻較低。
  • Spring Cloud 是微服務架構的最佳落地方案。

147. SpringCloud常用註解

  • @Mapper:  註解寫在你的Mapper映射接口上面
  • @SpringBootApplication:  寫在主程序上面
  • @Configuration:   寫在配置類上面
  • @Bean:  寫在配置類中的返回新的對象的方法上面
  • @EnableEurekaServer:  把當前微服務標記爲Eureka註冊中心 接收其他微服務的註冊
  • @EnableEurekaClient:  註冊該微服務到Eureka中
  • @LoadBalanced:  該註解寫在配置RestTemplate的配置類方法上來啓動ribbon負載均衡
  • @EnableFeignClients:  寫在主程序上來支持feign
  • @HystrixCommand(fallbackMethod=“你的方法”)
  • @EnableCircuitBreaker :  啓用對Hystrix熔斷機制的支持
  • @FeignClient(value=“服務名”,fallbackFactory=實現FallbackFactory的類.class):  實現服務降級
  • @EnableHystrixDashboard:   加在主程序上啓動服務監控
  • @FeignClient(value=“服務名”):  寫在接口上 來調用遠程服務
  • @EnableZuulProxy:  寫在主程序上啓動zuul路由訪問功能

148. 線程和進程的區別:

  • 進程是一個 “執行中的程序”,是系統進行資源分配和調度的一個獨立單位;
  • 線程是進程的一個實體,一個進程中擁有多個線程,線程之間共享地址空間和其它資源(所以通信和同步等操作線程比進程更加容易);
  • 線程上下文的切換比進程上下文切換要快很多。
    • 進程切換時,涉及到當前進程的 CPU 環境的保存和新被調度運行進程的 CPU 環境的設置。
    • 線程切換僅需要保存和設置少量的寄存器內容,不涉及存儲管理方面的操作。

149. 什麼是阻塞(Blocking)和非阻塞(Non-Blocking)?

阻塞和非阻塞通常用來形容多線程間的相互影響。比如一個線程佔用了臨界區資源,那麼其他所有需要這個而資源的線程就必須在這個臨界區中進行等待。等待會導致線程掛起,這種情況就是阻塞。此時,如果佔用資源的線程一直不願意釋放資源,那麼其他所有阻塞在這個臨界區上的線程都不能工作。
非阻塞的意思與之相反,它強調沒有一個線程可以妨礙其他線程執行。所有的線程都會嘗試不斷前向執行。

150. Java 中線程有幾種狀態?

六種(查看 Java 源碼也可以看到是 6 種),並且某個時刻 Java 線程只能處於其中的一個狀態。

  • 新建(NEW)狀態:表示新創建了一個線程對象,而此時線程並沒有開始執行。
  • 可運行(RUNNABLE)狀態:線程對象創建後,其它線程(比如 main 線程)調用了該對象的 start() 方法,才表示線程開始執行。當線程執行時,處於 RUNNBALE 狀態,表示線程所需的一切資源都已經準備好了。該狀態的線程位於可運行線程池中,等待被線程調度選中,獲取 cpu 的使用權。
  • 阻塞(BLOCKED)狀態:如果線程在執行過程終於到了 synchronized 同步塊,就會進入 BLOCKED 阻塞狀態,這時線程就會暫停執行,直到獲得請求的鎖。
  • 等待(WAITING)狀態:當線程等待另一個線程通知調度器一個條件時,它自己進入等待狀態。在調用Object.wait方法或Thread.join方法,或者是等待java.util.concurrent庫中的Lock或Condition時,就會出現這種情況;
  • 計時等待(TIMED_WAITING)狀態:Object.wait、Thread.join、Lock.tryLock和Condition.await 等方法有超時參數,還有 Thread.sleep 方法、LockSupport.parkNanos 方法和 LockSupport.parkUntil 方法,這些方法會導致線程進入計時等待狀態,如果超時或者出現通知,都會切換會可運行狀態;
  • 終止(TERMINATED)狀態:當線程執行完畢,則進入該狀態,表示結束。
    注意:從 NEW 狀態出發後,線程不能再回到 NEW 狀態,同理,處於 TERMINATED 狀態的線程也不能再回到RUNNABLE 狀態

151. sleep( ) 和 wait( n)、wait( ) 的區別:

  • sleep 方法:是 Thread 類的靜態方法,當前線程將睡眠 n 毫秒,線程進入阻塞狀態。當睡眠時間到了,會解除阻塞,進行可運行狀態,等待 CPU 的到來。睡眠不釋放鎖(如果有的話);
  • wait 方法:是 Object 的方法,必須與 synchronized 關鍵字一起使用,線程進入阻塞狀態,當 notify 或者notifyall 被調用後,會解除阻塞。但是,只有重新佔用互斥鎖之後纔會進入可運行狀態。睡眠時,釋放互斥鎖;

152. synchronized 關鍵字:

  • 底層實現:
    • 進入時,執行 monitorenter,將計數器 +1,釋放鎖 monitorexit 時,計數器-1;
    • 當一個線程判斷到計數器爲 0 時,則當前鎖空閒,可以佔用;反之,當前線程進入等待狀態。
  • 含義:(monitor 機制)
    • Synchronized 是在加鎖,加對象鎖。對象鎖是一種重量鎖(monitor),synchronized 的鎖機制會根據線程競爭情況在運行時會有偏向鎖(單一線程)、輕量鎖(多個線程訪問 synchronized 區域)、對象鎖(重量鎖,多個線程存在競爭的情況)、自旋鎖等。

153. 什麼是進程

進程是指運行中的應用程序,每個進程都有自己獨立的地址空間(內存空間)。
比如用戶點擊桌面的IE瀏覽器,就啓動了一個進程,操作系統就會爲該進程分配獨立的地址空間。當用戶再次點擊左邊的IE瀏覽器,又啓動了一個進程,操作系統將爲新的進程分配新的獨立的地址空間。目前操作系統都支持多進程。

154. 什麼是線程

進程是表示自願分配的基本單位。而線程則是進程中執行運算的最小單位,即執行處理機調度的基本單位。通俗來講:一個程序有一個進程,而一個進程可以有多個線程。

155. 多線程的幾種實現方式

  • 繼承Thread類創建線程
    Thread類本質上是實現了Runnable接口的一個實例,代表一個線程的實例。啓動線程的唯一方法就是通過Thread類的start()實例方法。start()方法將啓動一個新線程,並執行run()方法。這種方式實現多線程比較簡單,通過自己的類直接繼承Thread,並重寫run()方法,就可以啓動新線程並執行自己定義的run()方法。
  • 實現Runnable接口創建線程
    如果自己的類已經繼承了兩一個類,就無法再繼承Thread,因此可以實現一個Runnable接口
  • 實現Callable接口通過FutureTask包裝器來創建Thread線程
  • 使用ExecutorService、Callable、Future實現有返回結果的線程
    ExecutorService、Callable、Future三個接口實際上都是屬於Executor框架。返回結果的線程是在JDK1.5中引入的新特徵,有了這種特徵就不需要再爲了得到返回值而大費周折了。
    可返回值的任務必須實現Callable接口;無返回值的任務必須實現Runnabel接口。
    執行Callable任務後,可以獲取一個Future對象,在該對象上調用get()方法就可以獲取到Callable任務返回的Object了。(get()方法是阻塞的,線程無返回結果,該方法就一直等待)

156. Vector、SimpleDateFormat是線程安全類嗎

Vector類的單個方法是原子性的,符合操作不是原子性的
SimpleDateFormat類不是線程安全的

157. 哪些集合類是線程安全的

  • Vector
  • Stack
  • hashtable
  • enumeration
  • StringBuffer

158. 多線程中忙循環是什麼

忙循環就是程序員用循環讓一個線程等待,不像傳統方法wait()、sleep()或者yied()它們都放棄了CPU控制,而忙循環不會放棄CPU,它就是在運行一個空循環。這麼做的目的是爲了保留CPU緩存,在多核系統中,一個等待線程醒來的時候可能會在另一個內核運行,這樣會重建緩存。爲了避免重建緩存和減少等待重建的時間就可以使用它了。

159. 什麼是線程局部變量

ThreadLocal並非是一個線程本地實現版本,它並不是一個Thread,而是threadlocalvariable(線程局部變量)。也許把它命名爲ThreadLocalVar更合適。線程局部變量(ThreadLocal)功能非常簡單,就是爲每一個使用該變量的線程都提供了一個變量值副本,是java中一種較爲特殊的線程綁定機制,是每一個線程都可以獨立地改變自己的副本,而不會和其他線程的副本衝突。

160. 什麼是多線程環境下的僞共存(false sharing)

緩存系統中是以緩存行爲單位存儲的。緩存行是2的整數冪個連續字節,一般爲32-256個字節。最常見的緩存行大小是64個字節。當多線程修改互相獨立的變量時,如果這些變量共享同一個緩存航,就會無意中影響彼此的性能,這就是僞共存

161. 同步和異步有何不同,在什麼情況下分別使用它們?舉例說明

如果數據將在線程間共享。例如:正在寫的數據以後可能會被另一個線程讀到,或者正在讀的數據可能已經被另一個線程寫過了,那麼這些數據就是共享數據,必須進行同步存取
當應用程序在對象上調用了一個需要花費很長時間來執行的方法,並且不希望讓程序等待方法的返回時,就應該使用異步編程,在很多情況下采用異步途徑往往更有效。
同步交互:指發送一個請求,需要等待返回,然後才能發送下一個請求,有個等待的過程
異步交互:指發送一個請求,不需要等待返回,隨時可以再發送下一個請求,即不需要等待。
區別:一個需要等待,一個不需要等待

162. Thread類中的strat()和run()方法有什麼區別?

start()方法被用來啓動新創建的線程,而且start()內部調用了run()方法,這和直接調用run()方法的效果不一樣。當你調用run()方法的時候,只會在原來的線程中調用,沒有新的線程啓動,而調用start()方法會啓動一個新的線程。

163. java中Runnable和Callable的區別

Runnable和Callable都代表那些要在不同的線程中執行的任務。Runnable從JDK1.0開始就有了,Callable是在JDK1.5增加的。
他們的主要區別是Callable的call()方法可以返回值和拋出異常,而Runnable的run()方法沒有這些功能。Callable可以返回裝載有計算結果的Future對象。

164. 什麼是線程安全?

如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果都是一樣的,而且其他變量的值也和預期的是一樣的,就是線程安全的。一個線程安全的計數器類的同一個實例對象在被多個線程使用的情況下也不會出現計算失誤。

165. 如何在兩個線程間共享數據?

可以通過共享對象來實現這個目的,或者是使用阻塞隊列,或者使用wait()和notify()方法

167. 鎖池和等待池

鎖池:假設線程A已經擁有了某個對象的鎖,而其它的線程想要調用這個對象的某個Synchronized方法(或者Synchronized代碼塊),由於這些線程在進入對象的synchronized方法之前必須先獲得該對象的鎖的擁有權,但是該對象的鎖目前正被線程A擁有,所以這個線程就進入了該對象的鎖池中
等待池:假設一個線程A調用了某個對象的wait()方法,線程A就會釋放該對象的鎖後,進入到該對象的等待池中。

168. 什麼是FutureTask?

在java併發程序中FutureTask表示一個可以取消的異步運算。它有啓動和取消運算、查詢運算是否完成和取回運算結果等方法。只有當運算完成的時候結果才能返回,如果運算尚未完成,get()方法將會阻塞。一個FutureTask對象可以對調用了Callable和Runnable的對象進行包裝,由於FutureTask也是調用了Runnbale接口所以它可以提交給Executor來執行

169. 爲什麼你應該在循環中檢查等待條件

處於等待狀態的線程可能會受到錯誤警報和僞喚醒,如果不在循環中檢查等待條件,程序就會在沒有滿足結束條件的情況下推出。因此,當一個等待線程醒來時,不能認爲它原來的等待狀態仍然是有效的,在notify()方法調用之後和等待線程醒來之前這段時間它可能會改變。這就是在循環中使用wait()方法效果更好的原因。

170. java中堆和棧有什麼不同?

爲什麼把這個問題歸類在多線程和併發面試題裏?因爲棧是一塊和線程緊密相關的內存區域。每個線程都有自己的棧內存,用於存儲本地變量、方法參數和棧調用,一個線程中存儲的變量對其他線程是不可見的。而堆是所有線程共享的一片公共內存區域。對象都在堆裏創建,爲了提升效率,線程會從堆中弄一個緩存到自己的棧,如果多個線程使用該變量就可能引發問題,這時volatile變量就可以發揮作用了,它要求線程從主存中讀取變量的值

171. 什麼是線程池?爲什麼要使用它?

創建線程需要花費昂貴的資源和時間,如果任務來了才創建線程那麼響應時間會變成,而且一個進程能創建的線程數有限。爲了避免這些問題,在程序啓動的時候就創建若干線程來響應處理,他們被稱爲線程池,裏面的線程叫工作線程。從JDK1.5開始,java API提供了Executor框架讓你可以創建不同的線程池。比如單線程喫,數目固定的線程池等
25.有三個線程T1、T2和T3,怎麼確保它們按照順序執行?
答:在多線程中有多重方法讓線程按特定的順序執行,你可以用線程類的join()方法在一個線程中啓動另一個線程,另外一個線程完成該線程繼續執行。爲了確保三個線程的順序你應該先啓動最後一個(T3調用T2,T2調用T1),這樣T1就會先完成而T3最後完成

172. 什麼是阻塞式方式?

阻塞式方式是指程序會一直等待該方法完成期間不做其他事情,ServiceSocket的accept()方法就是一直等待客戶端連接。這裏的阻塞是指調用結果返回之前,當前線程會被掛起,直到等到結果之後纔會返回。此外,還有異步和非阻塞式方法在任務完成前就返回。

173. 接口與接口之間的調用,如何保證數據安全

  • 通信使用https
  • 請求籤名,防止參數被篡改
  • 身份確認機制,每次請求都要驗證是否合法
  • app中使用ssl pinning 防止抓包操作
  • 對所有請求和響應都進行加解密操作:ssl pinning:它是在開發時就將服務端證書(ssl證書)一塊打包到客戶端裏。這樣在HTTPS建立時與服務端返回的證書比對一致性,進而識別出中間人攻擊後直接在客戶端側中止連接。
    在實際的工作中,情況差不多爲以下(分兩種):
  • 公司內部的接口:公司內部的接口,當然是涉及到比較隱祕信息的時候,調用方需要持有一個私鑰,調用的時候將傳入的參數通過私鑰進行的加密,若加密後的內容能夠被公鑰解密,那麼則能夠通過。
  • 調用第三方的接口:在調用第三方的接口的時候,實現的方式也有兩種:
    • 利用私鑰加密。
    • 利用http的請求頭的要求數據和格式展開訪問控制,如:在調用第三方接口的時候,需要head中的內容必須是:token:xxx,sign:xxx,client_id:xxx,且sign是經過加密的內容。從而達到訪問控制。

174. HTTPS的優點

儘管HTTPS並非絕對安全,掌握根證書的機構、掌握加密算法的組織同樣可以進行中間人形式的攻擊,但HTTPS仍是現行架構下最安全的解決方案,主要有以下幾個好處:

  • 使用HTTPS協議可認證用戶和服務器,確保數據發送到正確的客戶機和服務器;
  • HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全,可防止數據在傳輸過程中不被竊取、改變,確保數據的完整性。
  • HTTPS是現行架構下最安全的解決方案,雖然不是絕對安全,但它大幅增加了中間人攻擊的成本。
  • 谷歌曾在2014年8月份調整搜索引擎算法,並稱“比起同等HTTP網站,採用HTTPS加密的網站在搜索結果中的排名將會更高”。

175. HTTPS的缺點

雖然說HTTPS有很大的優勢,但其相對來說,還是存在不足之處的:

  • HTTPS協議握手階段比較費時,會使頁面的加載時間延長近50%,增加10%到20%的耗電;
  • HTTPS連接緩存不如HTTP高效,會增加數據開銷和功耗,甚至已有的安全措施也會因此而受到影響;
  • SSL證書需要錢,功能越強大的證書費用越高,個人網站、小網站沒有必要一般不會用。
  • HTTPS協議的加密範圍也比較有限,在黑客攻擊、拒絕服務攻擊、服務器劫持等方面幾乎起不到什麼作用。最關鍵的,SSL證書的信用鏈體系並不安全,特別是在某些國家可以控制CA根證書的情況下,中間人攻擊一樣可行。

176. HTTP與HTTPS有什麼區別?

HTTP協議傳輸的數據都是未加密的,也就是明文的,因此使用HTTP協議傳輸隱私信息非常不安全,爲了保證這些隱私數據能加密傳輸,於是網景公司設計了SSL(Secure Sockets Layer)協議用於對HTTP協議傳輸的數據進行加密,從而就誕生了HTTPS。簡單來說,HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全。
HTTPS和HTTP的區別主要如下:

  • https協議需要到ca申請證書,一般免費證書較少,因而需要一定費用。
  • http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
  • http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,後者是443。
  • http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

177. Redis有哪些數據結構?

字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。
如果你是Redis中高級用戶,還需要加上下面幾種數據結構HyperLogLog、Geo、Pub/Sub。
如果你說還玩過Redis Module,像BloomFilter,RedisSearch,Redis-ML,面試官得眼睛就開始發亮了。

178. 使用過Redis分佈式鎖麼,它是什麼回事?

先拿setnx來爭搶鎖,搶到之後,再用expire給鎖加一個過期時間防止鎖忘記了釋放。
這時候對方會告訴你說你回答得不錯,然後接着問如果在setnx之後執行expire之前進程意外crash或者要重啓維護了,那會怎麼樣?
這時候你要給予驚訝的反饋:唉,是喔,這個鎖就永遠得不到釋放了。緊接着你需要抓一抓自己得腦袋,故作思考片刻,好像接下來的結果是你主動思考出來的,然後回答:我記得set指令有非常複雜的參數,這個應該是可以同時把setnx和expire合成一條指令來用的!

179. Redis裏面有1億個key,其中有10w個key是以某個固定的已知的前綴開頭的,如何將它們全部找出來?

使用keys指令可以掃出指定模式的key列表。
對方接着追問:如果這個redis正在給線上的業務提供服務,那使用keys指令會有什麼問題?
這個時候你要回答redis關鍵的一個特性:redis的單線程的。keys指令會導致線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key列表,但是會有一定的重複概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。

180. 使用過Redis做異步隊列麼,你是怎麼用的?

一般使用list結構作爲隊列,rpush生產消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep一會再重試。
如果對方追問可不可以不用sleep呢?list還有個指令叫blpop,在沒有消息的時候,它會阻塞住直到消息到來。
如果對方追問能不能生產一次消費多次呢?使用pub/sub主題訂閱者模式,可以實現1:N的消息隊列。
如果對方追問pub/sub有什麼缺點?在消費者下線的情況下,生產的消息會丟失,得使用專業的消息隊列如rabbitmq等。
如果對方追問redis如何實現延時隊列?我估計現在你很想把面試官一棒打死如果你手上有一根棒球棍的話,怎麼問的這麼詳細。但是你很剋制,然後神態自若的回答道:使用sortedset,拿時間戳作爲score,消息內容作爲key調用zadd來生產消息,消費者用zrangebyscore指令獲取N秒之前的數據輪詢進行處理。

181. 如果有大量的key需要設置同一時間過期,一般需要注意什麼?

如果大量的key過期時間設置的過於集中,到過期的那個時間點,redis可能會出現短暫的卡頓現象。一般需要在時間上加一個隨機值,使得過期時間分散一些。

182. Redis如何做持久化的?

bgsave做鏡像全量持久化,aof做增量持久化。因爲bgsave會耗費較長時間,不夠實時,在停機的時候會導致大量丟失數據,所以需要aof來配合使用。在redis實例重啓時,優先使用aof來恢復內存的狀態,如果沒有aof日誌,就會使用rdb文件來恢復。
如果再問aof文件過大恢復時間過長怎麼辦?你告訴面試官,Redis會定期做aof重寫,壓縮aof文件日誌大小。如果面試官不夠滿意,再拿出殺手鐗答案,Redis4.0之後有了混合持久化的功能,將bgsave的全量和aof的增量做了融合處理,這樣既保證了恢復的效率又兼顧了數據的安全性。這個功能甚至很多面試官都不知道,他們肯定會對你刮目相看。
如果對方追問那如果突然機器掉電會怎樣?取決於aof日誌sync屬性的配置,如果不要求性能,在每條寫指令時都sync一下磁盤,就不會丟失數據。但是在高性能的要求下每次都sync是不現實的,一般都使用定時sync,比如1s1次,這個時候最多就會丟失1s的數據。

183. 使用redis的目的是什麼?

項目中使用redis一般都是作爲緩存來使用的,緩存的目的就是爲了減輕數據庫的壓力提高存取的效率。

184. Redis的同步機制瞭解麼?

從從同步。第一次同步時,主節點做一次bgsave,並同時將後續修改操作記錄到內存buffer,待完成後將rdb文件全量同步到複製節點,複製節點接受完成後將rdb鏡像加載到內存。加載完成後,再通知主節點將期間修改的操作記錄同步到複製節點進行重放就完成了同步過程。

185. Redis集羣原理是什麼?

Redis Sentinal着眼於高可用,在master宕機時會自動將slave提升爲master,繼續提供服務。
Redis Cluster着眼於擴展性,在單個redis內存不足時,使用Cluster進行分片存儲。

186. 使用Redis有哪些好處?

  • 速度快,因爲數據存在內存中,類似於HashMap,HashMap的優勢就是查找和操作的時間複雜度都是O(1)
  • 支持豐富數據類型,支持string,list,set,sorted set,hash
  • 支持事務,操作都是原子性,所謂的原子性就是對數據的更改要麼全部執行,要麼全部不執行
  • 豐富的特性:可用於緩存,消息,按key設置過期時間,過期後將會自動刪除

187. redis相比memcached有哪些優勢?

  • memcached所有的值均是簡單的字符串,redis作爲其替代者,支持更爲豐富的數據類型
  • redis的速度比memcached快很多
  • redis可以持久化其數據

188. redis常見性能問題和解決方案:

  • Master最好不要做任何持久化工作,如RDB內存快照和AOF日誌文件
  • 如果數據比較重要,某個Slave開啓AOF備份數據,策略設置爲每秒同步一次
  • 爲了主從複製的速度和連接的穩定性,Master和Slave最好在同一個局域網內
  • 儘量避免在壓力很大的主庫上增加從庫
  • 主從複製不要用圖狀結構,用單向鏈表結構更爲穩定,即:Master <- Slave1 <- Slave2 <- Slave3… 這樣的結構方便解決單點故障問題,實現Slave對Master的替換。如果Master掛了,可以立刻啓用Slave1做Master,其他不變。

189. MySQL裏有2000w數據,redis中只存20w的數據,如何保證redis中的數據都是熱點數據

相關知識:redis 內存數據集大小上升到一定大小的時候,就會施行數據淘汰策略。redis 提供 6種數據淘汰策略:
voltile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰
volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰
allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
no-enviction(驅逐):禁止驅逐數據

190. Memcache與Redis的區別都有哪些?

  • 存儲方式
    • Memecache把數據全部存在內存之中,斷電後會掛掉,數據不能超過內存大小。
    • Redis有部份存在硬盤上,這樣能保證數據的持久性。
  • 數據支持類型
    • Memcache對數據類型支持相對簡單。
    • Redis有複雜的數據類型。
  • 使用底層模型不同
    • 它們之間底層實現方式 以及與客戶端之間通信的應用協議不一樣。
    • Redis直接自己構建了VM 機制 ,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
  • value大小:redis最大可以達到1GB,而memcache只有1MB

191. Redis 常見的性能問題都有哪些?如何解決?

  • Master寫內存快照,save命令調度rdbSave函數,會阻塞主線程的工作,當快照比較大時對性能影響是非常大的,會間斷性暫停服務,所以Master最好不要寫內存快照。
  • Master AOF持久化,如果不重寫AOF文件,這個持久化方式對性能的影響是最小的,但是AOF文件會不斷增大,AOF文件過大會影響Master重啓的恢復速度。Master最好不要做任何持久化工作,包括內存快照和AOF日誌文件,特別是不要啓用內存快照做持久化,如果數據比較關鍵,某個Slave開啓AOF備份數據,策略爲每秒同步一次。
  • Master調用BGREWRITEAOF重寫AOF文件,AOF在重寫的時候會佔大量的CPU和內存資源,導致服務load過高,出現短暫服務暫停現象。
  • Redis主從複製的性能問題,爲了主從複製的速度和連接的穩定性,Slave和Master最好在同一個局域網內。

192. redis最適合的場景

  • 會話緩存(Session Cache)
    最常用的一種使用Redis的情景是會話緩存(session cache)。用Redis緩存會話比其他存儲(如Memcached)的優勢在於:Redis提供持久化。當維護一個不是嚴格要求一致性的緩存時,如果用戶的購物車信息全部丟失,大部分人都會不高興的,現在,他們還會這樣嗎?
    幸運的是,隨着 Redis 這些年的改進,很容易找到怎麼恰當的使用Redis來緩存會話的文檔。甚至廣爲人知的商業平臺Magento也提供Redis的插件。
  • 全頁緩存(FPC)
    除基本的會話token之外,Redis還提供很簡便的FPC平臺。回到一致性問題,即使重啓了Redis實例,因爲有磁盤的持久化,用戶也不會看到頁面加載速度的下降,這是一個極大改進,類似PHP本地FPC。
    再次以Magento爲例,Magento提供一個插件來使用Redis作爲全頁緩存後端。
    此外,對WordPress的用戶來說,Pantheon有一個非常好的插件 wp-redis,這個插件能幫助你以最快速度加載你曾瀏覽過的頁面。
  • 隊列
    Reids在內存存儲引擎領域的一大優點是提供 list 和 set 操作,這使得Redis能作爲一個很好的消息隊列平臺來使用。Redis作爲隊列使用的操作,就類似於本地程序語言(如Python)對 list 的 push/pop 操作。
    如果你快速的在Google中搜索“Redis queues”,你馬上就能找到大量的開源項目,這些項目的目的就是利用Redis創建非常好的後端工具,以滿足各種隊列需求。例如,Celery有一個後臺就是使用Redis作爲broker,你可以從這裏去查看。
  • 排行榜/計數器
    Redis在內存中對數字進行遞增或遞減的操作實現的非常好。集合(Set)和有序集合(Sorted Set)也使得我們在執行這些操作的時候變的非常簡單,Redis只是正好提供了這兩種數據結構。所以,我們要從排序集合中獲取到排名最靠前的10個用戶–我們稱之爲“user_scores”,我們只需要像下面一樣執行即可:
    當然,這是假定你是根據你用戶的分數做遞增的排序。如果你想返回用戶及用戶的分數,你需要這樣執行:
    ZRANGE user_scores 0 10 WITHSCORES
    Agora Games就是一個很好的例子,用Ruby實現的,它的排行榜就是使用Redis來存儲數據的,你可以在這裏看到。
  • 發佈/訂閱
    最後(但肯定不是最不重要的)是Redis的發佈/訂閱功能。發佈/訂閱的使用場景確實非常多。我已看見人們在社交網絡連接中使用,還可作爲基於發佈/訂閱的腳本觸發器,甚至用Redis的發佈/訂閱功能來建立聊天系統!(不,這是真的,你可以去核實)。
    Redis提供的所有特性中,我感覺這個是喜歡的人最少的一個,雖然它爲用戶提供如果此多功能。
    Redis最適合所有數據in-momory的場景,雖然Redis也提供持久化功能,但實際更多的是一個disk-backed的功能,跟傳統意義上的持久化有比較大的差別,那麼可能大家就會有疑問,似乎Redis更像一個加強版的Memcached,那麼何時使用Memcached,何時使用Redis呢?
    如果簡單地比較Redis與Memcached的區別,大多數都會得到以下觀點:
    • Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
    • Redis支持數據的備份,即master-slave模式的數據備份。
    • Redis支持數據的持久化,可以將內存中的數據保持在磁盤中,重啓的時候可以再次加載進行使用。

193. Redis集羣方案應該怎麼做?都有哪些方案?

  • codis。
    目前用的最多的集羣方案,基本和twemproxy一致的效果,但它支持在 節點數量改變情況下,舊節點數據可恢復到新hash節點。
  • redis cluster3.0自帶的集羣,特點在於他的分佈式算法不是一致性hash,而是hash槽的概念,以及自身支持節點設置從節點。具體看官方文檔介紹。
  • 在業務代碼層實現,起幾個毫無關聯的redis實例,在代碼層,對key 進行hash計算,然後去對應的redis實例操作數據。 這種方式對hash層代碼要求比較高,考慮部分包括,節點失效後的替代算法方案,數據震盪後的自動腳本恢復,實例的監控,等等。

194. Redis集羣方案什麼情況下會導致整個集羣不可用?

有A,B,C三個節點的集羣,在沒有複製模型的情況下,如果節點B失敗了,那麼整個集羣就會以爲缺少5501-11000這個範圍的槽而不可用。

195. redis快速的原因

  • 完全基於內存,大部分請求都是純粹的內存操作,非常快速,數據存儲在內存中,例如HashMap,優勢是查找和操作的時間複雜度 都是O(1);
  • 數據結構簡單,對數據操作也簡單,Redis中的數據結構是專門進行設計的;
  • 採用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或多線程導致的切換而消耗cpu,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因爲可能出現死鎖而導致的性能消耗;
  • 使用異步非阻塞IO;(重點說)(同步/異步:是否主動讀寫數據;阻塞/非阻塞:是否需要等待.)
  • 底層自己構建了VM機制,因爲一般系統調用系統函數的話會浪費一定的時間去移動和請求。

196. 工作中Redis的持久化方案,你們是怎麼做的

持久化方案用的是RDB;RDB 是 Redis 默認的持久化方案。
在指定的時間間隔內,執行指定次數的寫操作,則會將內存中的數據寫入到磁盤中。即在指定目錄下生成一個dump.rdb文件。Redis 重啓會通過加載dump.rdb文件恢復數據。

197. 爲啥用redis做緩存,而不用HashMap做緩存

  • redis 數據可持久化保存,有些緩存你想重啓程序後還能繼續使用,而map實現不了
  • redis 可以實現分佈式部署,只要涉及到多臺多進程啥的,map就實現不了
  • redis 有很多數據結構,方便操作,比如 hash set list sort-set等,在某些場景下操作起來比map方便

198. Redis是nosql數據庫,是否適合存儲大數據

Redis 是 nosql 數據庫,但是 redis 是 key-value 形式的 nosql 數據庫,數據是存儲到內存中的,適合於快速存取,一般作爲緩存使用。
並且 redis 是單線程的如果某個操作進行大數據的存儲的話其他的進程都處於等待狀態,這樣就降低了性能。
所以在 redis 中不適合於大數據的存儲。
如果是類似商品評論這樣的價值不高的大批量數據,我們的做法是採用 mongodb。

199. 穿透_雪崩_Redis緩存穿透和redis雪崩處理

  • 緩存穿透
    一般的緩存系統,都是按照key去緩存查詢,如果不存在對應的value,應該去後端系統查詢(比如數據庫)。如果key對應的value不存在,並且對key併發請求量很大,就會對後端系統造成很大的壓力。這就叫做緩存穿透。
  • 緩存雪崩
    當緩存服務器重啓或者大量緩存集中在某一個時間段失效,這樣在失效的時候,也會給後端系統(比如數據庫)帶來很大的壓力。
    緩存雪崩是指在我們設置緩存是採用了相同的過期時間,導致緩存在某一時期同時失效,請求全部轉發到DB,DB瞬間壓力過大雪崩。
    解決方案:
    • 把緩存時間分散開,比如在原來的時間基礎上增加一個隨機值,比如1~5分鐘隨機,這樣每一個緩存的過期時間的重複率就會降低,就很難引發集體失效的事件。

200. 集羣_redis怎麼做集羣

爲了保證可以進行投票,需要至少3個主節點。每個主節點都需要至少一個從節點,所以需要至少3個從節點,一共需要6臺redis服務器可以使用6個redis實例6個redis實例的端口號,7001~7006,因爲集羣中每個redis除了端口號,其他配置其實一樣,所以我們可以先配置好一個集羣的redis,然後賦值,修改端口號即可。6臺準備完畢之後,需要開啓集羣策略,然後再這基礎上創建集羣環境。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章