<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          springboot第70集:字節(jié)跳動(dòng)后端三面經(jīng),一文讓你走出微服務(wù)迷霧架構(gòu)周刊

          共 21090字,需瀏覽 43分鐘

           ·

          2024-04-26 21:48

          創(chuàng)建一個(gè)使用Kubernetes (K8s) 和 Jenkins 來自動(dòng)化 GitLab 前端項(xiàng)目打包的CI/CD流水線,需要配置多個(gè)組件。下面,我將概述一個(gè)基本的設(shè)置步驟和示例腳本,以幫助你理解如何使用這些工具整合一個(gè)自動(dòng)化流程。

          前提條件

          確保你已經(jīng)有:

          1. Kubernetes 集群:用于部署 Jenkins 和可能的其他相關(guān)服務(wù)。

          2. Jenkins:安裝在 Kubernetes 集群上,并配置好相關(guān)插件(例如 GitLab 插件、Kubernetes 插件等)。

          3. GitLab:托管你的前端代碼。

          步驟一:在 Kubernetes 上部署 Jenkins

          首先,你需要在 Kubernetes 集群上部署 Jenkins。你可以使用 Helm chart 來簡化部署過程。以下是一個(gè)基本的 Helm 安裝命令:

             

          helm repo add jenkins https://charts.jenkins.io helm repo update helm install jenkins jenkins/jenkins

          helm repo add jenkins https://charts.jenkins.io
          helm repo update
          helm install jenkins jenkins/jenkins

          確保配置 Jenkins 的持久卷和服務(wù),以便它能穩(wěn)定運(yùn)行并保持?jǐn)?shù)據(jù)。

          步驟二:配置 Jenkins 與 GitLab 的集成

          在 Jenkins 中安裝并配置 GitLab 插件:

          1. 在 Jenkins 中安裝 GitLab Plugin。

          2. 在 GitLab 中創(chuàng)建一個(gè)具有適當(dāng)權(quán)限的訪問令牌。

          3. 在 Jenkins 的系統(tǒng)配置中配置 GitLab 連接,輸入 GitLab 的URL和創(chuàng)建的訪問令牌。

          步驟三:創(chuàng)建 Jenkins Pipeline

          在 Jenkins 中創(chuàng)建一個(gè)新的 Pipeline 項(xiàng)目,你可以使用 Jenkinsfile 來定義流水線。這個(gè) Jenkinsfile 需要放在你的前端項(xiàng)目的根目錄下:

             

          pipeline {
          agent {
          kubernetes {
          yaml """
          apiVersion: v1
          kind: Pod
          spec:
          containers:
          - name: node
          image: node:14-buster
          command:
          - cat
          tty: true
          """
          }
          }
          stages {
          stage('Checkout') {
          steps {
          git branch: 'main', url: 'https://gitlab.example.com/your-username/your-project.git'
          }
          }
          stage('Install') {
          steps {
          script {
          container('node') {
          sh 'yarn install'
          }
          }
          }
          }
          stage('Build') {
          steps {
          script {
          container('node') {
          sh 'yarn build'
          }
          }
          }
          }
          stage('Deploy') {
          steps {
          // 添加部署腳本或 Kubernetes 部署命令
          }
          }
          }
          }

          說明

          • Jenkins Pipeline 使用 Kubernetes 插件在 Kubernetes Pod 內(nèi)運(yùn)行。

          • 使用 Node.js 容器來執(zhí)行前端構(gòu)建任務(wù)(例如 yarn install 和 yarn build)。

          • 這個(gè)示例基于 Node.js 容器,你需要確保鏡像版本與你的項(xiàng)目兼容。

          • 根據(jù)需要調(diào)整 GitLab 倉庫 URL 和分支。

          步驟四:觸發(fā)器和部署

          • 在 Jenkins 中配置觸發(fā)器,以便在 GitLab 中推送更新時(shí)自動(dòng)啟動(dòng)構(gòu)建。

          • 在 "Deploy" 階段,你可以添加部署到 Kubernetes 的步驟,如使用 kubectl 命令或 Helm chart。

          在GitLab CI/CD流水線中,當(dāng)你使用Yarn來安裝依賴,這些依賴通常會(huì)被安裝在項(xiàng)目的node_modules目錄下。這是Node.js和Yarn的標(biāo)準(zhǔn)行為。GitLab CI/CD流水線使用的是GitLab Runner來執(zhí)行定義在.gitlab-ci.yml文件中的作業(yè)。

          GitLab Runner工作目錄

          GitLab Runner通常會(huì)為每一個(gè)CI/CD作業(yè)創(chuàng)建一個(gè)隔離的環(huán)境,這通常是在Runner的系統(tǒng)上的一個(gè)臨時(shí)目錄。這個(gè)目錄通常會(huì)在作業(yè)完成后被清理掉,除非你特別配置了緩存或者工件(artifacts)來存儲(chǔ)這些文件。

          使用 npm 安裝 CLI 到開發(fā)依賴

          $ npm install --save-dev @tarojs/[email protected]

          使用 yarn 安裝 CLI 到開發(fā)依賴

          $ yarn add --dev @tarojs/[email protected]

          使用 cnpm 安裝 CLI 到開發(fā)依賴

          $ cnpm install --save-dev @tarojs/[email protected]

          1. 簡化代碼:將操作合并到單個(gè)流操作中,減少了重復(fù)的代碼。

          2. 使用 flatMap() :使用 flatMap() 處理 feeRuleIds 字段,避免了在循環(huán)中手動(dòng)拆分字符串。

          3. 一致的命名風(fēng)格:使用了統(tǒng)一的命名風(fēng)格(駝峰命名法),提高了代碼的一致性和可讀性。

          4. 使用 StringBuilder 替代字符串拼接,提高效率。

          npm install echarts --save

             

          // echarts-4.0
          import echarts from 'echarts'
          Vue.prototype.$echarts = echarts

          // 引入echarts-5.0
          import * as echarts from 'echarts'
          Vue.prototype.$echarts = echarts

          let myChart = this.$echarts.init(document.getElementById('map'))

          import * as echarts from "echarts";

          let myChart = echarts.init(document.getElementById("map"));

          import "../../node_modules/echarts/map/js/china"; // 引入中國地圖 注意是4.0才有 不然會(huì)報(bào)錯(cuò)

          methods: {
          //中國地圖
          chinaMap() {
          let myChart = echarts.init(document.getElementById("map")); // 初始echarts
          let option = {
          // 繪制地圖
          tooltip: {
          // 提示框信息配置
          // triggerOn: "click", // 觸發(fā)方式
          trigger: "item", // 對象
          // backgroundColor:'#6950a1',
          formatter: (params) => {
          // 格式化提示框信息。 若要訪問 data中的數(shù)據(jù)則要用箭頭函數(shù)
          return `${params.name} <br/>
          地區(qū)ID: ${
          this.arrMap.find((item) => item.name === params.name)
          ?.id ?? 0
          }`;
          },
          },
          series: [
          // 配置地圖
          {
          type: "map", // 類型
          mapType: "china", // 地圖名稱,要和引入的地圖名一致
          roam: true, // 是否開啟鼠標(biāo)縮放和平移漫游
          label: {
          // 地圖省份模塊配置
          normal: { show: true }, // 是否顯示省份名稱
          position: "right", // 顯示位置
          },
          emphasis: {
          // 高亮狀態(tài)下的多邊形和標(biāo)簽樣式。
          label: {
          show: true, // 是否顯示標(biāo)簽。
          },
          },
          itemStyle: {
          //地圖區(qū)域的多邊形圖形樣式
          normal: {
          areaColor: "#2a5caa", //地圖區(qū)域顏色
          borderColor: "#afb4db", //圖形的描邊顏色
          borderWidth: 1, //描邊線寬。為 0 時(shí)無描邊
          borderType: "solid", // 邊框樣式
          opacity: 0.6, // 透明度
          },
          },
          data: this.arrMap, // 提示框的數(shù)據(jù)源
          },
          ],
          };
          myChart.setOption(option);
          },

             

          /**
          * echarts tooltip輪播
          * @param chart ECharts實(shí)例
          * @param chartOption echarts的配置信息
          * @param options object 選項(xiàng)
          * {
          * interval 輪播時(shí)間間隔,單位毫秒,默認(rèn)為2000
          * loopSeries boolean類型,默認(rèn)為false。
          * true表示循環(huán)所有series的tooltip,false則顯示指定seriesIndex的tooltip
          * seriesIndex 默認(rèn)為0,指定某個(gè)系列(option中的series索引)循環(huán)顯示tooltip,
          * 當(dāng)loopSeries為true時(shí),從seriesIndex系列開始執(zhí)行。
          * updateData 自定義更新數(shù)據(jù)的函數(shù),默認(rèn)為null;
          * 用于類似于分頁的效果,比如總數(shù)據(jù)有20條,chart一次只顯示5條,全部數(shù)據(jù)可以分4次顯示。
          * }
          * @returns {{clearLoop: clearLoop}|undefined}
          */
          export function loopShowTooltip(chart, chartOption, options) {
          let defaultOptions = {
          interval: 2000,
          loopSeries: false,
          seriesIndex: 0,
          updateData: null,
          };

          if (!chart || !chartOption) {
          return;
          }

          let dataIndex = 0; // 數(shù)據(jù)索引,初始化為-1,是為了判斷是否是第一次執(zhí)行
          let seriesIndex = 0; // 系列索引
          let timeTicket = 0;
          let seriesLen = chartOption.series.length; // 系列個(gè)數(shù)
          let dataLen = 0; // 某個(gè)系列數(shù)據(jù)個(gè)數(shù)
          let chartType; // 系列類型
          let first = true;
          let lastShowSeriesIndex = 0;
          let lastShowDataIndex = 0;

          if (seriesLen === 0) {
          return;
          }

          // 待處理列表
          // 不循環(huán)series時(shí)seriesIndex指定顯示tooltip的系列,不指定默認(rèn)為0,指定多個(gè)則默認(rèn)為第一個(gè)
          // 循環(huán)series時(shí)seriesIndex指定循環(huán)的series,不指定則從0開始循環(huán)所有series,指定單個(gè)則相當(dāng)于不循環(huán),指定多個(gè)
          // 要不要添加開始series索引和開始的data索引?

          if (options) {
          options.interval = options.interval || defaultOptions.interval;
          options.loopSeries = options.loopSeries || defaultOptions.loopSeries;
          options.seriesIndex = options.seriesIndex || defaultOptions.seriesIndex;
          options.updateData = options.updateData || defaultOptions.updateData;
          } else {
          options = defaultOptions;
          }

          // 如果設(shè)置的seriesIndex無效,則默認(rèn)為0
          if (options.seriesIndex < 0 || options.seriesIndex >= seriesLen) {
          seriesIndex = 0;
          } else {
          seriesIndex = options.seriesIndex;
          }

          /**
          * 清除定時(shí)器
          */
          function clearLoop() {
          if (timeTicket) {
          clearInterval(timeTicket);
          timeTicket = 0;
          }

          chart.off('mousemove', stopAutoShow);
          zRender.off('mousemove', zRenderMouseMove);
          zRender.off('globalout', zRenderGlobalOut);
          }

          /**
          * 取消高亮
          */
          function cancelHighlight() {
          /**
          * 如果dataIndex為0表示上次系列完成顯示,如果是循環(huán)系列,且系列索引為0則上次是seriesLen-1,否則為seriesIndex-1;
          * 如果不是循環(huán)系列,則就是當(dāng)前系列;
          * 如果dataIndex>0則就是當(dāng)前系列。
          */
          let tempSeriesIndex =
          dataIndex === 0
          ? options.loopSeries
          ? seriesIndex === 0
          ? seriesLen - 1
          : seriesIndex - 1
          : seriesIndex
          : seriesIndex;
          let tempType = chartOption.series[tempSeriesIndex].type;

          if (tempType === 'pie' || tempType === 'radar' || tempType === 'map') {
          chart.dispatchAction({
          type: 'downplay',
          seriesIndex: lastShowSeriesIndex,
          dataIndex: lastShowDataIndex,
          }); // wait 系列序號(hào)為0且循環(huán)系列,則要判斷上次的系列類型是否是pie、radar
          }
          }

          /**
          * 自動(dòng)輪播tooltip
          */
          function autoShowTip() {
          let invalidSeries = 0;
          let invalidData = 0;
          function showTip() {
          // chart不在頁面中時(shí),銷毀定時(shí)器
          let dom = chart.getDom();
          if (document !== dom && !document.documentElement.contains(dom)) {
          clearLoop();
          return;
          }

          // 判斷是否更新數(shù)據(jù)
          if (
          dataIndex === 0 &&
          !first &&
          typeof options.updateData === 'function'
          ) {
          options.updateData();
          chart.setOption(chartOption);
          }

          let series = chartOption.series;
          let currSeries = series[seriesIndex];
          if (
          !series ||
          series.length === 0 ||
          !currSeries ||
          !currSeries.type ||
          !currSeries.data ||
          !currSeries.data.length
          ) {
          return;
          }

          chartType = currSeries.type; // 系列類型
          dataLen = currSeries.data.length; // 某個(gè)系列的數(shù)據(jù)個(gè)數(shù)

          let tipParams = {
          seriesIndex: seriesIndex,
          };
          switch (chartType) {
          case 'pie':
          // 處理餅圖中數(shù)據(jù)為0或系列名為空的不顯示tooltip
          if (
          !currSeries.data[dataIndex].name ||
          currSeries.data[dataIndex].name === '空' ||
          !currSeries.data[dataIndex].value
          ) {
          invalidData += 1;
          dataIndex = (dataIndex + 1) % dataLen;
          if (options.loopSeries && dataIndex === 0) {
          // 數(shù)據(jù)索引歸0表示當(dāng)前系列數(shù)據(jù)已經(jīng)循環(huán)完
          // 無效數(shù)據(jù)個(gè)數(shù)個(gè)總數(shù)據(jù)個(gè)數(shù)相等,則該系列無效
          if (invalidData === dataLen) {
          invalidSeries += 1;
          }

          // 新系列,重置無效數(shù)據(jù)個(gè)數(shù)
          invalidData = 0;

          // 系列循環(huán)遞增1
          seriesIndex = (seriesIndex + 1) % seriesLen;
          // 系列數(shù)循環(huán)至起始值時(shí)重置無效系列數(shù)
          if (seriesIndex === options.seriesIndex) {
          if (seriesLen !== invalidSeries) {
          // 下一次系列輪回,重置無效系列數(shù)
          invalidSeries = 0;
          showTip();
          } else {
          // 下一次系列輪回,重置無效系列數(shù)
          invalidSeries = 0;
          clearLoop();
          }
          } else {
          showTip();
          }
          } else if (!options.loopSeries && dataIndex === 0) {
          if (dataLen !== invalidData) {
          invalidData = 0;
          showTip();
          } else {
          invalidData = 0;
          clearLoop();
          }
          } else {
          showTip();
          }

          return;
          }
          // eslint-disable-next-line no-fallthrough
          case 'map':
          case 'chord':
          tipParams.name = currSeries.data[dataIndex].name;
          break;
          case 'radar': // 雷達(dá)圖
          tipParams.seriesIndex = seriesIndex;
          // tipParams.dataIndex = dataIndex;
          break;
          case 'lines': // 線圖地圖上的lines忽略
          dataIndex = 0;
          seriesIndex = (seriesIndex + 1) % seriesLen;
          invalidSeries++; // 記錄無效系列數(shù),如果無效系列數(shù)和系列總數(shù)相等則取消循環(huán)顯示
          if (seriesLen !== invalidSeries) {
          showTip();
          } else {
          clearLoop();
          }
          return;
          default:
          tipParams.dataIndex = dataIndex;
          break;
          }

          if (chartType === 'pie' || chartType === 'radar' || chartType === 'map') {
          if (!first) {
          cancelHighlight();
          }

          // 高亮當(dāng)前圖形
          chart.dispatchAction({
          type: 'highlight',
          seriesIndex: seriesIndex,
          dataIndex: dataIndex,
          });
          }

          // 顯示 tooltip
          tipParams.type = 'showTip';
          chart.dispatchAction(tipParams);

          lastShowSeriesIndex = seriesIndex;
          lastShowDataIndex = dataIndex;

          dataIndex = (dataIndex + 1) % dataLen;
          if (options.loopSeries && dataIndex === 0) {
          // 數(shù)據(jù)索引歸0表示當(dāng)前系列數(shù)據(jù)已經(jīng)循環(huán)完
          invalidData = 0;
          seriesIndex = (seriesIndex + 1) % seriesLen;
          if (seriesIndex === options.seriesIndex) {
          invalidSeries = 0;
          }
          }

          first = false;
          }

          showTip();
          timeTicket = setInterval(showTip, options.interval);
          }

          // 關(guān)閉輪播
          function stopAutoShow() {
          if (timeTicket) {
          clearInterval(timeTicket);
          timeTicket = 0;

          if (chartType === 'pie' || chartType === 'radar' || chartType === 'map') {
          cancelHighlight();
          }
          }
          }

          let zRender = chart.getZr();

          function zRenderMouseMove(param) {
          if (param.event) {
          // 阻止canvas上的鼠標(biāo)移動(dòng)事件冒泡
          // param.event.cancelBubble = true;
          }
          stopAutoShow();
          }

          // 離開echarts圖時(shí)恢復(fù)自動(dòng)輪播
          function zRenderGlobalOut() {
          // console.log("移出了")
          // console.log(timeTicket)
          if (!timeTicket) {
          autoShowTip();
          }
          }

          // 鼠標(biāo)在echarts圖上時(shí)停止輪播
          chart.on('mousemove', stopAutoShow);
          zRender.on('mousemove', zRenderMouseMove);
          zRender.on('globalout', zRenderGlobalOut);

          autoShowTip();

          return {
          clearLoop: clearLoop
          };
          }


          getFirst() 方法是 List 接口沒有的方法。它可能是某個(gè)特定實(shí)現(xiàn)類的方法,比如 LinkedList 或者 ArrayList 的方法,但是在標(biāo)準(zhǔn)的 List 接口中并不存在。

          如果你希望獲取列表中的第一個(gè)元素,可以使用 get(0) 方法,它會(huì)返回列表中索引為 0 的元素。這是通用的方法,可以用于任何實(shí)現(xiàn)了 List 接口的類。

          問題出在List接口上,它沒有getFirst()方法。如果你想獲取列表中的第一個(gè)元素,可以使用get(0)方法來實(shí)現(xiàn)。所以,你需要將下面這行代碼:

             

          AppProductSkuSaveReqVO appProductSkuSaveReqVO = updateReqVO.getSkus().getFirst();

          修改為:

             

          AppProductSkuSaveReqVO appProductSkuSaveReqVO = updateReqVO.getSkus().get(0);

          這樣就可以正確獲取列表中的第一個(gè)元素了。

             

          StringBuilder url = new StringBuilder()
          .append("https://api.weixin.qq.com/sns/jscode2session")
          .append("?appid=").append(appid)
          .append("&secret=").append(secret)
          .append("&js_code=").append(code)
          .append("&grant_type=authorization_code");

             

          var mycharts = echarts.init(this.$refs.echartsMap);
          var option ={};
          mycharts.setOption(option);

          var index = 0; //播放所在下標(biāo)
          this.mTime = setInterval(function() {
          mycharts.dispatchAction({
          type: 'showTip',
          seriesIndex: 0,
          dataIndex: index
          });
          index++;
          if(index >= option.series[0].data.length) {
          index = 0;
          }
          }, 6000);
             

          let index = 0; //播放所在下標(biāo)
          const mTime = setInterval(function() {
          mycharts.dispatchAction({
          type: 'showTip',
          seriesIndex: 0,
          dataIndex: index
          });
          index++;
          if(index >= option.value.series[0].data.length) {
          index = 0;
          }
          }, 6000);

          發(fā)起過一次訂閱申請之后用戶在設(shè)置中不允許通知,則無法彈出申請對話框: 

          后端獲取Token:

             

          private TokenObj getAccessToken() {
          Map<String, Object> params = new HashMap<>();
          params.put("grant_type", "client_credential");
          params.put("appid", appletsConfig.getWxAppId());
          params.put("secret", appletsConfig.getWxAppSecret());
          String wxAppletDomain = "https://api.weixin.qq.com/cgi-bin/token";
          String res = HttpClientUtils.get(HttpClientUtils.getDefaultPoolClient(),wxAppletDomain,params);
          TokenObj obj = null;
          if (StringUtils.hasText(res)) {
          obj = JSON.parseObject(res, TokenObj.class);
          }
          if (obj == null || StringUtils.isEmpty(obj.getAccess_token())) {
          throw new BusinessException("獲取token失敗:" + res);
          }
          return obj;
          }

             

          public String sendMsg(HttpServletRequest request){
          //請求 微信接口 獲取 accessToken
          String accessToken = getAccessToken();
          String openid = "接收消息的微信用戶的openId";
          String templateId = "微信訂閱消息模板";
          String page = "點(diǎn)擊消息的跳轉(zhuǎn)路徑";
          // 構(gòu)建訂閱消息內(nèi)容的JSON對象
          // 構(gòu)建訂閱消息內(nèi)容的JSON對象
          JSONObject messageData = new JSONObject();
          messageData.put("name2", createDataItem("張三"));
          messageData.put("name3", createDataItem("李四"));
          messageData.put("time4", createDataItem("2023-06-30"));
          // 將訂閱消息內(nèi)容轉(zhuǎn)換為JSON字符串
          String jsonData = messageData.toJSONString();
          pushMessage(accessToken,openid,templateId,page,jsonData);
          return "success";
          }
          private static Map<String, Object> createDataItem(String value) {
          Map<String, Object> item = new HashMap<>();
          item.put("value", value);
          return item;
          }

          public void pushMessage(String accessToken, String openId, String templateId, String page, Map<String, Map<String,Object>> jsonData) {
          try {
          Map<String, Object> params=new HashMap<>();
          params.put("touser",openId);
          params.put("data", jsonData);
          if(StringUtils.hasText(page)){
          params.put("page",page);
          }
          params.put("miniprogram_state", "trial");
          params.put("template_id",templateId);
          String pushUrl = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s";
          String result= HttpClientUtils.post(HttpClientUtils.getDefaultPoolClient(), String.format(pushUrl, accessToken), params);
          logger.info("【微信推送】微信推送返回結(jié)果 ,{}",result);
          } catch (Exception e) {
          logger.error("【微信推送】微信推送請求失敗", e);
          }
          }

             

          js

          @RestController
          public class SendWxMessage {
          /*
          * 發(fā)送訂閱消息
          * */
          @GetMapping("/pushOneUser")
          public String pushOneUser() {
          return push("o3DoL0WEdzxxx96gbjM");
          }
          public String push(String openid) {
          RestTemplate restTemplate = new RestTemplate();
          //這里簡單起見我們每次都獲取最新的access_token(時(shí)間開發(fā)中,應(yīng)該在access_token快過期時(shí)再重新獲?。?/span>
          String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + getAccessToken();
          //拼接推送的模版
          WxMssVo wxMssVo = new WxMssVo();
          wxMssVo.setTouser(openid);//用戶的openid(要發(fā)送給那個(gè)用戶,通常這里應(yīng)該動(dòng)態(tài)傳進(jìn)來的)
          wxMssVo.setTemplate_id("CFeSWarQL-MPyBzTU");//訂閱消息模板id
          wxMssVo.setPage("pages/index/index");
          Map<String, TemplateData> m = new HashMap<>(3);
          m.put("thing1", new TemplateData("小程序1"));
          m.put("thing6", new TemplateData("小程序2"));
          m.put("thing7", new TemplateData("小程序3"));
          wxMssVo.setData(m);
          ResponseEntity<String> responseEntity =
          restTemplate.postForEntity(url, wxMssVo, String.class);
          return responseEntity.getBody();
          }
          @GetMapping("/getAccessToken")
          public String getAccessToken() {
          RestTemplate restTemplate = new RestTemplate();
          Map<String, String> params = new HashMap<>();
          params.put("APPID", "wx7c54942sssssd8"); //
          params.put("APPSECRET", "5873a729csxssssd49"); //
          ResponseEntity<String> responseEntity = restTemplate.getForEntity(
          "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APPID}&secret={APPSECRET}", String.class, params);
          String body = responseEntity.getBody();
          JSONObject object = JSON.parseObject(body);
          String Access_Token = object.getString("access_token");
          String expires_in = object.getString("expires_in");
          System.out.println("有效時(shí)長expires_in:" + expires_in);
          return Access_Token;
          }
          }

          發(fā)送訂閱消息三步走

          • 1,拿到用戶的openid

          • 2,獲取access_token

          • 3,調(diào)用小程序消息推送的接口

          使用Vite

          如果你的項(xiàng)目是使用Vite創(chuàng)建的,你的build.sh腳本可以修改為:

             

          bashCopy code
          echo "===打包文件==="
          # 設(shè)置環(huán)境模式
          export VITE_APP_BASE_URL=your_production_url
             

          echo "===打包文件===" # 設(shè)置環(huán)境變量
          export NODE_ENV=production
          yarn build echo "===傳輸文件==="
          1. Kafka:優(yōu)化用于高吞吐量消息傳輸,尤其在消息較小時(shí)表現(xiàn)出色。

          2. MySQL:作為關(guān)系型數(shù)據(jù)庫,適合復(fù)雜查詢,但高寫負(fù)載或復(fù)雜事務(wù)可能影響性能。

          3. MongoDB:作為NoSQL文檔數(shù)據(jù)庫,優(yōu)于處理大量讀寫操作,但取決于數(shù)據(jù)模型和索引。

          4. Elasticsearch:搜索和分析工作負(fù)載優(yōu)化,但受限于索引和查詢優(yōu)化。

          數(shù)據(jù)庫類型 吞吐量參考值(每秒操作數(shù)) 影響因素
          Kafka 數(shù)十萬到上百萬消息 消息大小、網(wǎng)絡(luò)帶寬、磁盤I/O、分區(qū)策略
          MySQL 數(shù)百到數(shù)千事務(wù) 查詢優(yōu)化、索引、數(shù)據(jù)模型、硬件資源
          MongoDB 數(shù)百到數(shù)千讀寫操作 文檔設(shè)計(jì)、索引、查詢模式、服務(wù)器配置
          Elasticsearch 數(shù)百到數(shù)千查詢和索引操作 索引結(jié)構(gòu)、查詢類型、數(shù)據(jù)量、硬件資源

          Kafka:在良好的硬件和網(wǎng)絡(luò)條件下,單機(jī)Kafka可以處理每秒數(shù)十萬到上百萬消息的吞吐量,尤其在消息大小較?。◣装僮止?jié)到幾KB)的情況下。

          MySQL:對于MySQL,一個(gè)常見的參考吞吐量是每秒幾百到幾千個(gè)事務(wù),但這極大地取決于事務(wù)的復(fù)雜性和數(shù)據(jù)庫的優(yōu)化。

          數(shù)據(jù)庫和消息隊(duì)列系統(tǒng)(如Kafka、MySQL、MongoDB、Elasticsearch)的單機(jī)吞吐量受多種因素影響,因此很難給出具體的數(shù)值。實(shí)際的吞吐量取決于硬件配置、網(wǎng)絡(luò)環(huán)境、數(shù)據(jù)模型、查詢類型以及系統(tǒng)的配置和優(yōu)化。以下是一些影響各系統(tǒng)吞吐量的關(guān)鍵因素以及如何評估各自的性能:

          1. Kafka

            • Kafka設(shè)計(jì)用于處理高吞吐量的數(shù)據(jù)流,其性能受制于網(wǎng)絡(luò)帶寬、磁盤I/O以及分區(qū)策略。

            • Kafka吞吐量的評估通??紤]消息大小和生產(chǎn)者/消費(fèi)者的數(shù)量。

          2. MySQL

            • 作為關(guān)系型數(shù)據(jù)庫,MySQL的性能受到查詢優(yōu)化、索引、數(shù)據(jù)模型和硬件資源(如CPU、內(nèi)存、磁盤I/O)的影響。

            • 評估MySQL性能時(shí),通??紤]每秒可以處理的事務(wù)數(shù)(TPS)和查詢響應(yīng)時(shí)間。

          3. MongoDB

            • MongoDB是一個(gè)文檔型數(shù)據(jù)庫,其性能受到文檔設(shè)計(jì)、索引、查詢模式和服務(wù)器配置的影響。

            • MongoDB吞吐量的評估可以考慮每秒讀寫操作的數(shù)量。

          4. Elasticsearch

            • Elasticsearch是一個(gè)搜索引擎和分析平臺(tái),其性能取決于索引結(jié)構(gòu)、查詢類型、數(shù)據(jù)量和硬件資源。

            • Elasticsearch的性能通常以每秒查詢數(shù)和索引操作來衡量。

          對于其他數(shù)據(jù)庫(如PostgreSQL、Redis、Cassandra等),同樣的原則適用。它們的性能取決于特定的使用場景和系統(tǒng)配置。

          要準(zhǔn)確地了解這些系統(tǒng)的吞吐量,最佳做法是在特定的環(huán)境下進(jìn)行基準(zhǔn)測試。基準(zhǔn)測試應(yīng)模擬真實(shí)的工作負(fù)載和數(shù)據(jù)模式,以獲得有意義的性能指標(biāo)。此外,性能調(diào)優(yōu)(如查詢優(yōu)化、索引調(diào)整、合理的分區(qū)和復(fù)制策略)也是提高系統(tǒng)吞吐量的重要方面。

          加群聯(lián)系作者vx:xiaoda0423

          倉庫地址:https://github.com/webVueBlog/JavaGuideInterview

          瀏覽 46
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码日日爽天天干 | 欧美性爱在线播放 | 99久久99久久精品免费看蜜桃 | 波多野结衣av在线免费观看 | 黄片在线免费网站 |