richcms可以支持电脑版本和移动版两个站点,比如常见的:www.baidu.com和m.baidu.com两个站点,richcms作为一个cms系统,需要同步数据缓存,此文章详细说明如何实现。

从部署角度来说,www和m是两个独立的进程,甚至可以跑在不同的服务器上(连接同样的mysql和redis)。他们之间的缓存同步操作,使用内部的http api来完成。

处理机制一:

判断主站点(www)是否需要API操作m的缓存,如果有需要,写入缓存清理队列(使用mysql来完成)。

// KeyToCacheQueue 把key存储到队列中
//
//	打开条件:有移动站点,而且当前站点是主站点
func KeyToCacheQueue(key string) {
	conf, _ := new(ConfigCache).GetConfig()
	//有配置移动点域名,而且是主站点,移动站点参数关闭时
	if conf.MobileDomain != "" && constname.IsPrimarySite() && !constname.IsSecondSite() {
		err := model.CreateCacheQueue(key)
		if err != nil {
			logx.Errorf("Create cache queue err: %v", err)
		}
	}
}

清理缓存的API实现:

type Result struct {
	Keys []string `json:"keys"`
}

// CacheRemove 清理cache的api
func CacheRemove(c *gow.Context) {
	key := c.GetString("key")
	if key == "" {
		c.DataJSON(1, "缺少key")
		return
	}
	key, _ = url.QueryUnescape(key)

	cacheKeys, err := cache.MC.GetKeys()
	if err != nil {
		c.DataJSON(1, fmt.Sprintf("获取缓存错误:%v", err))
		return
	}

	keys := make([]string, 0)
	for _, v := range cacheKeys {
		if strings.Contains(v, key) {
			_ = cache.MC.RemoveCache(v)
			keys = append(keys, v)
		}
	}
	c.DataJSON(Result{
		Keys: keys,
	})
}

缓存清理操作(通过缓存定时任务)

func (m *CacheTask) clear(item *model.CacheQueue, addr, token string) error {
	addr = fmt.Sprintf("%s?key=%s", addr, url.QueryEscape(item.CacheKey))
	return m.httpReq(addr, token)
}

func (m *CacheTask) httpReq(addr, token string) error {
	req, err := http.NewRequest("GET", addr, nil)
	if err != nil {
		return err
	}
	req.Header.Add("token", token)
	client := &http.Client{
		Timeout: 5 * time.Second,
	}
	resp, err1 := client.Do(req)
	if err1 != nil {
		return err1
	}
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body)

	body, err2 := io.ReadAll(resp.Body)
	if err2 != nil {
		return err2
	}
	logx.Infof("缓存清理返回值: %s", string(body))
	return nil
}