色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

記一次大庫大表的治理過程

京東云 ? 來源:jf_75140285 ? 作者:jf_75140285 ? 2024-07-24 09:53 ? 次閱讀

一、背景

部門中一核心應用,因為各種原因其依賴的MySQL數據庫一直處于高水位運行,無論是硬件資源,還是磁盤使用率或者QPS等都處于較高水位,急需在大促前完成對應的治理,降低各項指標,以保障在大促期間平穩運行,以期更好的支撐前端業務。

二、基本情況

2.1、數據庫

目前該數據庫是一主兩從,且都是零售的物理機,運行多年已都是過保機器。同時因為CPU和磁盤較大,已無同規格的物理機可以增加一個從庫。同時其中一個從庫的內存減半且磁盤還是機械盤,出故障風險極高且IO性能低導致查詢偏慢,出現過多次因性能問題切到另一個從庫的情況。

以下是其3臺機器的硬件資源信息,MySQL版本、部署機房和硬件配置情況。其中135機器硬盤容量128T是統計顯示有誤,可以認為也是16T。因為磁盤做了RAID0,因此實際容量在7T左右。

IP 域名 主/從 CPU 內存 容量 機房 DISK(/export)使用率(%) Memory使用率(%) 數據庫版本
1x.x.x.36 xxx_m.mysql.jddb.com 64 256G 16T 匯天云端機房 66.3% 87.7% 5.5.14
1x.x.x.73 xxx_sb.mysql.jddb.com 64 256G 16T 匯天云端機房 66.6% 85.2% 5.5.14
1x.x.x.135 xxx_sa.mysql.jddb.com 64 128G 128T 廊坊機房 76.5% 57.2% 5.5.14

2.2、磁盤空間

截止到2月底,各數據庫磁盤空間占用情況如下:

IP 主從 使用大小(G) 已用比例(%) 剩余空間(G) 周增長量(G) 預計報警(d) 預計可用(d) binlog(G) 日志(G)
1x.x.x.36 M 5017 69 2151 9 617.1 1735.8 159.45543 6
1x.x.x.73 S 5017 71 2151 14.8 333.2 1012.7 158.52228 1
1x.x.x.135 S 5017 4 129000 14.4 2986 8958 158.13548 0

從上表咱們可以看出,各數據庫的磁盤空間占用已處于較高水位,急需需要治理,通過結轉或刪除數據來降低磁盤占用比例。

2.3、表空間

數據庫存在大表其中一個原因是多條業務線共用一個應用,同時代碼層面抽象的部分不夠抽象,擴展部分又不容易擴展,導致數據都糅合和一起。

以下是所有的表空間占用情況,可以明顯看到大部分的表數據量都在千萬行以上,特別是前7張表的表空間占用都在100個G以上,數據行數也都在億級以上,最多的是status表,30億行數據,典型的大庫大表。

wKgZomad3a6ASDHhAAfe63Beiwg409.png

2.4、QPS情況

黃色的為主庫的QPS,可以看出主庫的查詢量遠大于從庫,由于各種原因,應用代碼里只有少部分的查詢是走的從庫,急需將部分流量大的查詢接口從主庫切到從庫去查詢;

wKgaomad3bCAYUhbAA7meR3bqDc229.png

2.5、慢SQL

不論是主庫還是從庫,都有偶發的慢SQL查詢,引發磁盤繁忙,影響系統穩定性。

wKgZomad3bGAGr-cAAHdzBDsoeA485.png

三、治理目標

1.數據結轉,降低磁盤使用率,處較低水位運行。

治理目標:將表空間占用大于100G的7張表(xxx_status、xxx_main、xxx_exception、xxx_product_code、xxx_item、freights_info、xxx_extend)先進行集中結轉,保留一年數據后進行常態化結轉,按天結轉,將數據量保持在365天;

1.降低主庫QPS,保障主庫安全。

