bloom 单实例多接口proxy+api 控制cache 测试

bloom 是支持多proxy 配置的(基于shared)但是对于多proxy 的处理有一个bug (处理map 一直获取的是第一个)参考https://github.com/valeriansaliou/bloom/issues/16,以前有写过简单的介绍
以下是一个多api 接口cache 的测试以及对于api cache 控制的试用

环境准备

 
fn map_shards() -> [Option<Uri>; MAX_SHARDS as usize] {
    // Notice: this array cannot be initialized using the short format, as hyper::Uri doesnt \
    //   implement the Copy trait, hence the ugly hardcoded initialization vector w/ Nones.
    let mut shards = [
        None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
        None,
    ];
    for shard in &APP_CONF.proxy.shard {
        // Shard number overflows?
        if shard.shard >= MAX_SHARDS {
            panic!("shard number overflows maximum of {} shards", MAX_SHARDS);
        }
        // Store this shard
        shards[shard.shard as usize] = Some(
            format!(
                "http://{}:{}",
               // 此处有bug
                APP_CONF.proxy.shard[0].host, APP_CONF.proxy.shard[0].port
            )
            .parse()
            .expect("could not build shard uri"),
        );
    }
    shards
}

为:

fn map_shards() -> [Option<Uri>; MAX_SHARDS as usize] {
    // Notice: this array cannot be initialized using the short format, as hyper::Uri doesnt \
    //   implement the Copy trait, hence the ugly hardcoded initialization vector w/ Nones.
    let mut shards = [
        None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
        None,
    ];
    for shard in &APP_CONF.proxy.shard {
        // Shard number overflows?
        if shard.shard >= MAX_SHARDS {
            panic!("shard number overflows maximum of {} shards", MAX_SHARDS);
        }
        // Store this shard
        shards[shard.shard as usize] = Some(
            format!(
                "http://{}:{}",
                shard.host, shard.port
            )
            .parse()
            .expect("could not build shard uri"),
        );
    }
    shards
}
 

相关修复的docker 镜像 dalongrong/bloom:v1.28.1

  • docker-compose 文件
version: "3"
services: 
  lb: 
    image: openresty/openresty:alpine
    volumes:
    - "./nginx-lb.conf:/usr/local/openresty/nginx/conf/nginx.conf"
    - "./access_test.log:/usr/local/openresty/nginx/logs/access_test.log"
    - "./access_test2.log:/usr/local/openresty/nginx/logs/access_test2.log"
    ports:
    - "80:80"
    - "8080:8080"
    - "8081:8081"
  bloom: 
    image: dalongrong/bloom:v1.28.1
    volumes: 
    - "./bloom.cfg:/etc/bloom.cfg"
    ports: 
    - "8811:8811"
    - "9001:8080"
  redis:
    image: redis
    ports:
    - "6379:6379"
  • bloom 配置
[server]
log_level = "debug"
inet = "0.0.0.0:8080"
[control]
inet = "0.0.0.0:8811"
tcp_timeout = 900
[proxy]
[[proxy.shard]]
shard = 1
host = "lb"
port = 8080
[[proxy.shard]]
shard = 2
host = "lb"
port = 8081
[cache]
ttl_default = 3600
executor_pool = 64
disable_read = false
disable_write = false
compress_body = false
[redis]
host = "redis"
port = 6379
database = 0
pool_size = 80
max_lifetime_seconds = 60
idle_timeout_seconds = 600
connection_timeout_seconds = 1
max_key_size = 256000
max_key_expiration = 2592000
  • openresty 配置以及基于openresty 的api
    为了方便测试同时基于openresty 的content_by_lua 以及header_filter_by_lua 处理api 以及添加api 控制需要的
    Bloom-Response-Buckets http header
 
