服務(wù)端集群搭建

​ 當單個服務(wù)端節點無法滿足當前業務(wù)吞吐量或者業務(wù)要求時,服務(wù)端将會采用(yòng)集群方式對外提供服務(wù)。URule屬于Web應用(yòng),所以URule服務(wù)端的集群搭建也和傳統的Web應用(yòng)一緻,有(yǒu)一個負載+n個服務(wù)端節點。

接下來我們将提供一種比較簡便的Redis session共享的方式搭建,并借助nginx實現負載均衡。

1. 服務(wù)端集群

img

2.在集群環境上實現Session共享

關于session共享的方式有(yǒu)多(duō)種,常見的有(yǒu):

(1)通過nginx的ip_hash,根據ip将請求分(fēn)配到對應的服務(wù)器,相當于開啓了會話保持功能(néng)

(2)基于關系型數據庫存儲

(3)基于cookie存儲

(4)服務(wù)器内置的session複制域

(5)基于nosql(memcache、redis都可(kě)以)

實現原理(lǐ)也比較簡單,在所有(yǒu)的請求之前配置一過濾器,在請求之前操作(zuò)session,其實spring-session中(zhōng)真正起作(zuò)用(yòng)的session過濾器是SessionRepositoryFilter。而spring-session集成了redis與mongodb,若啓用(yòng)redis方式隻需要稍加配置即可(kě)實現。

2.1 集成Redis實現Session共享

(1)集成spring-session-data-redis

 <!-- 引入redis的集成 -->
<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
        <exclusions>
            <exclusion>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
            </exclusion>
            <exclusion>
                <artifactId>lettuce-core</artifactId>
                <groupId>io.lettuce</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.6.3</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
<!-- 引入 session與redis的集成:若不用(yòng)redis請去掉本依賴 -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

(2)配置類添加(非必須)

@Configuration
//不設置默認30分(fēn)鍾
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
public class RedisSessionConfig {

    @Bean("redisTemplate")
    @ConfigurationProperties(prefix="spring.redis")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);

        //将key的序列化設置成StringRedisSerializer
        StringRedisSerializer keySerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(keySerializer);
        redisTemplate.setHashKeySerializer(keySerializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

}

@EnableRedisHttpSession:開啓Session共享功能(néng)。使用(yòng)此注解之後Session調用(yòng)會自動通過Redis存儲和獲取。另外,想要達到Session共享的目的,在其他(tā)的系統上隻需要做同樣的配置即可(kě)。 其中(zhōng)maxInactiveIntervalInSeconds參數是設置Session失效時間,在使用(yòng)Redis Session之後,原Spring Boot的server.session.timeout屬性不再生效。

(3)修改Session的儲存方式為(wèi)redis

# session的存儲方式配置為(wèi)redis
spring:
  session:
    store-type: redis

  redis:
    host: localhost
    port: 6379
    database: 1
    timeout: 10000
    jedis:
      pool:
        max-active: 50    # 連接池最大連接數(使用(yòng)負值表示沒有(yǒu)限制)
        max-wait: 5000    # 連接池中(zhōng)連接用(yòng)完時,新(xīn)的請求等待時間(毫秒(miǎo)),超過該時間抛出異常JedisConnectionException,(默認-1,負值表示沒有(yǒu)限制,不建議使用(yòng)默認值)
        max-idle: 10      # 連接池中(zhōng)的最大空閑連接,默認8
        min-idle: 2       # 連接池中(zhōng)的最小(xiǎo)空閑連接,默認0

2.2 nginx配置負載均衡示例

nginx的配置文(wén)件如下

upstream nginx-cluster{
        server localhost:8080;
        server localhost:8081;
    }

 server {
        listen       80;
        server_name  localhost;

        location / {
             proxy_pass http://nginx-cluster;
         }
 }

2.3 測試頁(yè)面

訪問nginx地址http://192.168.1.16:80/,會自動跳由到任一tomcat實例上,通過日志(zhì)可(kě)以發現上述nginx配置的分(fēn)發策略默認是輪詢

img

2.4 實現規則設計器中(zhōng)複制粘貼的多(duō)實例同步

@Service
public class SessionRedisClipboardStore implements ClipboardStore {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public void set(String key, String value) {
        String sessionkey = RequestHolder.getRequest().getSession().getId()+key;
        stringRedisTemplate.opsForValue().set(sessionkey,value);
        RequestHolder.getRequest().getSession().setAttribute(sessionkey, value);
    }