治理目標:將主庫的高頻查詢切換到從庫查詢,使主庫白天QPS降低30%,近一個月上午峰值平均在20k,下午峰值平均在25k;治理的目標為:上午峰值15k,下午峰值18k;

1.慢SQL治理,避免導致磁盤繁忙而影響整體業務。

治理目標:10s以上的徹底消除;5s以上的,消除80%;1s以上的消除60%;底數是過去一個月(1s以上慢sql);

四、治理方案

4.1、大表數據結轉

根據這7張表的業務屬性不同,結轉的類型也不相同;比如對于歷史數據無意義的,可以將歷史數據直接刪除,比如xxx_exception;另外一類是純歷史數據,比如流水數據xxx_status表,結轉方式是同步大數據平臺后就可以刪除;最后是業務主數據,是需要同步大數據平臺和需要結轉至歷史庫的,比如main、item和extend表等;

表名 表空間GB 索引空間GB 大數據 結轉類型 開始值 完成值
xxx_status 991.65 265.29 刪除 2020-04-30 01:00:00 2022-01-01
xxx_main 611.80 149.91 結轉 2021-09-30 2022-01-01
xxx_exception 382.80 24.65 刪除 2018-05-16 20:30:04 2022-01-01
xxx_product_code 244.18 61.54 刪除 ?
23億
xxx_item 208.66 85.46 結轉 2016-12-29 13:20:33 2022-01-01
xxx_freights_info 128.78 109.03 結轉 2018-11-29 13:26:00 ?
xxx_extend 127.36 26.07 結轉 2019-03-29 14:30:00 2022-01-01

以下的統計表格是在同步大數據平臺后集中刪除和結轉的空間釋放情況,在1個月內對數據量在1億以上并且占用空間在100G以上的7張大表進行了刪除和結轉后刪除,使數據在保留365天的業務承諾時間范圍內,降低了470G(10%)的磁盤空間占用

wKgaomad3bGABuM-AAY8I_ZJaio501.png

PS:紅色數字部分為負值,也就是磁盤的釋放空間。

4.2、攔截無參數查詢

運單主檔查詢偶發會有無任何參數的查詢,引發嚴重慢SQL,造成數據庫磁盤繁忙度嚴重飚高,極大地影響了其他業務操作,而由于入口眾多和交叉調用,如果在入口做參數校驗工作量及風險都比較大,所以采用MyBatis的插件機制在dao層做攔截,直接拒絕掉無參數的查詢,上線后就再沒有出現過因無參查詢而出現慢SQL而導致的磁盤繁忙情況;

mybatis-config.xml里的plugin配置:

wKgZomad3bKAZPjiAAIWb8t3Y1w666.png

ParameterInterceptor關鍵代碼如下:

wKgaomad3bSAH-E2AAkQrWzM18o184.png

源代碼如下:

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * MyBatis攔截器,用于攔截SQL查詢無入參的場景,避免全表查詢
 *
 */