worker_processes  1;
user root;  
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    lua_need_request_body on;
    #gzip  on; // should not use gzip 
    resolver 127.0.0.11 ipv6=off;     
    log_format graylog2_json escape=json '{ "timestamp": "$time_iso8601", '
                     '"remote_addr": "$remote_addr", '
                     '"body_bytes_sent": $body_bytes_sent, '
                     '"request_time": $request_time, '
                     '"response_status": $status, '
                     '"request": "$request", '
                     '"request_method": "$request_method", '
                     '"host": "$host",'
                     '"request_body":"$request_body",'
                     '"upstream_cache_status": "$upstream_cache_status",'
                     '"upstream_addr": "$upstream_addr",'
                     '"http_x_forwarded_for": "$http_x_forwarded_for",'
                     '"http_referrer": "$http_referer", '
                     '"http_user_agent": "$http_user_agent" }';
    log_format graylog2_json2 escape=json '{ "timestamp": "$time_iso8601", '
                     '"remote_addr": "$remote_addr", '
                     '"body_bytes_sent": $body_bytes_sent, '
                     '"request_time": $request_time, '
                     '"response_status": $status, '
                     '"request": "$request", '
                     '"request_method": "$request_method", '
                     '"host": "$host",'
                     '"request_body":"$request_body",'
                     '"upstream_cache_status": "$upstream_cache_status",'
                     '"upstream_addr": "$upstream_addr",'
                     '"http_x_forwarded_for": "$http_x_forwarded_for",'
                     '"http_referrer": "$http_referer", '
                     '"http_user_agent": "$http_user_agent" }';     
    real_ip_header     X-Forwarded-For;
    real_ip_recursive on;
    server {
        listen       80;
        charset utf-8;
        default_type text/html;
        location /userdemo {
            proxy_pass http://bloom:8080;
            proxy_set_header Bloom-Request-Shard 1;
            proxy_set_header Host $host;
            proxy_read_timeout 10000;
            proxy_send_timeout 10000;
            proxy_buffer_size 1M; 
            proxy_buffers 8 1M; 
            proxy_busy_buffers_size 1M; 
            proxy_temp_file_write_size 1M;
            proxy_set_header  X-Real-IP $remote_addr;
            proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header  X-Forwarded-Host $host;
        }
        location ^~ /appdemo {
            proxy_pass http://bloom:8080;
            proxy_set_header Bloom-Request-Shard 2;
            proxy_set_header Host $host;
            proxy_read_timeout 10000;
            proxy_send_timeout 10000;
            proxy_buffer_size 1M; 
            proxy_buffers 8 1M; 
            proxy_busy_buffers_size 1M; 
            proxy_temp_file_write_size 1M;
            proxy_set_header  X-Real-IP $remote_addr;
            proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header  X-Forwarded-Host $host;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    server {
        listen       8080;
        charset utf-8;
        default_type text/html;
        location /userdemo {
           access_log  /usr/local/openresty/nginx/logs/access_test.log  graylog2_json;
           content_by_lua_block {
               ngx.say("this is a demo")
           }
           header_filter_by_lua_block {
              ngx.header["Bloom-Response-Buckets"] = "user_id:10012"
           } 
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    server {
        listen       8081;
        charset utf-8;
        default_type text/html;
        location /appdemo {
           access_log  /usr/local/openresty/nginx/logs/access_test2.log  graylog2_json2;
           content_by_lua_block {
               ngx.say("appdemo")
           }
           header_filter_by_lua_block {
              ngx.header["Bloom-Response-Buckets"] = "login:10012"
           } 
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
} 
  • api 接口控制
    基于nodejs
    package.json
 
{
  "name": "api",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "bloom-control": "^1.2.1"
  },
  "scripts":{
    "start":"node app.js"
  }
}

app.js

var BloomControl = require("bloom-control").BloomControl;
var bloomControl = new BloomControl({
  host  : "127.0.0.1",  // Or '127.0.0.1' if you are still using IPv4
  port  : 8811,   // Default port is '8811'
  shard : 1       // Specify the Bloom shard to use, as \
                  //   a Bloom instance can host multiple cache shards, eg. for different API workers
}).connect({
  connected : function() {
    // Connected handler
    console.info("Bloom Control succeeded to connect to host.");
  },
  disconnected : function() {
    // Disconnected handler
    console.error("Bloom Control is now disconnected.");
  },
  timeout : function() {
    // Timeout handler
    console.error("Bloom Control connection timed out.");
  },
  retrying : function() {
    // Retry handler
    console.error("Trying to reconnect to Bloom Control...");
  },
  error : function(error) {
    // Failure handler
    console.error("Bloom Control failed to connect to host.", error);
  }
});
bloomControl.purgeBucket(`user_id:10012`, function(error) {
    // Handle purge errors here
    if (error) {
        console.log("some wrong")
    }
    else{
      console.log("ok")
    }
});

测试

  • 启动服务
docker-compose up -d
  • cache 测试

 

 


清理cache

 
cd api && yarn && yarn start

效果

 

 

说明

基于bloom高效,方便的cache 能力,我们可以方便的开发基于cache 的应用,提高应用的稳定性以及可控制性,以上是一个试用
大家可以自己扩展下,实现更加灵活的cache应用

参考代码

https://github.com/valeriansaliou/bloom
https://github.com/rongfengliang/bloom-api-test

posted on 2020-06-23 11:28  荣锋亮  阅读(305)  评论(0编辑  收藏  举报

导航