0

Jboss AS 7 コンテナーで実行されている Web ソフトウェアは、JTA に委任された構成である JPA を介して PostgreSQL 9.1 データベースにデータを保存します。

昨年、AWS EC2 クラウドで実行できるようになりました。ユーザーの需要が高まるにつれて、データベースの使用量も増加しました。予想通り、ラッシュ時にデータベース サーバーがビジー状態になり、ユーザーの使用経験に影響を与えました。

PostgreSQL に関するいくつかのレプリケーション調査の後、PGPool2 が私たちの場合に適したレプリケーション ソリューションになる可能性があることに気付きました。これは、SELECT クエリのロード バランシングと、CUD 操作 (UPDATE、INSERT、DELETE) のレプリケーションも提供します。

これまでのところ、ソフトウェアが遅くなることを除けば、とても良いです。実際、PGPool2 のドキュメントで明示されているように、明示的な BEGIN/END トランザクションで定義されている場合、SELECT クエリは負荷分散されません。

クエリを負荷分散するには、次のすべての要件を満たす必要があります。
  - PostgreSQL バージョン 7.4 以降
  - クエリは、明示的に宣言されたトランザクション内にあってはなりません (つまり、BEGIN ~ END ブロック内にあってはなりません)。
  - SELECT nextval または SELECT setval ではない
  - SELECT INTO ではありません
  - SELECT FOR UPDATE でも FOR SHARE でもありません
  - 「SELECT」または COPY TO STDOUT、EXPLAIN、EXPLAIN ANALYZE SELECT のいずれかで始まります...
  - ignore_leading_white_space = true は先頭の空白を無視します。

2 つの質問:

  • 明示的なトランザクションで実行されていた SELECT クエリを特定するにはどうすればよいでしょうか?
  • _javax.ejb.TransactionAttributeType.NOT_SUPPORTED_ はトランザクション スコープを修正し、SELECT メソッドが「トランザクション フリー」として実行されることを許可しますか?
4

2 に答える 2

1

明示的なトランザクションで実行されていた SELECT クエリを特定するにはどうすればよいでしょうか?

  1. SQL と接続の pgpool2 ロギングをオンにします。

    次のステートメントを pgpool.conf に入れます (これは で設定できますcp $prefix/etc/pgpool.conf.sample $prefix/etc/pgpool.conf):

    log_per_node_statement
    log_connections
    
  2. または、JPA のログ トレースをオンにします。

    これには、JPA 実装または JPA 実装 (JPA によって発行された SQL クエリを表示する方法は?Glassfish 3.0.1 および NetBeans 6.9.1 を使用した JPA 2.0 (ログとトレース): )に応じて、異なる方法が必要です。

    これは SQL を記録しますが、トランザクションの開始/コミット/ロールバックは記録しません。

    さらに、トランザクションの開始/コミット/ロールバックのタイミングを確認できるように、トランザクションを開始および終了するメソッドに独自のデバッグ ロギング コードを挿入します。

Does _javax.ejb.TransactionAttributeType.NOT_SUPPORTED_ fix the transaction scopes, granting that my SELECT method will be running as "transaction-free"?

@TransactionManagement(CONTAINER)コンテナ管理のトランザクション (アノテーションと@TransactionAttribute)を使用している場合NOT_SUPPORTED、 は現在のスレッドから JTA トランザクションの関連付けを一時的に解除します。その後、メソッドはトランザクション コンテキストなしで実行されます。