@Intercepts({
        @Signature(type = Executor.class, method = "query",
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class ParameterInterceptor implements Interceptor {

    private final Map mappedStatementIdMap = new HashMap();

    @Override
    public Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException {
        Object[] queryArgs = invocation.getArgs();

        MappedStatement mappedStatement = null;
        if (queryArgs[0] instanceof MappedStatement) {
            mappedStatement = (MappedStatement) queryArgs[0];
        }

        if (null != mappedStatement && mappedStatementIdMap.containsKey(mappedStatement.getId())) {
            // 獲取SQL
            BoundSql boundSql = mappedStatement.getBoundSql(queryArgs[1]);

            List parameterMappingList = boundSql.getParameterMappings();

            if (parameterMappingList.isEmpty()) {
                Profiler.businessAlarm(mappedStatement.getId(), "查詢參數為空");
                throw new BadArgumentException("查詢參數為空,請確認入參是否有值");
            }

        }

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        for (Object key : properties.keySet()) {
            mappedStatementIdMap.put(key, 1);
        }
    }
}

4.3、查詢切從庫

主庫QPS高峰期達30k/s,長期處于高位運行,需要梳理出TOP10的查接口來切從庫查詢,而應用中接口眾多,無法逐個接口查各接口的調用量,可以利用JSF的filter功能結合UMP業務監控來統計provider的調用次數,再通過Python程序獲取統計數據生產統計報表。

JSF的配置文件新增filter



JsfInvokeFilter的代碼:

import com.jd.jsf.gd.filter.AbstractFilter;
import com.jd.jsf.gd.msg.RequestMessage;
import com.jd.jsf.gd.msg.ResponseMessage;
import com.jd.jsf.gd.util.RpcContext;
import com.jd.ump.profiler.proxy.Profiler;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
 * JSF filter
 * JSF服務的調用次數統計
 */
@Component
public class JsfInvokeFilter extends AbstractFilter {
    /**
     * 按API接口統計方法調用量 - 業務監控KEY
     */
    private static final String API_PROVIDER_METHOD_COUNT_KEY = "api.jsf.provider.method.count.key";
    private static final String API_CONSUMER_METHOD_COUNT_KEY = "api.jsf.consumer.method.count.key";
    @Override
    public ResponseMessage invoke(RequestMessage requestMessage) {
        String key;
        if (RpcContext.getContext().isProviderSide()) {
            key = API_PROVIDER_METHOD_COUNT_KEY;
        } else {
            key = API_CONSUMER_METHOD_COUNT_KEY;
        }
        String method = requestMessage.getClassName() + "." + requestMessage.getMethodName();
        Map tags = new HashMap(2);
        tags.put("bMark", method);
        tags.put("bCount", "1");
        Profiler.sourceDataByStr(key, tags);
        return getNext().invoke(requestMessage);
    }
}

業務監控點列表

wKgZomad3baAZf1OAAmqiKv-dQs160.png

明細項

wKgaomad3bmAe4beABzJxaNCrIE950.png

Python腳本

import os
import openpyxl
import json
import requests
from cookies import Cookie
import time

headers = {
    'Cookie': Cookie,
    'Content-Type': 'application/json',
    'token': '******',
    'erp': '******'
}


def get_jsf(start_time, end_time):
    url = 'http://xxx.taishan.jd.com/api/xxx/xxx/xxx/'
    body = {}
    params = {'startTime': start_time,
              'endTime': end_time,
              'endPointKey': 'api.jsf.provider.method.count.key',
              'quickTime': int((end_time - start_time) / 1000),
              'markFlag': 'true',
              'markLimit': 500}

    res = requests.post(url=url, data=json.dumps(body), params=params, headers=headers)

    print('url: ', res.request.url)  # 查看發送的url
    # print('response: ', res.text)  # 返回請求結果

    res_json = json.loads(res.text)

    title = ['序號', 'jsf key', '次數', '占比%', '峰值', '次/秒', '峰值時間']
    i = 0

    keys = {}
    marks = res_json['response_data']['marks']
    for mark in marks:
        keys.setdefault(mark, [0, 0, 0, ''])

    data = []
    records = res_json['response_data']['monitorData']
    print(len(records))
    for key, value in records.items():
        count = 0
        max_val = 0
        max_time = ''
        for val in value:
            v = val['value']
            count += v
            if v > max_val:
                max_val = v
                max_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(val['dateTime'] / 1000)))
        keys[key] = [count, max_val, int(max_val / 1200), max_time]

    key_list = sorted(keys.items(), key=lambda x: x[1], reverse=True)
    # print(key_list)

    all_count = key_list[0][1][0]

    for key in key_list:
        values = [i, key[0], key[1][0], str(round(key[1][0] / all_count * 100, 2)) + '%', key[1][1], key[1][2], key[1][3]]
        data.append(values)
        i += 1
    #
    # # print(data)
    #
    path = r"/Users/xxx/Documents/治理/QPS治理/"
    os.chdir(path)  # 修改工作路徑
    workbook = openpyxl.Workbook()
    sheet = workbook.active
    sheet.title = 'JSF接口調用次數統計'
    sheet.append(title)
    for record in data:
        sheet.append(record)
    workbook.save('JSF接口調用次數統計-' + str(start_time / 1000) + '-' + str(end_time / 1000) + '.xlsx')


def change_time(dt):
    # 轉換成時間數組
    time_array = time.strptime(dt, "%Y-%m-%d %H:%M:%S")
    # 轉換成時間戳
    timestamp = time.mktime(time_array)
    return int(timestamp * 1000)


if __name__ == '__main__':
    start_time = '2024-03-06 12:20:00'
    end_time = '2024-03-07 12:20:00'

    get_jsf(change_time(start_time), change_time(end_time))


Cookie的代碼如下:

Cookie = '*****'

wKgZomad3byAENCBABPbu106yC8183.png

分析Top10接口的切從庫方案:

序號 接口 日調用量 占比% 次/秒 涉及到的表 是否可以切從庫 切從庫方案
0 總調用量 69787485 100.0% 1114 ?
?
?
1 com.jd.xxx.service.xxx.getLwbMainAndRelatedInfoByLwbNo 35366937 50.68% 747 lxxx_main xxx_goods_item extend_info xxx_extend 單查詢,在Service層加注解走從庫查詢
2 com.jd.xxx.service.xxx.getLwbMainByLwbNo 12212805 17.5% 235 xxx_main xxx_main_ext_coldchain xxx_product_code xxx_extend 有很多地方引用這個方法,切從庫需要新增API接口,在Service新增的方法上加走從庫注解
3 com.jd.xxx.open.xxx.getLwbMainPartByLwbNo 4138702 5.93% 102 xxx_main 在Service層加注解走從庫查詢
4 com.jd.xxx.open.xxx.gotoB2BSWbMainAllTrack 3929935 5.63% 70 xxx_main 兩次 xxx_main_ext_coldchain 在Service層加注解走從庫查詢
5 com.jd.xxx.btp.taskfunnel.handler.Handler.doFilter 2206697 3.16% 37 ?
接單框架(實現方法太多)
6 com.jd.xxx.service.xxx.findLwbMainByCondition 1435493 2.06% 32 xxx_main 列表查詢 xxx_item 是否查明細 package_added_service package_added_service_item 取舊服務 xxx_pay_main xxx_extend xxx_product_code xxx_main_ext_coldchain 有很多地方引用這個方法,切從庫需要新增API接口,在Service新增的方法上加走從庫注解
7 com.jd.xxx.open.OmsOrientedService.queryWayBillByLwbNo 1059754 1.52% 33 xxx_main freights_info xxx_enquiry_main xxx_status 兩次 xxx_b2b_box_item xxx_coupon 兩次 xxx_extend 積分 在Service層加注解走從庫查詢
8 com.jd.xxx.open.SellerOrientedService.getFreightsInfoFromTable 1008603 1.45% 66 xxx_main xxx_b2b_package xxx_extend xxx_product_code xxx_main_ext_coldchain xxx_main_ext_site freights_info fee_detail xxx_b2b_box_item 在Service層加注解走從庫查詢
9 com.jd.xxx.service.xxx.getLwbMain 817341 1.17% 24 xxx_main xxx_b2b_package xxx_extend xxx_product_code xxx_main_ext_coldchain xxx_main_ext_site 有很多地方引用這個方法,切從庫需要新增API接口,在Service新增的方法上加走從庫注解
10 com.jd.xxx.open.OmsOrientedService.getWayBillSettleMode 730328 1.05% 18 無數據庫查詢 ?
?

通過優化讀操作切換至從庫查詢,降低了主庫30%的QPS流量,白天峰值從25k降低到17.5k;

wKgaomad3cOAF0OmABP_QRWz6I0769.png

治理前QPS(峰值25k

wKgZomad3cWAatzmABV9o1XGMzk074.png

治理后QPS(峰值17.5k

4.4、慢SQL治理

通過對慢SQL設定有針對性的治理,成功地徹底消除10s以上的慢SQL;5s以上的,消除80%;1s以上的消除60%。

關于慢SQL的治理不過多介紹,采用的都是通用分析和治理方法,有很多的文章都有介紹。需要注意的是在治理過程中要做好灰度,完全驗證后再全量上線運行。

五、寫在最后

可能有同學會想到分庫分表,一個是在規劃中提前部署分庫分表,一個是現在使用分庫分表技術進行治理;關于前一個問題由于時間久遠咱們不做過多討論,關于未使用分庫分表進行治理的原因是業務規劃的問題,目前此應用業務較為穩定,如采用分庫分表治理動作比較大風險較高,ROI不高,故以上治理方案以穩定為主降低風險為輔。

還有一個治理方案是遷云,利用云計算的彈性及快速恢復等特性降低來運行風險,因為業務的不可中斷性,此方案必須是在線遷移,涉及雙數據庫從雙寫到雙讀,再到單讀,最后單寫,還有數據一致性檢查和同步等,成本較高。同時云數據庫未能有如此大的磁盤容量和CPU核數,所以此方案需要結合分庫分表方案同時進行,更增加了成本和風險,但此方案目前是在計劃中的,如業務有較大幅度增長,以上治理也已無法滿足時,將采用遷云加分庫分表,且分庫和分表是分期進行推進。

六、探討

大家在日常及大促中有其他好的治理方案的話,歡迎發在評論區一起探討。


審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • SQL
    SQL
    +關注

    關注

    1

    文章

    773

    瀏覽量

    44219
  • 數據庫
    +關注

    關注

    7

    文章

    3845

    瀏覽量

    64601
  • MySQL
    +關注

    關注

    1

    文章

    829

    瀏覽量

    26682
收藏 人收藏

    評論

    相關推薦

    【freeRTOS開發筆記】一次坑爹的freeTOS升級

    【freeRTOS開發筆記】一次坑爹的freeTOS-v9.0.0升級到freeRTOS-v10.4.4
    的頭像 發表于 07-11 09:15 ?4728次閱讀
    【freeRTOS開發筆記】<b class='flag-5'>記</b><b class='flag-5'>一次</b>坑爹的freeTOS升級

    labview能否對動態數組的元素每循環一次就比較一次大

    labview能否對個動態數組,每進行一次循環,就比較下本次元素值和上次元素值的大小,若大于上次循環元素,則記錄,不大于,則不記錄
    發表于 11-16 17:11

    使用HAProxy軟件的一次學習過程介紹

    一次學習過程
    發表于 06-13 10:48

    一次網站設計稿的方法

    一次網站設計稿
    發表于 06-16 09:43

    一次完整的Ping過程會涉及哪些協議?

    一次完整的網絡Ping過程
    發表于 03-31 06:19

    記錄一次STM32H743 CANFD調試過程中的一次BUG

    記錄一次STM32H743 CANFD調試過程中的一次BUG
    發表于 08-13 06:30

    一次呼叫典型流程

    一次呼叫典型流程:一次呼叫典型流程B.1 概述本章將分別給出主叫流程和被叫流程的例子,以示一次通話過程中UTRAN的典型流程。B.2 主叫流程主叫流程是指UE呼叫其它用戶
    發表于 11-28 17:57 ?26次下載

    一次過程的等值電路

    一次過程的等值電路 圖 一次過程的等值電路 在電動機端子上安裝阻抗匹配器可
    發表于 07-18 11:24 ?1722次閱讀
    <b class='flag-5'>一次</b>波<b class='flag-5'>過程</b>的等值電路

    數字電視的典型的處理過程

    典型的處理過程 下面介紹數字電視的幾個典型的處理過程
    發表于 07-31 14:23 ?1549次閱讀
    數字電視的典型的處<b class='flag-5'>理過程</b>

    華為的一次大膽嘗試燒起了把火,所有手機都借鑒這個功能

    華為的一次大膽嘗試燒起了把火,所有手機都借鑒這個功能!華為向在技術創新和大膽嘗試上出名,這次也是依靠其果敢的嘗試,掀起了場手機革命。
    發表于 02-08 10:14 ?970次閱讀

    【學習打卡】一次給OpenHarmony提交代碼的過程

    一次給OpenHarmony提交代碼的過程 作者:堅果 公眾號:"大前端之旅" OpenHarmony布道師,InfoQ簽約作者,CSDN博客專家,華為云享專家,阿里云專家博主,51CTO博客首席
    的頭像 發表于 07-02 10:31 ?2778次閱讀
    【學習打卡】<b class='flag-5'>記</b><b class='flag-5'>一次</b>給OpenHarmony提交代碼的<b class='flag-5'>過程</b>

    電氣一次識圖基礎

    電氣一次識圖基礎
    的頭像 發表于 11-12 11:24 ?2148次閱讀

    腳本小子的一次滲透全過程

    .前言 在一次綜合滲透的過程中遇到的比較完整的個滲透流程。很多現查的技巧,這次滲透的基礎是基于隊友已經在服務器寫入了句話木馬但無法執行
    的頭像 發表于 06-14 09:21 ?606次閱讀
    <b class='flag-5'>記</b>腳本小子的<b class='flag-5'>一次</b>滲透全<b class='flag-5'>過程</b>

    一次調頻和二調頻的概念 一次調頻可以實現無差調節?

    頻帶(單邊帶調制)的技術。在無線電通信中的一次調頻,是指把通過調制產生的語音、圖像等信息信號直接調制到載波上,而不需要經過中間頻率過程。單邊帶調制被廣泛用于無線電通信中,如AM廣播、短波通信、海事通信、衛星通信等領域。 2. 二
    的頭像 發表于 10-17 16:15 ?9620次閱讀

    oracle如何一次添加多行數據

    Oracle是種關系型數據管理系統,可以通過SQL語句來操作數據。要一次添加多行數據,可以使用INSERT INTO語句結合使用INSERT ALL和SELECT子句。 INSE
    的頭像 發表于 11-21 14:15 ?5520次閱讀
    主站蜘蛛池模板: 色婷婷99综合久久久精品 | 国产免费午夜高清 | yellow片高清视频免费看 | 老司机深夜福利ae 入口网站 | 高清无码中文字幕在线观看视频 | 精品国产自在现线拍400部 | 欧美另类摘花hd | 免费特黄一区二区三区视频一 | 成 人 色综合 | 成人性生交片无码免费看 | 内射无码AV-区二区在线观看 | 国产在线一区二区AV视频 | 99pao成人国产永久免费视频 | 97国产成人精品视频 | 护士一级片| 日本福利片午夜免费观着 | 99九九精品国产高清自在线 | 国内国外精品影片无人区 | 亚洲 小说 欧美 激情 另类 | 国产亚洲精品久久无码98 | 泡妞高手在都市免费观看 | 久久re视频精品538在线 | 久久无码人妻AV精品一区 | 美女挑战50厘米长的黑人 | 精品人妻无码一区二区三区蜜桃臀 | 最新高清无码专区 | 在线免费观看毛片网站 | 高清bblxx手机在线观看 | 精品久久久久久久99热 | 伊人影院综合网 | 午夜阳光影院在线观看视频 | 久久久久综合 | 中文字幕一区二区视频 | 伊人精品在线 | 国产AV精品国语对白国产 | 91精品欧美一区二区三区 | 国产成人午夜精品免费视频 | 国产精品玖玖玖影院 | 一本之道高清在线3线观看 一本之道高清视频在线观看 | 小SAO货水真多把你CAO烂 | 又粗又大又爽又黄的免费视频 |