    @Override
    public String get(String key) {
        String sessionkey = RequestHolder.getRequest().getSession().getId()+key;
        String val = stringRedisTemplate.opsForValue().get(sessionkey);
        if(StringUtils.hasText(val)){
            return val;
        }
        return (String) RequestHolder.getRequest().getSession().getAttribute(sessionkey);
    }

    @Override
    public void remove(String key) {
        String sessionkey = RequestHolder.getRequest().getSession().getId()+key;

        stringRedisTemplate.delete(sessionkey);
        RequestHolder.getRequest().getSession().removeAttribute(sessionkey);
    }
}

3.知識包數據同步問題

重點說明:

  • 知識包在發布後被編譯成一個rete樹,RETE算法的核心是以‘内存空間換取執行時間’,故而發布後的知識包是直接存儲在jvm虛拟内存中(zhōng),那麽要解決的是各實例内存中(zhōng)知識包數據同步更新(xīn)問題
  • 解決這個問題參考文(wén)檔14.6.知識包多(duō)環境部署 · GitBook
  • 我們也可(kě)以自行實現PacketPublishListener接口,用(yòng)來攔截發布知識包操作(zuò),将狀态寫入到MQ中(zhōng)來通知其它實例自行加載最新(xīn)的知識包數據
  • 另外,知識包數量越多(duō)(體(tǐ)積越大),占用(yòng)的jvm内存空間也越大,那麽我們在生産(chǎn)環境上設置jvm堆内存大小(xiǎo)建議在4g以上

而事實上‘知識包集群環境下内存同步問題與上述session共享并無關聯’,session是由于多(duō)實例造成緩存不同步問題,而知識包是内存不同步造成的,内存比緩存性能(néng)更高。

3.1 多(duō)服務(wù)端集群同步

在集群環境下,由于服務(wù)端會有(yǒu)多(duō)個實例節點,各實例(jvm)之間是物(wù)理(lǐ)隔離的,那麽當在某一個實例上【發布/啓用(yòng)知識包新(xīn)版本】時,就需要立即同步到其它服務(wù)實例的jvm内存中(zhōng),我們可(kě)以在系統管理(lǐ)端中(zhōng)維護集群實例信息來解決這一問題。

更多(duō)配置請查看文(wén)檔3.8.集群管理(lǐ) · GitBook,,都是在集群環境下内存同步引起的一系列問題。

  • 集群(8080,8081實例節點維護)

img

  • 知識包數據同步更新(xīn)

在知識包頁(yè)面,【查看當前已發布的知識包】點擊啓用(yòng)後,利用(yòng)http rpc通知各實例從數據庫加載最新(xīn)的知識包數據到jvm内存中(zhōng),會彈出窗口(若事先沒有(yǒu)配置集群節點數據,那就不會彈出如下窗口)自動顯示同步結果,如下图所示:

img

在上述2個tomcat的控制台可(kě)以看到日志(zhì) Successfully reload file packet package:310

3.2 多(duō)客戶端集群同步

(1)主動推送到客戶端

  • 客戶端地址維護

img

  • 查看當前已發布的知識包,在點擊【推送到客戶端】,如下操作(zuò)所示

img

  • 點擊上图“确定”按鈕後,彈出如下图所示界面(若沒有(yǒu)配置在客戶端地址,是不會顯示如下列表)

img

  • 在客戶端tomcat控制台能(néng)看到以下日志(zhì):

    Successfully receive the server side to pushed package:310(fc399b91f72240d89bc6d58fdd50538f)(1.0.3)

(2)被動拉取到客戶端

  • 在客戶端(消費方)通過sdk調用(yòng)知識包時,會從指定的服務(wù)器獲取最新(xīn)的知識包,實際上取決于urule.knowledgeUpdateCycle=?的值,即同步策略。

img

  • 用(yòng)postman調用(yòng)客戶端服務(wù)

img

  • 查看控制台,發現了每次運行知識包時都會從服務(wù)端加載最新(xīn)的

img

3.3 自定義同步方式

重寫PacketPublishListener.java接口,再結合消息中(zhōng)間件MQ來實現消息的發布和訂閱等。

todo

results matching ""

    No results matching ""