Nacos深入淺出(二)


如果你的服務已經能正常跑起來,個人建議可以先感受下nacos的魅力,也就是怎么使用吧

直接上代碼

@Controller
@NacosPropertySource(dataId = "springboot2-nacos-config", autoRefreshed = true)
public class HealthController {


    @NacosValue(value = "${nacos.test.propertie:123}", autoRefreshed = true)
    private String testProperties;

    @ResponseBody
    @GetMapping("/nacos/test")
    public String test(){
        return testProperties;
    }

    @ResponseBody
    @RequestMapping(value = "/readiness", method = RequestMethod.GET)
    public Object readiness(HttpServletRequest request) {
        boolean isConfigReadiness = true;
        boolean isNamingReadiness = false;

        if (isConfigReadiness && isNamingReadiness) {
            return ResponseEntity.ok().body("OK");
        }

        if (!isConfigReadiness && !isNamingReadiness) {
            return ResponseEntity.status(500).body("Config and Naming are not in readiness");
        }

        if (!isConfigReadiness) {
            return ResponseEntity.status(500).body("Config is not in readiness");
        }

        return ResponseEntity.status(500).body("Naming is not in readiness");
    }
}

我們直接用postman請求下,直接返回結果了,

我們在nacos中的相關配置如下:

這樣我就很方便的把我們需要的值取過來了,而且不是通過DB,cache方式獲取,而是在遠程nacos中配置,我們能夠實時獲取的到;

那么問題就來了,nacos是怎么做到的呢,當然nacos的功能遠不止於此;

我們就根據這個作為一個最直觀的入口,跟下代碼:

在nacos中發布的操作

 

 找代碼v1/cs/configs,當然再試的時候可以找V1/CS

Constants.java
    
public static final String BASE_PATH = "/v1/cs";

public static final String CONFIG_CONTROLLER_PATH = BASE_PATH + "/configs";

 

 

