docker-hiveでHive JDBCを試す

Dockerを使ってHive JDBCを試したときのメモ。

準備

ソースコード

build.gradle

plugins {
    id 'java'
    id 'application'
}

group 'com.example'
version '1.0-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_11

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.apache.hive:hive-jdbc:2.3.6'
}

mainClassName = 'com.example.Main'

Main.java

package com.example;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class Main {

    public static void main(String[] args) throws Exception {
        Connection con = DriverManager.getConnection("jdbc:hive2://localhost:10000/default");
        Statement stmt = con.createStatement();
        try (con; stmt) {
            stmt.execute("CREATE TABLE IF NOT EXISTS table1 (id int, name string)");

            stmt.executeUpdate("INSERT INTO table1 VALUES(1, 'user1')");
            stmt.executeUpdate("INSERT INTO table1 VALUES(2, 'user2')");
            stmt.executeUpdate("INSERT INTO table1 VALUES(3, 'user3')");

            ResultSet res = stmt.executeQuery("SELECT * FROM table1");
            while (res.next()) {
                System.out.println(res.getInt(1) + ", " + res.getString(2));
            }
        }
    }
}

docker-hive

今回はHive 2.3を試すため、2.3.2-postgresql-metastoreのブランチをダウンロードする。

% git clone https://github.com/big-data-europe/docker-hive -b 2.3.2-postgresql-metastore 

https://github.com/big-data-europe/docker-hive

確認

HiveServer2を起動後、デモアプリを起動する。

% cd docker-hive
% docker-compose up -d

Docker ComposeでMongoDBのReplica Setを使う

Docker ComposeでMongoDBのReplica Setを試したときのメモ。

準備

docker-compose.yml

version: '3'
services:
  mongo01:
    image: mongo:4.4
    command: mongod --replSet rs1 --bind_ip_all
    ports:
      - "27017:27017"
  mongo02:
    image: mongo:4.4
    command: mongod --replSet rs1 --bind_ip_all
    ports:
      - "27018:27017"
  mongo03:
    image: mongo:4.4
    command: mongod --replSet rs1 --bind_ip_all
    ports:
      - "27019:27017"

手順

ホスト(Mac)の/etc/hostsに以下を登録する。

127.0.0.1 mongo01 mongo02 mongo03

Docker ComposeでMongoDBを起動する。

% docker-compose up -d

Replica Setを設定する。

% mongo --port 27017

> rs.initiate({
  _id: "rs1",
  members: [
    {_id: 0, host: "mongo01:27017"},
    {_id: 1, host: "mongo02:27017"},
    {_id: 2, host: "mongo03:27017"}
  ]
})

動作確認

% mongo --host rs1/127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019
MongoDB shell version v4.4.3
connecting to: mongodb://127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019/?compressors=disabled&gssapiServiceName=mongodb&replicaSet=rs1

参考

Springfox SwaggerでCSRF tokenを送信する

Spring SecurityのCSRFを有効にしている状態で、SpringfoxのSwagger上でPOST等のメソッドを実行したいときのメモ。
そのままでは試せないが、以下のようなCSRF tokenがを返すエンドポイントを作れば、POST等のメソッドも実行できる。

ソースコード

plugins {
    id 'org.springframework.boot' version '2.4.5'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_11

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'io.springfox:springfox-boot-starter:3.0.0'
    ...
}
@Profile("dev")
@RestController
public class CsrfController {
    @GetMapping("/csrf")
    public CsrfToken csrf(CsrfToken token) {
        return token;
    }
}

springfox 3.0.0からはこの設定が必要。

@Bean
public SecurityConfiguration securityConfiguration() {
    return SecurityConfigurationBuilder.builder()
                                       .enableCsrfSupport(true)
                                       .build();
}

参考

Spring Boot ActuatorのHTTP Client MetricsのURI tagが上限に達した

Spring Boot ActuatorとMicrometerを使っているときに、こんなwarnログが出たときのメモ。

WARN o.s.b.a.a.m.OnlyOnceLoggingDenyMeterFilter -
Reached the maximum number of URI tags for 'http.client.requests'. Are you using 'uriVariables' on RestTemplate calls?

これは、RestTemplateのmetrics(http.client.requests)のURIタグがmanagement.web.client.max-uri-tags(defaultは100)に達したため。
warnログで指摘されている通り、RestTemplateのuriVariablesを使っていなかったので、クエリパラメータごとにURIタグが作られていた。

修正前

Spring Boot: 2.1.0

String uri = UriComponentsBuilder.fromHttpUrl("http://md5.jsontest.com")
                                 .queryParam("text", text)
                                 .toUriString();
restTemplate.getForObject(uri, Map.class);

Spring Boot ActuatorのPrometheusのエンドポイントを確認すると、URLクエリパラメータごとにURIタグが作られていた。

http_client_requests_seconds_count{clientName="md5.jsontest.com",method="GET",status="200",uri="/http://md5.jsontest.com?text=aaa",} 1.0
http_client_requests_seconds_count{clientName="md5.jsontest.com",method="GET",status="200",uri="/http://md5.jsontest.com?text=bbb",} 1.0
http_client_requests_seconds_count{clientName="md5.jsontest.com",method="GET",status="200",uri="/http://md5.jsontest.com?text=ccc",} 1.0

修正後

RestTemplateを呼び出すときに、uriVariablesを使うように変更。

String uri = UriComponentsBuilder.fromHttpUrl("http://md5.jsontest.com")
                                 .queryParam("text", "{text}")
                                 .build(false)
                                 .toUriString();
restTemplate.getForObject(uri, Map.class, text);

URIタグはtemplate形式になったので、一つになった。

http_client_requests_seconds_count{clientName="md5.jsontest.com",method="GET",status="200",uri="/http://md5.jsontest.com?text={text}",} 3.0

参考

Spring BootでCaffeineのcacheごとにexpireAfterAccessを指定する

Spring BootのcacheにCaffeineを使っている場合で、cacheごとにmaximumSizeやexpireAfterAccessを指定したいときのメモ。

プロパティのspring.cache.caffeine.specにはcacheごとにexpireAfterAccessなどを設定できないので、SimpleCacheManagerを使うしかなさそう。

@Bean
public SimpleCacheManager cacheManager() {
    SimpleCacheManager cacheManager = new SimpleCacheManager();
    CaffeineCache cache1 =
                new CaffeineCache("cache1",
                                  Caffeine.newBuilder()
                                          .maximumSize(100)
                                          .expireAfterAccess(10, TimeUnit.MINUTES)
                                          .build());
    CaffeineCache cache2 =
                new CaffeineCache("cache2",
                                  Caffeine.newBuilder()
                                          .maximumSize(200)
                                          .expireAfterAccess(20, TimeUnit.MINUTES)
                                          .build());
    cacheManager.setCaches(List.of(cache1, cache2));
    return cacheManager;
}

参考

Spring DataとSpring Sessionで別々のRedisConnectionFactoryを使う

Spring Data RedisとSpring Session Data Redisで、RedisConnectionFactoryを分けたいときのメモ。
Spring Sessionで使うRedisConnectionFactoryに@SpringSessionRedisConnectionFactoryを付けると、Spring Sessionはこちらを使うようになる。

Spring Boot: 2.0.5

  @Bean
  @Primary
  public LettuceConnectionFactory redisConnectionFactory() {
    LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
    connectionFactory.setDatabase(0);
    return connectionFactory;
  }

  @Bean
  @SpringSessionRedisConnectionFactory
  public LettuceConnectionFactory springSessionRedisConnectionFactory() {
    LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
    connectionFactory.setDatabase(1);
    return connectionFactory;
  } 

参考