development

메모리에서만 PostgreSQL 실행

big-blog 2020. 9. 15. 18:54
반응형

메모리에서만 PostgreSQL 실행


내가 작성한 각 단위 테스트에 대해 메모리에서만 실행되는 작은 PostgreSQL 데이터베이스를 실행하고 싶습니다. 예를 들면 :

@Before
void setUp() {
    String port = runPostgresOnRandomPort();
    connectTo("postgres://localhost:"+port+"/in_memory_db");
    // ...
}

이상적으로는 단위 테스트에서 사용할 단일 postgres 실행 파일을 버전 제어에 체크인합니다.

과 같은 HSQL것이지만 postgres를 위해. 어떻게 할 수 있습니까?

그런 Postgres 버전을 구할 수 있었습니까? 디스크를 사용하지 않도록 어떻게 지시 할 수 있습니까?


Postgres에서는 불가능합니다. HSQLDB 또는 MySQL과 같은 in-process / in-memory 엔진을 제공하지 않습니다.

독립적 인 환경을 만들고 싶다면 Postgres 바이너리를 SVN에 넣을 수 있습니다 (단 하나의 실행 파일 이상입니다).

이 작업을 수행하기 전에 initdb 를 실행 하여 테스트 데이터베이스를 설정해야합니다. 이 작업은 배치 파일에서 또는 Runtime.exec ()를 사용하여 수행 할 수 있습니다. 그러나 initdb는 빠른 것이 아닙니다. 각 테스트에 대해 실행하고 싶지는 않을 것입니다. 그래도 테스트 스위트 전에 이것을 실행할 수 있습니다.

그러나 이렇게 할 수는 있지만 테스트를 실행하기 전에 테스트 데이터베이스를 다시 만드는 전용 Postgres 설치를 사용하는 것이 좋습니다.

템플릿 데이터베이스를 사용하여 테스트 데이터베이스를 다시 만들 수 있습니다. 템플릿 데이터베이스를 사용하면 매우 빠르게 생성 할 수 있습니다 ( 각 테스트 실행에 대해 initdb를 실행하는 것보다 훨씬 빠름).


( 메모리 내 PostgreSQL 사용에서 내 대답을 이동 하고 일반화) :

Pg in-process, in-memory를 실행할 수 없습니다.

테스트를 위해 메모리 내 Postgres 데이터베이스를 실행하는 방법을 알 수 없습니다. 가능할까요?

아니요, 불가능합니다. PostgreSQL은 C로 구현되고 플랫폼 코드로 컴파일됩니다. H2 또는 Derby와는 달리 jar일회용 인 메모리 DB로 로드하고 실행할 수 없습니다 .

C로 작성되고 플랫폼 코드로 컴파일되는 SQLite와 달리 PostgreSQL은 프로세스 내에서도로드 할 수 없습니다. 멀티 스레딩 아키텍처가 아닌 멀티 프로세싱이기 때문에 여러 프로세스 (연결 당 하나)가 필요합니다. 다중 처리 요구 사항 은 포스트 마스터를 독립 실행 형 프로세스로 시작 해야 함을 의미합니다 .

대신 : 연결 사전 구성

특정 호스트 이름 / 사용자 이름 / 암호가 작동 할 것으로 예상하는 테스트를 작성 하고 실행이 끝날 때 테스트 CREATE DATABASE가 일회용 데이터베이스 DROP DATABASE를 사용하도록하는 것이 좋습니다. 속성 파일, 빌드 대상 속성, 환경 변수 등에서 데이터베이스 연결 세부 정보를 가져옵니다.

그것은 당신이 이미 당신이 걱정하는 데이터베이스가 기존의 PostgreSQL 인스턴스를 사용하는 것이 안전 너무 오래 당신이 당신의 단위 테스트에 제공 한 사용자가 같이 하지 슈퍼 유저와 사용자 만 CREATEDB권한. 최악의 경우 다른 데이터베이스에서 성능 문제가 발생합니다. 이러한 이유로 테스트를 위해 완전히 격리 된 PostgreSQL 설치를 실행하는 것을 선호합니다.

대신 : 테스트를 위해 일회용 PostgreSQL 인스턴스 시작

또는 정말 열심이라면 테스트 하네스가 initdbpostgres바이너리를 찾고, initdb데이터베이스를 생성하기 위해 실행 하고,로 수정 pg_hba.conf하고 trust, postgres임의의 포트에서 시작하기 위해 실행 하고, 사용자를 생성하고, DB를 생성하고, 테스트를 실행할 수 있습니다. 여러 아키텍처에 대한 PostgreSQL 바이너리를 jar에 묶어 테스트를 실행하기 전에 현재 아키텍처에 대한 바이너리를 임시 디렉토리에 압축 해제 할 수도 있습니다.

개인적으로 그것은 피해야 할 큰 고통이라고 생각합니다. 테스트 DB를 구성하는 것이 더 쉽습니다. 그러나에서 include_dir지원 의 출현으로 조금 더 쉬워 졌습니다 postgresql.conf. 이제 한 줄만 추가 한 다음 나머지 모든 구성 파일을 작성할 수 있습니다.

PostgreSQL로 더 빠른 테스트