/**
     * 增加或更新非聚合數據。
     *
     * @throws NacosException
     */
    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public Boolean publishConfig(HttpServletRequest request, HttpServletResponse response,
                                 @RequestParam("dataId") String dataId, @RequestParam("group") String group,
                                 @RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY)
                                     String tenant,
                                 @RequestParam("content") String content,
                                 @RequestParam(value = "tag", required = false) String tag,
                                 @RequestParam(value = "appName", required = false) String appName,
                                 @RequestParam(value = "src_user", required = false) String srcUser,
                                 @RequestParam(value = "config_tags", required = false) String configTags,
                                 @RequestParam(value = "desc", required = false) String desc,
                                 @RequestParam(value = "use", required = false) String use,
                                 @RequestParam(value = "effect", required = false) String effect,
                                 @RequestParam(value = "type", required = false) String type,
                                 @RequestParam(value = "schema", required = false) String schema)
        throws NacosException {
        final String srcIp = RequestUtil.getRemoteIp(request);
        String requestIpApp = RequestUtil.getAppName(request);
// 參數校驗 ParamUtils.checkParam(dataId, group,
"datumId", content); ParamUtils.checkParam(tag); Map<String, Object> configAdvanceInfo = new HashMap<String, Object>(10); if (configTags != null) { configAdvanceInfo.put("config_tags", configTags); } if (desc != null) { configAdvanceInfo.put("desc", desc); } if (use != null) { configAdvanceInfo.put("use", use); } if (effect != null) { configAdvanceInfo.put("effect", effect); } if (type != null) { configAdvanceInfo.put("type", type); } if (schema != null) { configAdvanceInfo.put("schema", schema); } ParamUtils.checkParam(configAdvanceInfo); // 白名單 if (AggrWhitelist.isAggrDataId(dataId)) { log.warn("[aggr-conflict] {} attemp to publish single data, {}, {}", RequestUtil.getRemoteIp(request), dataId, group); throw new NacosException(NacosException.NO_RIGHT, "dataId:" + dataId + " is aggr"); } final Timestamp time = TimeUtils.getCurrentTime(); String betaIps = request.getHeader("betaIps"); ConfigInfo configInfo = new ConfigInfo(dataId, group, tenant, appName, content);
if (StringUtils.isBlank(betaIps)) { if (StringUtils.isBlank(tag)) {
// 插入或者更新 persistService.insertOrUpdate(srcIp, srcUser, configInfo, time, configAdvanceInfo,
false);
// 發布事件 EventDispatcher.fireEvent(
new ConfigDataChangeEvent(false, dataId, group, tenant, time.getTime())); } else { persistService.insertOrUpdateTag(configInfo, tag, srcIp, srcUser, time, false); EventDispatcher.fireEvent(new ConfigDataChangeEvent(false, dataId, group, tenant, tag, time.getTime())); } } else { // beta publish persistService.insertOrUpdateBeta(configInfo, betaIps, srcIp, srcUser, time, false); EventDispatcher.fireEvent(new ConfigDataChangeEvent(true, dataId, group, tenant, time.getTime())); } ConfigTraceService.logPersistenceEvent(dataId, group, tenant, requestIpApp, time.getTime(), LOCAL_IP, ConfigTraceService.PERSISTENCE_EVENT_PUB, content); return true; }

就從這個controller去做分析,其實核心一下就能看出來就是一個insertOrUpdate,一個fireEvent;

insertorUpdate這個nacos沒有用mybatis、hibernate這些ORM框架(減少依賴耦合吧);

下方高能!!!!!!!!!!!!!!!!!!!!!!!!!!

直接用jdbcTemblate就行數據插入,大家在進行debug的時候注意下,jdbcTemplate中有個事務超時時間,

nacos中有兩種模板,

 private JdbcTemplate jt;
 private TransactionTemplate tjt;

這個他都設置了默認超時時間(還有另外一個地方一個3秒一個5秒,建議大家在DEBUG的時候把這個時間調大一點,300,,500^_^)

BasicDataSourceServiceImpl.java
 @PostConstruct
    public void init() {
        queryTimeout = NumberUtils.toInt(System.getProperty("QUERYTIMEOUT"), 300);
        jt = new JdbcTemplate();
        /**
         *  設置最大記錄數,防止內存膨脹
         */
        jt.setMaxRows(50000);
        jt.setQueryTimeout(queryTimeout);

        testMasterJT = new JdbcTemplate();
        testMasterJT.setQueryTimeout(queryTimeout);

        testMasterWritableJT = new JdbcTemplate();
        /**
         * 防止login接口因為主庫不可用而rt太長
         */
        testMasterWritableJT.setQueryTimeout(1);
        /**
         * 數據庫健康檢測
         */
        testJTList = new ArrayList<JdbcTemplate>();
        isHealthList = new ArrayList<Boolean>();

        tm = new DataSourceTransactionManager();
        tjt = new TransactionTemplate(tm);
        /**
         *  事務的超時時間需要與普通操作區分開
         */
        tjt.setTimeout(TRANSACTION_QUERY_TIMEOUT);
        if (!STANDALONE_MODE || PropertyUtil.isStandaloneUseMysql()) {
            try {
                reload();
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(DB_LOAD_ERROR_MSG);
            }

            TimerTaskService.scheduleWithFixedDelay(new SelectMasterTask(), 10, 10,
                TimeUnit.SECONDS);
            TimerTaskService.scheduleWithFixedDelay(new CheckDBHealthTask(), 10, 10,
                TimeUnit.SECONDS);
        }
    }

 

看下config_info的表結構,他這邊判斷更新的依據就是直接插入,

捕獲唯一索引的異常,data_id+group+tenant重復的話就會拋出異常,捕獲這個異常進行更新操作!

表結構

persistService.insertOrUpdate
 /**
     * 寫入主表,插入或更新
     */
    public void insertOrUpdate(String srcIp, String srcUser, ConfigInfo configInfo, Timestamp time,
                               Map<String, Object> configAdvanceInfo, boolean notify) {
        try {
            addConfigInfo(srcIp, srcUser, configInfo, time, configAdvanceInfo, notify);
        } catch (DataIntegrityViolationException ive) { // 唯一性約束沖突
            updateConfigInfo(configInfo, srcIp, srcUser, time, configAdvanceInfo, notify);
        }
    }

后面就是最核心的地方了

EventDispatcher.fireEvent(new ConfigDataChangeEvent(false, dataId, group, tenant, time.getTime()));

通過event的dispatcher,進行相應的操作,這個就是觀察者模式的體現,Apollo中也有類似的操作;

篇幅過長,這里就不再追加了,看下一篇吧^_^

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM