分佈式架構
- 分佈式事務理論 分佈式系統一致性(ACID、CAP、BASE、二段提交、三段提交、TCC、冪等性)原理詳解
- 事務要求:具備ACID的特性,即原子性、一致性、隔離性、持久性
- 分佈式事務處理模型:DTS,模型中包含4個角色:應用程序、事務管理器、資源管理器、通信資源管理器四部分;關係簡稱解釋:
- TX協議定義應用程序與事務管理器之間的接口
- XA協議定義了事務管理器與資源處理器之間的接口
- CAP定理,分區容錯性必須實現,所以取捨再一致性與可用性
- 分區容錯性p、一致性c、可用性a
- BASE理論,平衡cap定理的理論
- 強一致性、弱一致性、最終一致性
- 強一致性,多用於金融、財務、訂單核心業務等
- 建議:分佈式或多或少無法做到強一致性的,比如串形執行的強事務處理也可能造成因通訊造成極端情況下數據不統一,所以需要的話就需要將強關聯的業務代碼寫到一起
- 實現:
- 二階段 2PC(強一致,高併發不推薦,mysql5.5+支持)
- 一階段:準備(寫日誌、鎖資源、準備提交)
- 二階段:都準備好後統一提交,釋放資源
- 缺點:
- 同步阻塞問題,需要鎖定從開始到結尾的所有同步執行的資源
- 如果例如單點故障、通訊失敗等造成事務執行不一致後出現的異常需要人工干預
- 三階段
- 一、二階段之間增加一個詢問過程階段,引入超時機制。防止因爲超時、宕機、故障等原因沒有收到執行者\協調者的消息一致阻塞下去
- 只能減少問題,如果真正執行的時候發生問題就同2pc的第二階段一樣了
- TCC(阿里提出,其實不是階段提交,是根據通訊與業務邏輯處理的)
- TCC分佈式事務詳解
- tcc-transaction框架,中文並且支持rpc協議(dubbo);其他還有ByteTCC、Himly等開源框架,一般通過註解@Confirm、@Cancel等自動感知成功、失敗進而自動執行
- 過程描述:
- Try:完成所有業務檢查(一致性)、預留必須業務資源(隔離性)
- eg:下訂單時訂單、進銷、積分……系統,可以通過數據庫增加凍結字段,先暫時保存並只鎖定該資源
- Confirm:真正執行業務、不做任務業務檢查、滿足冪等性
- Cancel:取消業務、釋放 Try 階段預留的業務資源、滿足冪等性
- Try:完成所有業務檢查(一致性)、預留必須業務資源(隔離性)
- 減少了阻塞問題,不過在執行2個C的時候也可能造成事務執行不一致的問題
- 注意冪等(攜帶唯一表示進行業務處理即可)
- 可補償(根據mq或者定時任務等對記錄錯誤的數據進行事務補償、人工補償)
- 二階段 2PC(強一致,高併發不推薦,mysql5.5+支持)
- 最終一致性
- 可靠消息模式(最常用)
- 消息持久化,2種方案:
- 各自系統自己的消息表(造成耦合)
- 統一的外部消息表(多一步預發送消息提交到消息管理模塊)
- 中間件(MQ)
- 冪等性
- 重試機制造成
- 使用唯一鍵進行濾重
- 使用分佈式表
- 使用狀態流轉的方向性
- 新增、刪除、獲取一個數據就是冪等性的
- mq見kafka詳情
- 冪等性
- 消息持久化,2種方案:
- 緩存一致模式(通過緩存,可以整合入消息模式)
- 性能要求不是極端:分佈式緩存
- 緩存要一次性種植完整,部分存不如不存
- 保持弱一致性
- 通過業務處理,根據各個應用場景進行選擇,需要人工開發
- 查詢模式
- 任何一個服務操作都需要提供一個查詢接口,用來向外部輸出操作執行的狀態
- 補償模式(查詢模式後發現數據不一致後執行,類似於TCC)
- 自動修復(重試、回滾)
- 通知運營、通知技術
- 異步確保模式
- 場景:將響應時間要求不高的業務從主幹剝離,這個方案最大的好處能夠對高併發流量進行消峯,例如:電商系統中的物流、配送,以及支付系統中的計費、入賬等
- 如果遲遲沒有收到響應,我們通過查詢模式和補償模式來繼續未完成的操作
- 定期覈對模式(金融:數據準確;社交:量大)
- 需要唯一ID(分佈式系統需要生成策略)
- 需要記錄調用鏈
- 專題模式
- 特殊情況,eg:版本升級、數據遷移等
- 查詢模式
- 可靠消息模式(最常用)
- 高併發
- 名詞解釋
- 峯值每秒請求數(QPS):
- 解釋:每秒鐘請求或者查詢的數量,在互聯網領域,指每秒響應請求數(指HTTP請求)
- 公式:峯值每秒請求數(QPS) = (總PV數 * 80%) / (6小時秒數 * 20%);80%的訪問量集中在20%的時間
- QPS達到50,可以稱之爲小型網站,一般的服務器就可以應付
- QPS達到100,假設關係型數據庫的每次請求在10ms完成,假設單頁面只有一個SQL查詢,那麼100QPS意味着1s完成100次請求,但是此時並不能保證數據庫查詢能完成100次
- 優化方案:數據庫緩存層,數據庫的負載均衡
- QPS達到800,假設使用百兆帶寬,意味着網站出口的實際帶寬是8M左右,假設每個頁面只有10k,在這個併發條件下,百兆帶寬已經喫完
- 優化方案:CDN加速,負載均衡
- QPS達到1000,假設使用memcache緩存數據庫查詢數據,每個頁面對memcache的請求遠大於直接對db的請求,memcache的悲觀併發數在2w左右,但有可能在之前內網帶寬已經喫光,表現出不穩定,
- 解決方案:nosql、靜態HTML緩存
- QPS達到2000,這個級別下,文件系統訪問鎖都成爲了災難
- 優化方案:做業務分離,分佈式存儲
- 併發連接數:系統同時處理的請求數量
- 吞吐量:單位時間內處理的請求數量(通常由QPS與併發數決定)
- PV:綜合瀏覽量(page view),即頁面瀏覽量或者點擊量,一個訪客在24小時內訪問的頁面數量;同一個人瀏覽網站同一頁面,只記作一次PV
- UV:獨立訪客(unique visitor),即一定時間範圍內相同訪客多次訪問網站,只計算爲一個獨立訪客
- 日網站帶寬 = PV / 統計時間(換算到s) * 平均頁面大小(單位KB) * 8;峯值一般是平均值的倍數,根據實際情況來定
- 峯值每秒請求數(QPS):
- 優化方案
- 緩存
- 降級:目的是保證核心服務可用,即使是有損的
- eg:頁面非核心服務不展示button
- eg:查詢必須攜帶索引列
- eg:使用通用內容替代個性化推薦內容
- eg:降低容災能力,降低性能,延遲持久化等等
- 限流
- 算法
- 令牌桶:令牌勻速入桶,url請求獲取令牌後server進行處理,允許突發增量
- 漏桶:令牌勻速入桶,勻速出筒,不允許突發
- 應用級限流
- Tomcat的Connector其中一種配置有如下幾個參數
- acceptCount:如果Tomcat的線程都忙於響應,新來的連接會進入隊列排隊,如果超出排隊大小,則拒絕連接;
- maxConnections:瞬時最大連接數,超出的會排隊等待;
- maxThreads:Tomcat能啓動用來處理請求的最大線程數,如果請求處理量一直遠遠大於最大線程數則可能會僵死。
- 線程池
- Tomcat的Connector其中一種配置有如下幾個參數
- 單機限流:緩存,使用算法(Guava RateLimiter提供了令牌桶算法實現:平滑突發限流(SmoothBursty)和平滑預熱限流(SmoothWarmingUp)實現)
- 分佈式限流:redis/nginx + lua腳本
- 算法
- 基礎優化方案-場景
- 流量優化:防盜鏈處理(防止流量被外戰使用)
- 前端優化:減少HTTP請求,合併css或js,添加異步請求,啓用瀏覽器緩存和文件壓縮
- 服務端優化:頁面靜態化
- 數據庫優化:引入緩存數據庫,進行數據\數據庫緩存
- web服務器優化:負載均衡,nginx反向代理
- 進階優化方案-場景
- 前端優化:CDN加速,獨立的靜態資源服務器
- 服務端優化:併發處理(多線程),隊列處理(異步)
- 數據庫優化:讀寫分離,分庫分表,分區操作,負載均衡
- 多數據源,其實就是多個配置,使用@aop或者自定義註解進行攔截處理
- web服務器優化:7,4層LVS軟件
- 4層是通過ip+端口及tcp/udp進行負載均衡
- 7層是通過url,http,cookies等應用層進行負載均衡
- 名詞解釋
框架
- Springboot
-
AOP
- @Aspect 切面註釋
- @Pointcut(“execution(* cn.zp.…controller..*(…))”) 切入點
- @Around、before、after等等 執行
- 以下是一個不常用的案例,將不常用的一場進行切面,@AfterThrowing註解的使用
/**
-
凡是註解了RequestMapping的方法都被攔截
*/
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
private void webPointcut() {
}/**
-
攔截web層異常,記錄異常日誌,並返回友好信息到前端 方法只攔截Exception
-
將未做處理的異常統一進行處理
*/
@AfterThrowing(pointcut = “webPointcut()”, throwing = “e”)
public void handleThrowing(Exception e) {
logger.error(JSON.toJSONString(e.getStackTrace()));
//通過response和writer將信息輸出到瀏覽器
} -
IOC、DI
- 各種註解Configuation、Bean、Service、Controller、Repository、Component
-
- Mybatis
- 半ORM(對象關係映射)框架
- 一對多、多對一、多對多
- 使用RowBounds對象進行分頁
- tk.mybatis 通用Mapper插件
- Shiro 與 Spring Security
- 對比
- shiro四大核心功能
- 身份認證,支持多數據源(api簡單)
- 訪問控制(api簡單),支持粒度(粗:角色;細:權限)的授權
- 會話管理(session),會話驗證(驗證器、定時任務等驗證是否過期)
- 加密(api簡單)
- shiro其他功能
- 支持一級緩存
- 多線程支持,即如在一個線程中開啓另一個線程,能把權限自動傳播過去
- 測試支持
- “記住我”功能支持
- 授權支持,允許一個用戶假裝爲另一個用戶(如果他們允許)的身份進行訪問
- 不與任何的框架或者容器捆綁,可以獨立運行
- shiro核心組件
- Subject 主體,即登錄用戶
- SecurityManager:安全管理器;即過濾器Filter
- Realm:域,Shiro從從Realm獲取安全數據(如用戶、角色、權限)
- SpringSecurity
- 比shiro難,如果不使用spring則不考慮
- shiro的功能它都有,並且支持Oauth、OpenID
- shiro四大核心功能
- 一般數據庫結構(經典5張表)
- 用戶表、角色表、權限表(資源表)、用戶-角色表、角色-權限表
- Shiro的實現過程 springboot整合redis
- 自定義Realm(安全域)繼承AuthorizingRealm,實現獲取授權信息方法(數據庫)、獲取身份驗證信息(url攔截後身份信息驗證)2個方法
- @Configuration配置,將自己的Realm驗證加入容器,將容器加入權限管理,增加攔截器工廠,增加啓用註解等配置
- controller內使用,通過註解:@RequiresRoles(“admin”)角色、@RequiresPermissions(“add”)權限等
- 對比
- Netty
-
特點
- 一個高性能、異步事件驅動的NIO框架,它提供了對TCP、UDP和文件傳輸的支持
- 使用更高效的socket底層避免一些問題,簡化了NIO的處理方式
- 對TCP粘包/分包進行自動化處理
- 可使用接受/處理線程池,提高連接效率,對重連、心跳檢測的簡單支持
- 大量使用了volitale、使用了CAS和原子類、線程安全類的使用、讀寫鎖的使用
-
序列化
- xml - 數據全,全平臺支持
- json - 移動、web端
- thrift - 完全rpc支持
- Protobuf - 跨防火牆,多語言支持
-
IO 一對一(一個線程對應一個連接)
-
NIO 一對多(一個線程對應多個連接),非阻塞IO
- Channel:表示 IO 源與目標打開的連接,是雙向的,但不能直接訪問數據,只能與Buffer 進行交互。
- Buffer:與Channel進行交互,數據是從Channel讀入緩衝區,從緩衝區寫入Channel中的
- Selector可使一個單獨的線程管理多個Channel
- Pipe:兩個線程之間的單向數據連接,數據會被寫到sink通道,從source通道讀取
-
使用
- 服務器端
public class NettyServer { public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); NioEventLoopGroup boos = new NioEventLoopGroup(); NioEventLoopGroup worker = new NioEventLoopGroup(); serverBootstrap .group(boos, worker) // 創建分組 .channel(NioServerSocketChannel.class) // 創建頻道 .childHandler(new ChannelInitializer<NioSocketChannel>() { @Override protected void initChannel(NioSocketChannel ch) { ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) { System.out.println(msg); } }); } }) .bind(8000); // 監聽8000端口 } }
- 客戶端
public class NettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap .group(group) //組信息 .channel(NioSocketChannel.class) .handler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) { ch.pipeline().addLast(new StringEncoder()); } }); //監聽url和端口 Channel channel = bootstrap.connect("127.0.0.1", 8000).channel(); while (true) { channel.writeAndFlush(new Date() + ": hello world!"); Thread.sleep(2000); } }
``` -
中間件
-
Nginx
- 特點
- 佔用內存小、宕機概率低
- 負載均衡
- 非阻塞高併發(官方:5w併發,2-3w沒壓力)
- 異步非阻塞事件處理機制:運用了epoll模型,提供了一個隊列,排隊解決
- 不使用多線程:切換線程佔用cpu
- 正向代理:異步非阻塞接受請求後統一發送到服務器(降低服務器壓力),代理客戶端
- 反向代理:代理服務端
- 動、靜分離
- 特點
-
MQ(Kafka) kafka常見問題
- 分佈式發佈-訂閱消息系統
- 削峯填谷、緩衝
- 解藕、擴展
- 名詞解釋
- Producer :消息生產者,就是向kafka broker(服務器)發消息的客戶端
- Consumer、Consumer Group(CG) :消息消費者,向kafka broker取消息的客戶端
- Topic :主題,消息以topic爲類別記錄,內部包含多個partition(隊列)
- Broker :一臺kafka服務器就是一個broker。一個集羣由多個broker組成。一個broker可以容納多個topic;一個非常大的topic可以分佈到多個broker上。
- Partition:一個topic可以分爲多個partition,每個partition是一個有序的隊列。partition中的每條消息都會被分配一個有序的id(offset)。kafka只保證按一個partition中的順序將消息發給consumer,不保證一個topic的整體(多個partition間)的順序
- Offset:消息id,kafka的存儲文件都是按照offset.kafka來命名,eg:the first offset就是00000000000.kafka
- 主從複製(leader follower)
- topic的分區擁有若干副本,這個數量是可以配置的,並且是各個節點均勻分佈的
- zk保持連接,如果是follower並且同步延時符合配置要求,則說明是同步節點
- 只有當所有同步節點狀態都是committed時,消息纔會被髮送到consumer
- leader選舉:
- broker選舉:誰先創建了zk內的controller節點,誰就是
- ISR,同步狀態的副本的集合(a set of in-sync replicas),在這個集合中的節點都是和leader保持高度一致的,所以任何follower都可以被選爲leader,相當於隨機
- 冪等性
- 原因
- 先commit,再執行業務邏輯:提交成功,處理失敗 。造成丟失
- 先執行業務邏輯,再commit:提交失敗,執行成功。造成重複執行
- 先執行業務邏輯,再commit:提交成功,異步執行fail。造成丟失
- Producer重複提交問題
- 單會話
- Kafka增加了pid和seq
- 1、Producer中每個RecordBatch都有一個單調遞增的seq; Broker上每個Topic也會維護pid-seq的映射,並且每Commit都會更新lastSeq。
- 2、當RecordBatch到來時,broker會先檢查:如果baseSeq(新消息第一條) > lastSeq(維護的最後一條消息)則保存數據
- 有序性處理:
- 1、設置enable.idempotence=true後能夠動態調整max-in-flight-request。正常情況下max.in.flight.requests.per.connection大於1。
- 2、當重試請求到來且時,batch 會根據 seq重新添加到隊列的合適位置,並把max.in.flight.requests.per.connection設爲1,這樣它 前面的 batch序號都比它小,只有前面的都發完了,它才能發
- Kafka增加了pid和seq
- 多會話
- 原因:當應用重啓時,新的producer並沒有old producer的狀態數據。可能重複保存。
- 方案:通過事務隔離機制來實現,所以事務引入了transactionId和Epoch
- 原理:同單會話
- 單會話
- Consumer端會話
- 通過msgId自己進行操作
- 原因
- 命令
- 配置文件:監聽地址、序列化方法、group-id(消費組)
- 方法:
-
producer生產:
@Autowired private KafkaTemplate<String, String> kafkaTemplate; @RequestMapping("/send") public String send(String msg) { kafkaTemplate.send("group-id", msg); return "success"; }
-
consumer消費
- 單消費組:
// 如果是單消費組,這裏的group-id就是topicName @KafkaListener(topics = "group-id") public void listen(ConsumerRecord<?, ?> record) throws Exception { System.out.printf("topic = %s, offset = %d, value = %s \n" , record.topic(), record.offset(), record.value()); }
- 多消費組配置:@KafkaListener(topics = {"${自定義}"},groupId = “xxx”)
-
- 分佈式發佈-訂閱消息系統
-
Zookeeper 常見功能
- 分佈式的協調組件,功能:
- 發佈/訂閱
- 負載均衡
- 命名服務
- 分佈式協調/通知
- 集羣管理
- Master選舉
- 分佈式鎖和分佈式隊列等
- 崩潰恢復模式(正常時爲消息廣播模式)
- 當剛剛啓動、Leader服務器宕機、重啓、網絡故障等導致過半服務器與Leader服務器沒有保持正常通信時,所有進程(服務器)進入崩潰恢復模式
- 首先選舉產生新的Leader服務器,然後集羣中Follower服務器開始與新的Leader服務器進行數據同步,當集羣中超過半數機器與該Leader服務器完成數據同步之後,退出恢復模式
- Leader選舉,過半策略
-
=3臺服務器,投票選舉
-
- 數據同步,過半策略
- 直接差異化同步(DIFF同步)
- 先回滾再差異化同步(TRUNC+DIFF同步)
- 僅回滾同步(TRUNC同步)
- 全量同步(SNAP同步)
- 事務
- 順序一致
- 採用了全局遞增的版本Id(ZXID)來標識,zxid記錄ZooKeeper狀態的改變
- zxid實際上是一個64位的數字,高32位用來標識leader週期,如果有新的leader產生出來會自增,低32位用來遞增計數
- 當新產生(事務)提議的時候,會依據數據庫的兩階段過程,首先會向其他的server發出事務執行請求,如果超過半數的機器都能執行並且能夠成功,那麼就會開始執行
- 分佈式事務、分佈式隊列
- 臨時節點:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個唯一的瞬時有序節點;eg:new ZooKeeper(**).create(**)
- 獲取鎖:判斷有序節點中序號最小的一個
- 釋放鎖:將瞬時節點刪除即可
- 過程:創建臨時節點 - 隊列中序號最小的獲取鎖 - 執行 - 關閉鎖 - 重複
- 順序一致
- 擴容
- 水平擴容,全部重啓或者順序重啓(不是很好),3.5+會支持動態擴容
- 分佈式的協調組件,功能:
數據庫、Nosql
-
Mysql
- 使用多版本控制協議實現強一致性
- 優化
- 索引
- explain 命令獲取語句執行計劃
- explain extended 會在 explain 的基礎上額外提供一些查詢優化的信息;show warnings 可以 得到優化後的查詢語句,從而看出優化器優化了什麼
- explain partitions 會顯示將查詢的分區(如果分區的話)
- explain 命令獲取語句執行計劃
- 熱備、主從、分庫分表
- 配置
- 索引
-
Nosql(Redis、MongoDB等)
- Nosql完全不適合交易場景,Nosql主要用來做數據分析、ETL(數據抽取、轉換以及加載)、報表、數據挖掘、推薦、日誌處理等其他非交易場景
- 對比
- HBase 實現的語言爲Java,依託於 Hadoop 的 HDFS(分佈式文件系統)作爲最基本存儲基礎單元。
- java編寫,需要java環境
- 存儲量大、分割簡單,但佔用內存大
- api不靈活
- 適用於大數據環境
- redis 實現語言爲c:
- 存儲數據結構靈活
- 事務保證業務原子性
- 執行速度快
- 適合數據變化快並且容量可預見
- 集羣方案在3.0-版本效果不好
- 單線程、支持事務,所以在單個處理和事務處理均可保證原子性
- mongdb 實現語言爲c++:
- json格式
- 在服務器端可執行js腳本
- 非事務
- 單個文檔大小限制爲16M,32位系統上,不支持大於2.5G的數據
- 對內存要求比較大,至少要保證熱數據(索引,數據及系統其它開銷)都能裝進內存
- 適合集羣
- LevelDB
- Couchbase(memcache的升級版)
- HBase 實現的語言爲Java,依託於 Hadoop 的 HDFS(分佈式文件系統)作爲最基本存儲基礎單元。
- 數據備份
- redis:主從配置
- 分佈式
- 非動態
- 餘數算法:通過數據的key進行hash計算,根據數據庫數量取餘將數據存儲到各個數據庫上
- 動態增加
- hash槽
- 一共16384個槽,各個服務器分管一部分
- 新增機器,將數據通過key進行遷移
- jedis會協調數據的獲取
- hash槽
- 非動態
- 分佈式鎖
- redis鎖:setnx,不過這個不是分佈式的,是單庫的鎖;如果需要分佈式則建議使用zk的臨時節點
- Redisson(java框架)實現了redis作者出的RedLock算法
- 分佈式部署
- 修改配置文件
-
Elasticsearch與Hbase的分析
- 有es爲什麼還需要hadoop
- 趨勢:相互之間會越來越模糊,現階段側重點不同,hadoop是一個生態,es只是能替換其中的一些功能
- Elasticsearch
- 優勢:
- ElasticSearch擅長建立索引和搜索索引
- 基於索引查詢的快速文本、結構化、統計化查詢,以及聚合類數據分析
- 基於json進行查詢,開發效率簡單且高
- 劣勢:
- 只能查詢索引列,無法搜索和合並未索引的內容;
- 無法運行創建新數據集的複雜分析,所以並不適合做數據分析類操作
- 經上述國外論壇內的討論,當文檔查詢結果破萬後效率會下降
- 複雜關聯查詢會降低速度
- 優勢:
- Hbase(Hadoop)
- 優勢
- 量大、批處理,複雜計算
- 如果需要專門的數據分析,需要建立團隊並使用hadoop
- 劣勢
- 較es開發複雜,需要人工較多,投入大
- 優勢
-
Elasticsearch
-
特點
- 是一個分佈式,高性能、高可用、可伸縮的文本搜索和分析系統
- Lucene是單機的模式,es解決了分佈式問題
-
場景
- 全文檢索、結構化檢索(同義詞處理,相關度排名)
- 複雜數據分析
- 近實時數據
-
日誌
- logstash
-
持久化
- 路由分片查找文檔位置
-
優化
- 查詢的時候,操作系統會將磁盤文件裏的數據自動緩存到 filesystem cache裏面去,所以cache建議是全部索引數據內容的一半大小
- 所以一定要符合業務,只將需要搜索的字段進行索引,減少索引也就減少了內存佔用提高了查詢效率
- 數據預熱、冷熱分離;可以建立一個系統定時對流量較大的索引進行提前刷入內存進行預熱
- 複雜數據提前計算,es的關聯對象一定要簡單或者是已經處理過的數據再插入es
- 分頁性能優化:分頁也還是要獲取之前的數據,所以無論是一次性多取,還是和微博、淘寶一樣的下拉等,都無法滿足用戶自定義頁碼跳轉,建議還是一頁頁前進;
-
基礎概念
- 索引(database):含有相同屬性的文檔集合
- 分片:每個索引都有多個分片,每個分片是一個lucene索引,減少索引壓力
- 備份:拷貝一份分片就完成了分片的備份,用處:分攤搜索壓力、容災
- 啓動後自動創建5個分片,1個備份;創建索引的時候指定分片,備份可以後期處理
- 類型(table):文檔必須屬於一個類型,索引可以定義1+個類型
- 文檔(rows):文檔是可以被索引的基本數據單位
- 索引(database):含有相同屬性的文檔集合
-
API基本格式:http://<ip>:<port>/<索引>/<類型>/<文檔id>
- json格式
- 可以創建索引,指定分片和備份,並指定索引結構(put方式)
put請求:http://\<ip\>:\<port\>/<索引> { "settings":{ "number_of_shards": 3, // 分片 "number_of_replicas": 1 // 備份 }, "mappings":{ // 索引結構 "man":{ // 類型 "properties":{ // 文檔 "name":{ "type":"text" }, "country":{ "type": "keyword" },
- 插入,根據結構使用json傳遞即可
-
-
Hbase(Hadoop database)
- 介紹
- 是一個高可靠性、高性能、面向列、可伸縮的、建立在hdfs上的分佈式存儲系統
- 是Google Bigtable的開源實現
- 只支持單行事務,可通過hive執行復雜join語句
- 所以一般是配合Hadoop、ZooKeeper、MapReduce進行搭建
- 特點
- 主要用來存儲非結構化、半鬆散化數據
- KV基礎存儲
- 基於列的模式(其他關係型是基於行)
- 存儲大數據,可以支持千萬的QPS、PB級別的存儲
- null和空不佔用存儲空間,表可以設計的非常鬆散
- 動態列
- 強同步
- 使用場景
- 對象存儲:1b~100m海量存儲(新聞、視頻、音頻、論壇)
- 時序數據:高併發、海量數據(k線圖、監控數據、傳感器)
- 推薦畫像:用戶特徵,非常鬆散
- 時空數據:高併發、海量數據(軌跡、氣候數據)
- CubeDB([kjuːb]):全稱是多維立方體,用來實現實時報表,底層數據存儲在hbase
- 消息/訂單:強同步、海量存儲(聊天、訂單等)
- Feeds([fiːd])流:feed是將用戶主動訂閱的若干消息源組合在一起形成內容聚合器,幫助用戶持續地獲取最新的訂閱源內容;訂閱源不再是某個內容,而是生產內容的人/團體。訂閱中通常夾雜非訂閱內容,比如熱門推薦,廣告(今日頭條、朋友圈、知乎)
- NewSQL:之上有Phoenix的插件,可以滿足二級索引、SQL的需求,對接傳統數據需要SQL非事務的需求
- 語法
- 介紹
RPC
- 什麼是RPC,RPC好處,常用的RPC框架
- Dubbo 分佈式服務框架,以及SOA治理方案 RPC協議底層原理
- 傳輸服務:netty(默認)、mina、grizzy
- 序列化:hessian2(默認)、json、fastjson、自定義報文
- 連接描述:單個長連接NIO;異步傳輸
- 使用場景:1.常規RPC調用 2.傳輸數據量小 3.提供者少於消費者
- 報文格式:
- 可視化:dobbo admin、各種客戶端
- 應用
- 配置zookeeper,啓動
- dubbo配置指定zk地址、密碼、掃描路徑、xml配置名、zk組名
- 服務端新建配置:provicer.xml,顯式的對外提供接口
- 客戶端信息配置:client.xml,同上
- SpringCloud 提供了搭建分佈式系統及微服務常用的工具以及方案,基於Spring Boot, 使得開發部署極其簡單
- Thrift 可擴展且跨語言的服務的開發
- Facebook Thrift是最新一代高性能、跨需要的RPC通信框架,支持多種語言
- rmi
- http
- hessian
前端
- javascript
- jquery
- vue
- 腳本引入
- 語法使用
大數據
- ElasticSearch見數據庫章節
- Hadoop
- 分佈式系統基礎架構,用戶可以在不瞭解分佈式底層細節的情況下,開發分佈式程序。充分利用集羣的威力進行高速運算和存儲
- HDFS
- 特點
- 存儲非常大的文件
- 採用流式的數據訪問方式
- 電腦要求不高
- 例外
- 高延時,低延時可以使用hbase
- 大量小文件
- 需要頻繁修改
- 概念
- Blocks:文件存儲分塊
- Namenode:存儲各個節點的元數據、以及文件系統樹等
- Datanode:存儲的數據,定期向nomenode彙報
- 使用
- 命令行操作(測試、臨時操作等,比以下的幾個方便很多)
- java可以直接當做數據庫進行訪問(太麻煩,要自己實現mapreduce)
- hive訪問(使用spark進一步封裝和提高了效率)
- spark訪問(新項目一般使用)
- 命令
- 特點
- YARN
- 資源管理和作業調度技術,負責將系統資源分配給在 Hadoop 集羣中運行的各種應用程序,並調度要在不同集羣節點上執行的任務
- 調度:在整個資源管理框架中,ResourceManager 爲 master,NodeManager 是 slave
- HBASE 見數據庫章節
- HIVE
- hive -> mapreduce -> hadoop -> hdfs
- hive利用hdfs存儲數據,利用mapreduce處理數據
- HiveOnSpark與SparkSQL
- SparkSQL
- 支持多數據源,包括JSON、JDBC、Parquet、MapReduce、文件等
- 組件DataFrame、RDD
- Spark主推
- HiveOnSpark
- 前期沒有很好的適配其他數據源,只支持MapReduce
- 現在使用spark較多,這個就很少用了
- SparkSQL
- 爲什麼要用hive
- spark沒有自己的數據倉庫,hive原生支持hdfs(這個不是關鍵,spark可以用其他的)
- spark沒有自己的meta(管理元數據)庫,需要用hive的
- 其實代碼裏面spark的項目是引用了hive的jar,所以沒有替代關係
- Spark(快速計算引擎)
- 特點與優勢
- 封裝了mapreduce
- 啓用了內存分佈數據集,速度更快,適合負載算法
- api更高級,可以專注開發,不用太關注集羣
- Spark 是一個通用引擎,可用它來完成各種各樣的運算,包括 SQL 查詢、文本處理、機器學習等
- 使用
- 離線
- 初始化
- SparkConf sparkConf = new SparkConf().setMaster(“local[2]”);// 起兩個線程
- sparkConf.setAppName(“Class”); // 當前類名稱
- JavaSparkContext javaSc = new JavaSparkContext(sparkConf);
- JavaRDD javaRDD = javaSc.textFile(textFilePath); // 文件讀取
- javaSc.stop();
- 其他
- JavaPairRDD javaPairRDD = javaSc.parallelizePairs(Tuple);
- JavaRDD javaRDD = javaSc.parallelize(List);
- …
- 各種類型轉換:rdd、map、tuple、list、bean
- RDD
- 語法:可以數據轉換、json導入解析、file導入導出、hive導入導出、mysql導入導出、cvs導入導出等
- JavaRDD javaRDD = javaSc.textFile(textFilePath)
- JavaRDD javaRDD = javaSc.parallelize(List)
- ……
- 操作:過濾、排序、扁平化、分組、抽樣等
- 語法:可以數據轉換、json導入解析、file導入導出、hive導入導出、mysql導入導出、cvs導入導出等
- Dataset(sparksql的封裝)
- 基本過程:
- SparkContext sc = new SparkContext(sparkConf);
- SparkSession sparkSession = new SparkSession(sc)
- Dataset row = sparkSession.read().json(“json text”)
- Dataset userRow = row.select(“id”);
- ……對row進行數據庫類似的操作
- 其他
- rdd、bean、list、json等轉JavaRDD
- 基本過程:
- 初始化
- 流式 Storm flume
- 離線
- 特點與優勢
TCP/IP
- TCP/IP 傳輸空空告知協議/因特網互聯協議,是一個協議簇的核心,所以如此命名,協議簇還包括FTP、SMTP、ARP、PPP、IEEE 802.x等
- 分層:
- 應用層:HTTP、SMTP、FTP
- 傳輸層:TCP、UDP
- 網絡層:IP、ARP(地址解析協議,mac尋址)
- 鏈路層:IEEE 802.x、PPP
- 物理層:網卡
- IP,是面向無連接、無狀態,是TCP/IP協議的基石
- ps:ttl,數據包可經過的最多路由器總數,經過一個路由ttl-1,爲0則丟棄數據報並通知主機防止報文繼續發送
- TCP,每個tcp包都封裝在ip包內
- 特點:面向連接,失敗/超時重傳,可靠
- 3次握手建立,目的:信息對等、防止超時、防止請求超時導致的髒連接
- 4次揮手斷開,多了一個fin信號,接收方處理完所有信息才能通知發送方可以斷開
- UDP,只是在ip數據包上增加端口等部分信息,是面向無連接的,是不可靠傳輸
- HTTPS
JAVA基礎
-
抽象、封裝、繼承、多態、組合
-
io
- 字節流:多處理視頻、音頻、圖片等
- 字符流:多處理帶有編碼格式的文本
- 裝飾器模式
-
泛型
- eg1:public static T max(List list)
- 分析:靜態的是標示範型方法
- eg2:public static <T extends Comparable> T max(List list)
- 分析:如果是排序方法,需要參數繼承自Comparable類的子類
- 其他:K - key,V - value,E - element,
- <? extends T>可以賦值T以及T子類的集合(null可以),元素會向上轉型爲T,取值會有範型限制
- <? super T>可以賦值T以及T父類的集合,元素會範型丟失,例如不記名投票,結束後無法查看投票記錄
-
- 彙總、總結、代碼、動圖
- 數據結構:棧、隊列、鏈表、樹、圖(散列、最短路徑、拓撲)
- 常用排序算法
- 穩定性解釋:若在排序之前,a[i]在a[j]前面;並且排序之後,a[i]仍然在a[j]前面
- 時間複雜度
- O(1),一次就找到,哈希算法就是典型的O(1)時間複雜度
- O(logn),2爲底,eg:當數據增大256倍時,耗時只增大8倍
- O(n),就代表數據量增大幾倍,耗時也增大幾倍
- O(nlogn),eg:當數據增大256倍時,耗時增大256*8=2048倍
- O(n²)/O(n^2),2爲底,數據量增大n倍時,耗時增大n的平方倍
- 空間複雜度:臨時佔用存儲空間大小的量度
- 推薦
- 1、基本算法使用插入排序
- 2、快速+穩定+佔空間:歸併排序
- 3、快速+不穩定+少空間:堆排序
- 4、23之間有個快速排序,簡單,不穩定,時間和空間均也介於23之間
- 5、純數字:基數排序
- 基本算法,時間換空間
- 插入排序,穩定,推薦
- O(n²),空間:O(1)
- 對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入
- 通過代碼分析大數據量比冒泡速度快
- 冒泡排序,穩定
- 時間:O(n²),空間:O(1)
- 從前往後依次的比較相鄰兩個數的大小;如果前者比後者大,則交換它們的位置
- 選擇排序,不穩定
- 時間:O(n²),空間:O(1)
- 在未排序序列中找到最小(大)元素,存放到排序序列的起始(末尾)位置
- 插入排序,穩定,推薦
- 希爾排序/縮小增量排序/Shell排序
- 不穩定,時間:O(n^(1.3—2)),空間:O(1)
- 插入排序的改進版
- 需要定好步長(間隔>1),所以需要對數據非常瞭解
- 歸併排序,穩定
- 時間:O(nlogn),空間:O(n)
- 空間換時間
- 使用分治法,遞歸一分爲二,在分組後的數據順序性較好的情況下使用
- 快速排序,不穩定
- 時間:O(nlogn),空間:O(nlogn)
- 選擇一個基準數,通過一趟排序將要排序的數據分割成獨立的兩部分;其中一部分的所有數據都比另外一部分的所有數據都要小
- 堆排序,不穩定
- 時間:O(nlogn),空間:O(1)
- 二叉樹
- 基數排序,必須是確定範圍的整數,穩定,快速
- 桶排序
- 算法思想:
- 分治算法(分組計算後再通過算法合併)
- 動態規劃算法(類似遞歸)
- 貪心算法(最多人滿足,eg:先滿足最容易滿足的人)
- 二分法(折半搜索)
- 搜索算法(eg:導航最近距離)
- 回溯算法(eg:乘階、ip劃分等)
- 領域算法:大數據算法、分佈式算法、加密算法、負載均衡算法、推薦算法等
-
多線程
- 鎖: 悲觀鎖:鎖表、鎖行;樂觀鎖:增加version字段
- 線程中斷
- 使用線程池ExecutorService的話,shutdownNow是立刻停止,shutdown是執行完現在沒執行完的再停止
- 線程間協作,join(在start後使用join,其他線程會等待)、yield(讓出cpu重新競爭)
- 線程池工廠
private static ExecutorService executorService; public static ExecutorService getExecutorService(String groupName) { synchronized (ExecutorFactory.class) { if (executorService == null) { executorService = new ThreadPoolExecutor(4, 8, Long.MAX_VALUE, TimeUnit.NANOSECONDS, new LinkedBlockingQueue<>(1024),
// Executors.defaultThreadFactory(), // 默認工廠
new UserThreadFactory(groupName), // 自定義工廠,可以console線程組和一些上下文參數
new ThreadPoolExecutor.CallerRunsPolicy());
}
}
return executorService;
}
// int corePoolSize, //常駐核心數,0:直接銷燬;需要合理分配,太大浪費資源,太小頻會繁銷燬創建
// int maximumPoolSize, //最大數, >=1 超過會進入緩存隊列
// long keepAliveTime, // 連接最大時間,這裏使用了最長時間
// TimeUnit unit, // 時間格式,一般使用秒
// BlockingQueue<Runnable> workQueue, // 等待中的任務隊列,超過則執行拋棄策略;隊列有三種策略,不過阿里雲推薦這樣,所以有其他需要上網再查
// 該隊列爲單向鏈表,使用鎖來控制入隊和出隊的原子性,是一個生產消費模型隊列
// ThreadFactory threadFactory, // 創建線程工程,線程池命名是通過給這個工廠增加組命名來實現的
// RejectedExecutionHandler handler // 拒絕策略,超過緩存隊列長度以後執行,阿里建議一般跳轉固定頁面並將數據記數據庫or日誌後期削峯填谷再處理
//拋棄策略
// ThreadPoolExecutor.AbortPolicy() 拋出java.util.concurrent.RejectedExecutionException異常
// ThreadPoolExecutor.CallerRunsPolicy() 重試添加當前的任務,他會自動重複調用execute()方法
// ThreadPoolExecutor.DiscardOldestPolicy() 拋棄舊的任務
// ThreadPoolExecutor.DiscardPolicy() 拋棄當前的任務
// 不過默認的拋棄策略和線程工廠功能簡單,一般不滿足使用,實現自己的更合適,實現見
```
* 使用
```
while(線程池數量){
Future<Integer> future = executorService.submit(() -> {
......
})
}
boolean isDone = false;
while (!isDone){
if(future.isDone()) {
// System.out.println(future.get());
isDone = true;
} else {
System.out.println(false);
Thread.sleep(50);
}
}
service.shutdown();
```
-
反射
- 因爲效率問題,使用場景不高,一般會在三方或者獲取其他項目私有屬性的時候使用;或者自己寫框架時使用
- class類:獲取類加載器、類名、創建類實例、包名、父類名、接口名、獲取註解、所有方法、返回值、類型(匿名、內部、接口實現方法)、構造方法等幾乎所有能用到的
- Field類:成員變量/類的屬性
- Method類:等
- Constructor類:構造方法
- 使用:Class<?> c = Class.forName(“package path”).method;(eg:newInstance())
-
動態代理,框架等底層都是通過該方法進行切面編程的:eg:HttpServlet的dopost方法調用
method: private void testInvocation2(){ PersonServer server = new PersonProxy().getPersonProxy(); server.login(); server.submit(); } // 代理類 public class PersonProxy { // 業務接口 private PersonServer server = new PersonServerImp(); public PersonServer getPersonProxy() { // 返回一個代理 return (PersonServer) Proxy.newProxyInstance( server.getClass().getClassLoader() , server.getClass().getInterfaces() , (proxy, method, args) -> { if (method.getName().equals("login")) { // 前置業務 System.out.println("login_begin"); // 主業務執行 Object object = method.invoke(server, args); // 後置業務 System.out.println("login_end"); // 返回執行結果 return object; } else if (method.getName().equals("submit")) { // 其他方法 return method.invoke(server, args); } return null; }); } } // (proxy, method, args) -> {}的原文 new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { } }
-
異常
- finally 即使發生oom也會執行
- finally執行順序:先保存return的值,再執行finally,最後將保存的值return,不再考慮finally改變後的值
- 綜上:finally是處理諸如清理資源、釋放連接、關閉管道流等,所以不要有賦值、return等操作
- ps:lock需要寫到try內,小心造成finally內的lock.unlock方法在加鎖失敗後仍舊執行造成報錯
-
測試
- 類註解
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = xxxApplication.class)
- 初始化,使用mockMvc,MockMvc實現對Http請求的模擬,可以方便對Controller進行測試,使得測試速度快、不依賴網絡環境,而且提供驗證的工具,使得請求的驗證統一而且很方便
private MockMvc mockMvc; @Autowired private WebApplicationContext webContext; @Before public void before() throws Exception { mockMvc = MockMvcBuilders.webAppContextSetup(webContext).build(); } @After public void after() throws Exception { }
- 方法
@Test public void testIndexFail() throws Exception { String responseString = mockMvc .perform(get("/api/***") .accept(MediaType.APPLICATION_JSON_UTF8) ) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); assertNotNull(responseString); JSONObject json = JSONObject.fromObject(responseString); assertEquals(json.getString("code").toString(), "1"); assertEquals(json.getString("msg").toString(), TrainConstants.ErrorMsg.PARAMS_ERROR); }
-
日誌
- 日誌門面:門面模式,只提供了接口規範,slf4j、commons-logging
- 日誌庫:具體實現門面,log4j -> 升級 -> logback、log-jdk
- 日誌適配器:因爲log4j日誌庫比slf4j日誌接口先出,所以沒有使用logback的項目需要增加slf4j-log4j12適配器
- 綜述:推薦slf4j + logback模式
JVM
- 類加載過程
- 1、bootstrap jvm啓動時創建,c/c++實現,加載核心類,eg:object、system、string
- 2、extension classloader平臺類加載器,家在擴展的系統類,eg:xml、壓縮、加密等
- 3、application classloader應用類加載器,用戶可以自定義,用來因爲環境的隔離加載類、按需加載、增加加載源、編譯加密等
- 4、底層不能越級加載,不能覆蓋父類已經加載的類
- 內存:堆、棧、本地方法、計數寄存器
- heap堆,線程共用,存儲幾乎所有的實例對象,自動gc
- 新生代,1個eden區,2個survivor區
- 初始對象佔用大於eden區則直接進入老年代
- eden填滿後出發ygc,存活對象進入survivor,如果佔用大於survivor則直接進入老年代
- 每次ygc時,將存活的對象存入survivor另一個區,當前區清空,交換使用狀態,計數器+1,默認14次後進入老年代
- 如果老年代也放不下,則oom
- 老年代
- perm永久代(摒棄):perm永久代固定大小很難調優,並且fgc的時候會移動類元信息,類加載過多會造成perm的oom
- metaspace元空間,替換perm區,存儲元信息、字段、靜態屬性、方法、常量等。元空間在本地內存中分配
- 堆設置,-X jvm參數,ms:memory start;mx:memory max
- -Xms:初始堆大小,初始大小和最大設爲一致,避免在gc後調整堆大小時帶來的額外壓力
- -Xmx:最大堆大小
- -XX:NewSize=n:設置年輕代大小,性能考慮不要太小,否則對象直接進入老年代浪費內存
- -XX:NewRatio=n:設置年輕代和年老代的比值。如:爲3,表示年輕代與年老代比值爲1:3,年輕代佔整個年輕代年老代和的1/4
- -XX:SurvivorRatio=n:年輕代中Eden區與兩個Survivor區的比值。注意Survivor區有兩個。eg:3表示 Eden:Survivor = 3:2,說明一個Survivor區佔整個年輕代的1/5
- -XX:MaxTenuringThreshol=n:配置計數器,記錄對象從新生代轉入老年代的閾值,默認15
- -XX:PretenureSizeThreshold:設置直接進入老年代的對象大小
- -XX:MaxPermSize=n:設置持久代大小,在jdk8+設置會提示,現在改爲元空間
- 新生代,1個eden區,2個survivor區
- jvm stack棧,線程私有
- 只有位於棧頂的幀纔是有效的,稱爲當前棧
- StackOverflowError棧溢出,通常出現在遞歸方法中
- 棧存儲局部變量、操作棧、動態鏈接、方法返回地址
- native method stacks 本地方法棧,線程私有
- 不再受jvm控制,甚者可以直接操作cpu的寄存器,出錯信息都是黑盒
- eg:system.currentTimeMillis()
- native heap OutOfMemory
- Program Counter Register 程序計數寄存器,線程執行或恢復都要依賴
- 對象實例化過程
- 1、確認類元數據是否存在,不存在則類加載,進入堆內存
- 2、分配棧內引用變量的內存空間
- 3、設置默認值(不同形式的零值)
- 4、執行方法內的init,並把堆內對象的首地址賦值給引用變量
- heap堆,線程共用,存儲幾乎所有的實例對象,自動gc
- 垃圾回收
- System.gc()提醒虛擬機進行垃圾回收,不建議使用
- 判斷是否可以回收
- 判定:如果一個對象與GC Roots之間沒有直接或間接的引用關係
- eg:失去任何引用的對象、或者兩個互相環島狀循環引用的對象
- 可回收:類靜態屬性中、常量、虛擬機棧中、本地方法棧中引用的對象
- 回收算法
- “標記-清除”:基礎算法,造成空間碎片,導致分配較大連續空間時容易出發fgc
- “標記-整理”:改進算法,將存活對象整理到內存空間的一端,解決空間碎片問題
- “mark-copy”:繼續改進算法,將標記和整理空間分爲兩塊,依次激活,解決並行的問題;是主流的解決ygc算法
- 回收器
- jdk8默認回收器查看命令行: java -XX:+PrintCommandLineFlags -version
- 默認:
- jdk11 默認垃圾收集器G1
- jdk1.8 默認垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代),即:-XX:+UseParallelGC 並行收集器,是獨佔式的,最大化的提高程序吞吐量,同時縮短程序停頓時間,另外它不能與CMS收集器配合工作
- idea2017的openjdk默認jvm配置,配置很多,關鍵點展示
- -XX:+UseParNewGC:年輕代並行整理
- -XX:+UseConcMarkSweepGC:老年代並行整理,一般就使用這個
- -XX:+UseCMSCompactAtFullCollection:老年代進行壓縮整理
- -XX:+UseCMSInitiatingOccupancyOnly:自定義回收,減少gc
- -XX:CMSInitiatingOccupancyFraction=70:配合上面的參數,70%以後gc
- -XX:CMSFullGCsBeforeCompaction=0:每次fgc只要超過70%就進行壓縮
- 還有一些減少停頓、gc佔運行時間佔比、指定線程數量等等的很多配置……
- 垃圾回收器詳解
- CMS回收器:較常用,使用“標記-清除”算法,會產生大量碎片,需要其他配置見上
- G1回收器:-XX:+UseG1GC,使用“mark-copy”算法,通過jstat查看垃圾回收情況
- jstat是jdk提供的查看內存的小工具,命令: jstat -class pid
- 統計信息
- -XX:+PrintGCDetails:java -xx -version
- 優化
- JVM調優工具,Jconsole,jProfile,VisualVM
- 年輕代大小選擇
- 響應時間優先的應用:儘可能設大,直到接近系統的最低響應時間限制(根據實際情況選擇)。在此種情況下,年輕代收集發生的頻率也是最小的。同時,減少到達年老代的對象。
- 吞吐量優先的應用:儘可能的設置大,可能到達Gbit的程度。因爲對響應時間沒有要求,垃圾收集可以並行進行,一般適合8CPU以上的應用。
- 年老代大小選擇
- 響應時間優先的應用:如果堆設置小了,可以會造成內存碎片、高回收頻率以及應用暫停而使用傳統的標記清除方式;如果堆大了,則需要較長的收集時間。參考:
- 併發垃圾收集信息
- 持久代併發收集次數
- 傳統GC信息
- 花在年輕代和年老代回收上的時間比例
- 減少年輕代和年老代花費的時間,一般會提高應用的效率
- 吞吐量優先的應用
- 一般吞吐量優先的應用都有一個很大的年輕代和一個較小的年老代。原因是,這樣可以儘可能回收掉大部分短期對象,減少中期的對象,而年老代盡存放長期存活對象。
- 較小堆引起的碎片問題
- MAC優化了停頓,但是碎片需要其他配置,見以上文檔描述
- 使用G1的回收方式
- 響應時間優先的應用:如果堆設置小了,可以會造成內存碎片、高回收頻率以及應用暫停而使用傳統的標記清除方式;如果堆大了,則需要較長的收集時間。參考:
- oom分析,所有的調優都是爲了用戶體驗(減少卡頓)、減少oom的發生
- -XX:+HeapDumpOnOutOfMemoryError:讓jvm遇到oom的時候能輸入堆內信息
- 彙總常用工具、框架,例如數據庫、文件、映射、地圖、多媒體、網絡、安全、搜索、序列化、模版等工具
- 彙總最佳工具實踐
linux
- 系統命令
- uname [-amnprsv] :顯示機器的處理器架構、版本信息、內核等
- rpm
- yum install
- apt
- cal 2018 :顯示2018年的日曆表
- clear :清空命令行
- ifconfig :顯示或設置網卡(查ip等)(類似windows中ipconfig)
- ping -c 3 www.baidu.com :測試百度與本機的連接情況( -c 3表示測試3次)
- top :動態實時顯示cpu、內存、進程等使用情況(類似windows下的任務管理器)
- vmstat 2 10 :每隔2秒採集一次服務器狀態,採集10次(查看內存、io讀寫狀態、cpu)
- free -h :查看系統內存及虛擬內存使用情況
- df -h :顯示磁盤的空間使用情況
- iostat :可查io讀寫、cpu使用情況(mac)
- ps aux|grep firefox :獲取火狐的進程號(PID)(可查看進程佔用cpu、內存百分比及進程觸發指令的路徑)
- ps -ef | grep java : <s|l|o|t|m|a>
- kill -9 進程號 :強制殺死進程
- systemctl :查看正在運行的服務
- 權限
- chmod [-R] 777文件或目錄 :設置權限(chmod a+rwx a=chmod ugo +rwx a=chmod 777 a)
- chown [-R] admin:root /opt/ :變更文件及目錄的擁有者和所屬組(-R遞歸處理所有文件和文件夾,admin爲擁有者,root爲所屬者)
- 文件
- cd
- pwd 查看當前目錄
- mkdir
- touch a.txt :創建文件a.txt
- rm
- find /User/ -name *
- which 查找文件,eg:which java; which hive
- mv
- cp
- cat [-n] 文件名 :顯示文件內容,連行號一起顯示
- cat filename |grep ‘關鍵字’ [-A10] :查看filename中含有abc所在行後10行
- less 文件名 :一頁一頁的顯示文件內容
- 空格、pagedown下一頁;pageup上一頁
- “/”向下查詢
- “?”向上查詢
- “n”重複前一個查詢;N反向重複前一個查詢
- “q”離開
- head [-n] 文件名 :顯示文件頭n行內容,n指定顯示多少行
- tail [-nf] 文件名:顯示文件尾幾行內容,n指定顯示多少行,f用於實時追蹤文件的所有更新,常用於查閱正在改變的日誌文件(如tail -f -n 3 a.log 表示開始顯示最後3行,並在文件更新時實時追加顯示,沒有-n默認10行)
- sed [-nefri] :a新增c替換d刪除i插入p打印
- sed -n ‘2,$p’ filename :顯示第二行到最後一行;
- sed -n ‘/搜索的關鍵詞/p’ a.txt :顯示包括關鍵詞所在行
(A10)、前10行(B10)內容;
- grep -i ‘HELLO’ . -r -n :在當前目錄及子目錄下查找文件內容中包含hello的文件並顯示文件路徑(-i表示忽略大小寫)
- 內容
- vim 東西太多
- 壓縮
- file 文件名 :查文件類型(可看是用哪一種方式壓縮的)
- tar -zxvf a.tar.gz -C ./test :解壓tar.gz到當前目錄下的test目錄
- tar -zcvf /opt/c.tar.gz ./a/ :壓縮tar.gz(把當前目錄下的a目錄及目錄下所有文件壓縮爲 /opt/目錄下的c.tar.gz,這樣tar -zxvf c.tar.gz解壓出來帶有目錄a)
- tar -jxvf a.tar.bz2 :解壓tar.bz2(到當前目錄)
- tar -jcvf c.tar.bz2 ./a/ :壓縮tar.bz2(把當前目錄下的a目錄及目錄下所有文件壓縮到當前目錄下爲c.tar.gz2)
- unzip a.zip :解壓zip(到當前目錄)
- unzip -o mdmtest.war -d /opt/mdm :推薦使用unzip解壓war包(-o覆蓋原有文件,-d指定文件解壓後存儲的目錄)
- zip -r c.zip ./a/ :壓縮zip(把當前目錄下的a目錄及目錄下所有文件壓縮到當前目錄下爲c.zip
- bzip2 -k file1 : 壓縮一個 ‘file1’ 的文件(-k表示保留源文件)(bzip2格式,比gzip好)
- bzip2 -d -k file1.bz2 : 解壓一個叫做 'file1.bz2’的文件
- gzip file1 : 壓縮一個叫做 'file1’的文件(gzip格式)(不能保留源文件)
- gzip -9 file1 : 最大程度壓縮
- gzip -d file1.gz : 解壓縮一個叫做 'file1’的文件
- shell腳本
-
運行 ./xx.sh,如果不用./則會去path裏面找路徑
-
變量
-
基礎
- 與其他語言類似,name=“params”,不能有空格
- 變量以{}包裹
- 雙引號內部可以有變量,單引號不行,所以拼接等建議使用雙引號
- echo -e 激活轉義符(mac不需要)
- 字符串長度:${#變量}
-
字符串
- 長度:${#變量}
- 提取:${變量:開始:個數}(從開始+1截取個數)
-
數組
- array_name=(value0 value1 value2 value3)
- array_name[0]=value0
- valuen=${array_name[n|@]}
-
傳遞參數
echo "執行的文件名:$0"; echo "第一個參數爲:$1"; $ ./test.sh 1 2 3 Shell 傳遞參數實例! 執行的文件名:./test.sh 第一個參數爲:1
- $@全部參數
- $*全部參數作爲一個參數
-
-
命令-關係與邏輯
- 算數,加減乘除:echo `expr 2 + 2` 注意空格必須要有
- 布爾運算 eg:if [ $a -lt 5 -o $b -gt 100 ]
- !非
- -o 或
- -a 與
- eg:if [ $one == $two ]; then xxx elif xxx else xxx fi
- 關係,只支持數字,eg:if [ $a -eq $b ]
- -eq 相等
- -ne 不相等
- -gt 大於
- -lt 小於
- -ge 大於等於
- -le 小於等於
- 邏輯運算 eg:if [[ $a -lt 100 && $b -gt 100 ]]
- && ||
- 字符串運算符
- = !=
- -z 是否爲0
- -n 是否不爲0 eg:if [ -n “$a” ]
- $ 是否爲空 eg:if [ $a ]
-
命令-文件測試運算符
- -r file 文件是否可讀;-w 是否可寫
- -f file 是否是普通文件(非設備、非目錄文件);-d 是否是目錄
- -x file 是否可執行
- -s file 文件不爲空;-e 文件存在
-
命令-其他
-
read 獲取console的輸入
- eg:read param;echo $param
-
echo
- \n 換行,\c 不換行,\f 換頁,\r 回車,\t 水平製表符,\v 垂直製表符
- -e 轉義
- 單引號:原文輸出
- 反引號:輸出命令結果
- 輸出到文件(覆蓋):eg:echo “Im’ OK” >xxx/test.sh
-
printf,同c語言
- eg:
printf "%-10s %-8s %-4s\n" 姓名 性別 體重kg printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234 # %s %c %d %f都是格式替代符;-10:寬度;-4.2f:保留小數等
- 無論多少個佔位符,多少個參數,都按照參數數量進行格式輸出;注意:如果是%d,但是參數是字符串,則報錯
printf "%s %s\n" "參數一" "參數二" # 參數一 參數二 printf "%s %s %s\n" "參數一" "參數二" # 參數一 參數二 printf "%s\n" "參數一" "參數二" "參數三" # 參數一 # 參數二 # 參數三
-
test eg:if test $num1 = $num2
- 測試、調試等使用,可以快速獲取表達式問題
-
-
流程控制
- if:if [ $(ps -ef | grep -c “ssh”) -gt 1 ]; then echo “true”; fi
- for:for var in item1 item2 … itemN; do command1; command2… done;
- while:while condition do command done
- 無限循環:while true …… 或者 for (( ; ; ))
- case:
read item case "$item" in 1|z|\*) echo "case 1" ;; *) echo "default" ;; esac
- break
- continue
-
函數,注意參數當n>=10時,需要使用${n}來獲取參數
function name () { echo "name函數->$1" #a } name a b c d
-
輸入/重定向
- 輸出
- 覆蓋:command1 > file1;eg:who > test.sh * 追加:command1 >> file1;eg:who >> test.sh
- 輸入
- 將xxx的內容做cat處理:cat < xxx.xlsx
- 如果希望執行某個命令,但又不希望在屏幕上顯示輸出結果,那麼可以將輸出重定向到 /dev/null;/dev/null 是一個特殊的文件,寫入到它的內容都會被丟棄
- 輸出
-
設計模式
- spring中的設計模式
- 原則
- 開閉原則 - 對擴展開放,對修改關閉
- 里氏代換原則 - 任何基類可以出現的地方,子類一定可以出現
- 依賴倒轉原則 - 針對接口編程,依賴於抽象而不依賴於具體
- 接口隔離原則 - 使用多個隔離的接口,比使用單個接口要好
- 合成複用原則 - 儘量使用合成/聚合的方式,而不是使用繼承
- 創建型
- 簡單工廠(不屬於23種設計模式)
- Spring 中的 BeanFactory 就是簡單工廠模式的體現,根據傳入一個唯一的標識來獲得 Bean 對象
- 工廠方法模式(只對結果負責,不要三無產品)
- 一般情況下,應用程序有自己的工廠對象來創建 Bean.如果將應用程序自己的工廠對象交給 Spring 管 理,那麼 Spring 管理的就不是普通的 Bean,而是工廠 Bean
- 單例模式(保證獨一無二)
- Spring 下默認的 Bean 均爲單例
- 原型模式(拔一根猴毛,吹出千萬個)
- 就是 Java 中的克隆技術,以某個對象爲原型。複製出新的對象。顯然新的對象具備原 型對象的特點,效率高(避免了重新執行構造過程步驟)
- 簡單工廠(不屬於23種設計模式)
- 結構型
- 代理模式(辦事要求人,所以找代理)
- Spring 的 Proxy 模式在 AOP 中有體現,比如 JdkDynamicAopProxy 和 Cglib2AopProxy
- 模板方法模式(流程標準化,原料自己加)
- 定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。Template Method 使得子類可以不改變 一個算法的結構即可重定義該算法的某些特定步驟。 TemplateMethod 模式一般是需要繼承的。這裏想要探討另一種對 TemplateMethod 的理解。Spring 中的 JdbcTemplate
- 委派模式(不屬於23種設計模式)(活你幹,功勞是我的)
- 這種模式的原理爲類 B 和類 A 是兩個互相沒有任何關係的類,B 具有和 A 一模一樣的方法和屬性;第三方的代碼不需要知道 A 的 存在,也不需要和 A 發生直接的聯繫,通過 B 就可以直接使用 A 的功能,這樣既能夠使用到 A 的各種功 能,又能夠很好的將 A 保護起來了,一舉兩得
- 適配器模式(需要一個轉換頭)
- Spring AOP 模塊對 BeforeAdvice、AfterAdvice、ThrowsAdvice 三種通知類型的支持實際上是借 助適配器模式來實現的,這樣的好處是使得框架允許用戶向框架中加入自己想要支持的任何一種通知類 型,上述三種通知類型是 Spring AOP 模塊定義的,它們是 AOP 聯盟定義的 Advice 的子類型。
- 裝飾器模式(需要包裝,但不改變本質)
- IO流包裝、數據源包裝
- 觀察者模式(完成時通知我)
- 定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象 都得到通知並被自動更新。 Spring 中 Observer 模式常用的地方是 Listener 的實現。如 ApplicationListener
- 代理模式(辦事要求人,所以找代理)
- 行爲型
- 策略模式(我行我素,達到目的就行)
- 定義一系列的算法,把它們一個個封裝起來,並且使它們可相互替換。本模式使得算法可獨 立於使用它的客戶而變化。 Spring 中在實例化對象的時候用到 Strategy 模式,在 SimpleInstantiationStrategy 有使用
- 策略模式(我行我素,達到目的就行)