테스트 목적으로 PostgreSQL의 성능 안전하게 개선하는 방법에 대한 자세한 내용은 이전에이 주제에 대해 작성한 자세한 답변 : 빠른 테스트를 위해 PostgreSQL 최적화를 참조하십시오.

H2의 PostgreSQL 언어는 진정한 대체물이 아닙니다.

일부 사람들은 대신 PostgreSQL 언어 모드에서 H2 데이터베이스를 사용하여 테스트를 실행합니다. 그것은 테스트에 SQLite를 사용하고 프로덕션 배포에 PostgreSQL을 사용하는 Rails 사람들만큼이나 나쁘다고 생각합니다.

H2 supports some PostgreSQL extensions and emulates the PostgreSQL dialect. However, it's just that - an emulation. You'll find areas where H2 accepts a query but PostgreSQL doesn't, where behaviour differs, etc. You'll also find plenty of places where PostgreSQL supports doing something that H2 just can't - like window functions, at the time of writing.

If you understand the limitations of this approach and your database access is simple, H2 might be OK. But in that case you're probably a better candidate for an ORM that abstracts the database because you're not using its interesting features anyway - and in that case, you don't have to care about database compatibility as much anymore.

Tablespaces are not the answer!

Do not use a tablespace to create an "in-memory" database. Not only is it unnecessary as it won't help performance significantly anyway, but it's also a great way to disrupt access to any other you might care about in the same PostgreSQL install. The 9.4 documentation now contains the following warning:

WARNING

Even though located outside the main PostgreSQL data directory, tablespaces are an integral part of the database cluster and cannot be treated as an autonomous collection of data files. They are dependent on metadata contained in the main data directory, and therefore cannot be attached to a different database cluster or backed up individually. Similarly, if you lose a tablespace (file deletion, disk failure, etc), the database cluster might become unreadable or unable to start. Placing a tablespace on a temporary file system like a ramdisk risks the reliability of the entire cluster.

because I noticed too many people were doing this and running into trouble.

(If you've done this you can mkdir the missing tablespace directory to get PostgreSQL to start again, then DROP the missing databases, tables etc. It's better to just not do it.)


Or you could create a TABLESPACE in a ramfs / tempfs and create all your objects there.
I recently was pointed to an article about doing exactly that on Linux.

Warning

This can endanger the integrity of your whole database cluster.
Read the added warning in the manual.
So this is only an option for expendable data.

For unit-testing it should work just fine. If you are running other databases on the same machine, be sure to use a separate database cluster (which has its own port) to be safe.


Now it is possible to run an in-memory instance of PostgreSQL in your JUnit tests via the Embedded PostgreSQL Component from OpenTable: https://github.com/opentable/otj-pg-embedded.

By adding the dependency to the otj-pg-embedded library (https://mvnrepository.com/artifact/com.opentable.components/otj-pg-embedded) you can start and stop your own instance of PostgreSQL in your @Before and @Afer hooks:

EmbeddedPostgres pg = EmbeddedPostgres.start();

They even offer a JUnit rule to automatically have JUnit starting and stopping your PostgreSQL database server for you:

@Rule
public SingleInstancePostgresRule pg = EmbeddedPostgresRules.singleInstance();

You could use TestContainers to spin up a PosgreSQL docker container for tests: http://testcontainers.viewdocs.io/testcontainers-java/usage/database_containers/

TestContainers provide a JUnit @Rule/@ClassRule: this mode starts a database inside a container before your tests and tears it down afterwards.

Example:

public class SimplePostgreSQLTest {

    @Rule
    public PostgreSQLContainer postgres = new PostgreSQLContainer();

    @Test
    public void testSimple() throws SQLException {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(postgres.getJdbcUrl());
        hikariConfig.setUsername(postgres.getUsername());
        hikariConfig.setPassword(postgres.getPassword());

        HikariDataSource ds = new HikariDataSource(hikariConfig);
        Statement statement = ds.getConnection().createStatement();
        statement.execute("SELECT 1");
        ResultSet resultSet = statement.getResultSet();

        resultSet.next();
        int resultSetInt = resultSet.getInt(1);
        assertEquals("A basic SELECT query succeeds", 1, resultSetInt);
    }
}

There is now an in-memory version of PostgreSQL from Russian Search company named Yandex: https://github.com/yandex-qatools/postgresql-embedded

It's based on Flapdoodle OSS's embed process.

Example of using (from github page):

// starting Postgres
final EmbeddedPostgres postgres = new EmbeddedPostgres(V9_6);
// predefined data directory
// final EmbeddedPostgres postgres = new EmbeddedPostgres(V9_6, "/path/to/predefined/data/directory");
final String url = postgres.start("localhost", 5432, "dbName", "userName", "password");

// connecting to a running Postgres and feeding up the database
final Connection conn = DriverManager.getConnection(url);
conn.createStatement().execute("CREATE TABLE films (code char(5));");

I'm using it some time. It works well.

UPDATED: this project is not being actively maintained anymore

Please be adviced that the main maintainer of this project has successfuly 
migrated to the use of Test Containers project. This is the best possible 
alternative nowadays.

You can also use PostgreSQL configuration settings (such as those detailed in the question and accepted answer here) to achieve performance without necessarily resorting to an in-memory database.

참고URL : https://stackoverflow.com/questions/7872693/running-postgresql-in-memory-only

반응형