JTA トランザクションを使用できないため、後続の JPA クエリは JTA トランザクションの外部で実行されます。

  1. トランザクション スコープの EntityManagerを既に使用している場合

    ステートレス セッション Bean 内に、EntityManager注釈付き @PersistenceContext(type=PersistenceContextType.TRANSACTION)の 、または属性 @PersistenceContextなしの注釈付きがあります (がデフォルトであるため)。typeTRANSACTION

    • PC が現在のトランザクションに関連付けられているため、その EM は NOT_SUPPORTED メソッド内でその永続化コンテキストを失い、アクセスできなくなります。
    • そのため、メソッドでそのような EM を使用することはできません (たとえば、クエリを実行したり、キャッシュされたオブジェクトを検索したりするために)
    • したがって、NOT_SUPPORTED メソッド内で追加のアプリケーション管理 EM を使用する必要があります。
    • アプリ管理の EM は、作成中に現在のスレッドの JTA トランザクションに自動的に関連付けられるため、JTA トランザクションがアクティブでない場所 (NOT_SUPPORTED メソッドなど) で EntityManagerFactory からアプリ管理の EM を作成する必要があります。
    • 新しいアプリ管理 EM によってクエリから返されるオブジェクトは、元の EM とは異なる永続化コンテキストにあるため、そのようなオブジェクトを PC から完全に切り離すには細心の注意が必要です (例: appMgdEM.clear() または appMgdEM.close())。または appMgdEM.detach(someEntity)) を変更/元の EM とマージする場合。
  2. Extended-Scoped EntityManagerをすでに使用している場合

    ステートフル セッション Bean 内には、EntityManager注釈付きの@PersistenceContext(type=PersistenceContextType.EXTENDED).

    • その場合、PC はステートフル セッション Bean に関連付けられているため、その EM は NOT_SUPPORTED メソッド内に永続コンテキストを保持します。
    • しかし、EM はすでに「ライブ」トランザクションの途中にある接続を使用しています。
    • そのため、トランザクションの外部でクエリを実行する場合、メソッドでそのような EM を使用することはできません
    • この場合も、NOT_SUPPORTED メソッド内で追加のアプリケーション管理 EM を使用する必要があります (上記と同じ点が適用されます)。
  3. @Stateless
    public class DepartmentManagerBean implements DepartmentManager {
    
        @PersistenceUnit(unitName="EmployeeService")
        EntityManager txScopedEM;
    
        @PersistenceUnit(unitName="EmployeeService")
        EntityManagerFactory emf;
    
        @TranactionAttribute(REQUIRED)
        public void modifyDepartment(int deptId) {
            Department dept = txScopedEM.find(Department.class, deptId);
            dept.setName("New Dept Name");
            List<Employee> empList = getEmpList();
            for(Employee emp : empList) {
                txScopedEM.merge(emp);
                dept.addEmployee(emp);
            }
            dept.setEmployeeCount(empList.size()); 
        }
    
        @TranactionAttribute(NOT_SUPPORTED)
        public void getEmpList() {
            EntityManager appManagedEM = emf.createEntityManager();
            TypedQuery<Employee> empQuery = appManagedEM.createQuery("...", Employee.class);
            List<Employee> empList = empQuery.getResultList();
            // ...
            appManagedEM.clear();
            return empList;
        }
    }
    

    代替的/調整されたアプローチ

    上記では、クエリの方法と結果オブジェクトの使用方法にいくつかの制限があります。ステートレス セッション Bean を使用する場合は、EM を「オンザフライ」で作成する必要があり、またentityManager.merge()呼び出す必要があります。あなたには合わないかもしれません。

    強力な代替手段は、アプリケーションを再設計して、トランザクションの開始前にすべてのクエリを実行することです。次に、単一の Extended-Scoped EntityManager を使用できるようにする必要があります。拡張スコープ EM を使用して、"NOT_SUPPORTED" メソッド 1 (トランザクションなし) でクエリを実行します。次に、同じ拡張スコープ EM を使用して、「REQUIRED」メソッド 2 (トランザクションあり) で変更を実行します。トランザクション スコープの EntityManaged は機能しません (最初からトランザクションに対応しようとし、NOT_SUPPORTED メソッドに PC がありません)。

乾杯 :)

于 2013-06-24T08:37:05.087 に答える
1

EclipseLink データのパーティション分割を使用して、JPA でのパーティション分割を検討することをお勧めします。

http://java-persistence-performance.blogspot.com/2011/05/data-partitioning-scaling-database.html

于 2013-06-25T12:54:20.723 に答える