Agile Cat — Azure & Hadoop — Talking Book

June 27, 2009

初めての New SQL Data Services

Eugenio Pace – Cloud Computing Guidance

Windows Azure のセールス・ポイントとして注目される New SDS ですが、Eugenio さんのブログで新しいポストを見つけました。 それと、以前の Eugenio さんの LitwareHR ですが、カテゴリ Eugenio Tracker に整理しましたので、そちらもご覧ください。   --- A.C.

Clouds: one thing we really know about here in Redmond, WA, USA
Published Friday, June 12, 2009 12:03 PM by eugeniop

Pasted from <http://blogs.msdn.com/eugeniop/archive/2009/06/12/first-experiments-with-new-sql-data-services.aspx>

First experiments with (new) SQL Data Services

 
Last week I got my new login to the new SQL Data Services. As a reminder for all readers:
SDS accelerates its plans to offer relational capabilities

May 11, 2009 – Based on customer feedback, SDS has accelerated its plans and will be offering true relational capabilities through SQL Server’s existing network protocol, Tabular Data Stream (TDS) and existing query language Transact-SQL (T-SQL). This will provide customers direct access to the familiar relational model, T-SQL programming language and the existing development and management tools, while continuing to deliver on our key value props of fault tolerance, high availability, friction free provisioning and pay as you grow scaling. For more information, see the SDS product site and the MSDN Library.

May 11, 2009 – カスタマー・フィードバックに基づき、SQL Server における既存のネットワーク・プロトコルである Tabular Data Stream(TDS)を介して、また、既存のクエリー言語である Transact-SQL(T-SQL)を介して、SDS の計画を加速し、本当のリレーショナル機能を実現していく。 そこで顧客に提供されるのは、T-SQL プログラミング言語と、開発と管理のための既存のツールで構成される、親しみのあるリレーショナル・モデルへのダイレクトなアクセスであるが、フォールト・トレランスと、高可用性、スケールの成長に応じたプロビジョニングと支払いなどへの、支援に関する提供は継続される。 詳細な情報については、SDS プロダクト・サイトと MSDN Library を見てほしい。

 

————————-

What I’ve done? After some initial “hello world-ish” tests, I wanted to try something more interesting so I decided to port IssueTracker into SDS.

私がしたことについて、説明しよう。 最初に行った何パターンかの “hello world-ish”  テストの後に、もっと面白いことをやりたいと思った。 そして、SDS で IssueTracker をポートすることに決めた。

As you know, IssueTracker was originally designed for SDS’ previous ACE model (Authority, Container, Entity), so my first task was to re-write the data access layer to use SQL Server.

皆が知っているように、IssueTracker は以前の SDS が提供していた、ACE モデル(Authority、Container、Entit)のためにデザインされたため、最初の作業は SQL Server をように、そのデータ・アクセスレイヤをリライトすることだった。

One of my goals in this experiment was to test SDS “impedance match” with on-premises SQL Server. Also, I wanted to develop independently of the availability of SDS. Not that SDS is unreliable, but currently it is available only inside Microsoft’s corporate network. I didn’t want to VPN into corpnet for this when working from home.

この実験における目的にひとつは、オンプレミスの SQL Server を用いた、SDS の  “impedance match”をテストすることにあった。また、SDS の可用性とは切り離されたところで、開発を行いたいと望んだ。 SDS が信頼できないということではないが、現時点においては、Microsoft のコーポレート・ネットワークの中だけで利用できるというものである。 そして、コーポレート・ネットワークに依存したくなかったのは、家でも仕事をするからだ。

So I chose to develop exclusively against my local SQL Express instance first and then make a switch to the real SDS.

そこで私が選んだのは、ローカルな SQL Express インスタンスで最初に作業した後に、本物の SDS にスイッチする形態である。

Fortunately, the app was designed with a couple of layers that isolated the persistence details, so writing the new data tier was a fairly mechanical process.

幸いなことに、このアプリケーションは永続的に分離される、2 つの層の組み合わせを用いてデザインされていたため、新しいデータ層の記述は、機械的なプロセスで進んだ。

This diagram roughly captures the architecture:

そのアーキテクチャについて、以下の図に示す:

New SDS 1The repository classes implement a common interface the app uses, the Model is just a collection of rather simple C# objects with no knowledge of the database being used. The Mappers are responsible for the transformations between the application model and the entities that do have knowledge of the database.

そのリポジトリ・クラスはアプリケーションが使う普通のインターフェイスを実装する。そして、この Model は単純な C# オブジェクトというより、単なるコレクションであり、データベースの知識は必要ない。 また、Mappers に課せられた責任は、アプリケーション・モデルと、データベースの知識を持つエンティティの間での変換となる。

In the diagram, classes marked with * are new, the numbers indicate variability points in the implementation, meaning that I can switch between one implementation and the other. Because I used LINQ to SQL, the types in the box labeled as “SQL Model” were generated automatically by the LINQ to SQL designer.

この図で、* マークが付いているのは新しいクラスであり、また、数が記されているのは、実装を切り替えられる可変のポイントである。 SQL に対して LINQ を使用したため、ボックス内に記された “SQL Model” であるというラベルは、LINQ to SQL デザイナーにより自動的に生成された。

When my unit tests compiled again, I switched the connection string to point from the “.\SQLEXPRESS” to the SDS instance in our network and…it worked! First attempt! 

単体テストのために再コンパイルしたとき、接続文字列のポイントを、 “.\SQLEXPRESS” から、ネットワーク上の SDS インスタンスに切り替えた。それが、そのまま動いた。 それが、最初のトライである!

New SDS 2

Overall, it was a rather painless and pleasant experience. Of course the data model in the app is simple and I’m not using any advanced queries or any sophisticated features in SQL yet.

もちろん、アプリケーションのデータモデルはシンプルであり、また、SQL の洗練されたクエリーや、先進的なキューは使っていない。

Things missing and Possible next steps:

The original implementation had 2 requirements that leveraged features in SDS previous ACE model:

1- Multi-tenant isolation: achieved through containers. Each tenant got its own container.

2- Schema flexibility: tenants could customize the application, extending the schema of some core entities. Flexible entities made this very easy, because they are essentially property bags.

このオリジナルの実装は、以前の SDS ACE モデルにおける 2つの機能を活用するという用件を持っていた:

1- Multi-tenant isolation: コンテナを介して達成されるものであり、それぞれのテナントが自身のコンテナを持つ。

2- Schema flexibility: いくつかのコア・エンティティを拡張することで、テナントによるアプリケーションのカスタマイズを実現する。柔軟なエンティティにより実現可能な理由は、それらが、本質的にプロパティ・バッグだからである。

For #1, I considered two options:

1- Partitioning by tenant
2- Do not partition at all and have all tenants on the same database (single-instance, multi-tenant)

#1 については、2つのオプションを検討した:

1-  テナントによるパーティショニング
2- パーティショニングは全く行わずに、すべてのテナントを同一のデータベース上に持つ(single-instance, multi-tenant)
The first option is fairly straight forward. Each tenant gets its own database that is created at provisioning time. The “tenant id” is part of the calling context in the application, so I dynamically connect to each database as needed. Two advantages of this approach: there’s high isolation between tenants (no data from one can leak into another), and the application code is simpler, because from the data perspective, the application is “single-tenant”.

最初のオプションは、かなり単刀直入なものである。 それぞれのテナントが、プロビジョニング時に作成される。自身のデータベースを取得する。 その “tenant id” が、アプリケーションにおけるコール・コンテキストの一部となるため、個々のデータベースとの動的な接続が、必要に応じて実現される。 このアプローチにおける のアドバンテージは、テナント間の分離が強化されることである。 また、アプリケーション・コードもシンプルになる。 その理由は、データの視点から見ると、対象となるアプリケーションが “single-tenant” になる点にある。

I haven’t implemented the extensibility feature yet, but I’m planning on reusing some techniques we did some research on in the past, probably through extension tables.

拡張された機能については、まだ実装していないが、いくつかのテクニックを再利用したいと考えている。それは、おそらく、過去において研究してきた、拡張テーブルを介したものとなるだろう。

There’re other interesting areas for research such as:


そのほかの、研究すべき領域としては、以下のような面白い分野がある:

1- Strategies for partitioning: in discussions with Ryan, he suggested I should consider more sophisticated ways of partitioning the information: by tenant, by tenant + project, etc. and I agree this would be interesting .

1- Strategies for partitioning:  Ryan とのディスカッションにおいて、情報のパーティショニングについて、もっと洗練された方式を考えるべきだとの示唆があった。それは、 by tenant や by tenant + project などであり、それらが興味深いものであることに、私は同意している。

2- Unit of Work: currently I’m simply reusing the original ACE implicit UoW that comes with each interaction. This is, each time you called Create, Delete or Update on SDS, the operation was completed in the context of a unit of work. You could not logically group multiple operation (say, 2 creates and 1 delete). This is suboptimal with the SQL implementation, because the new SDS supports transactions and I would like to leverage that.

2- Unit of Work: 現時点では、それぞれの相互作用に伴って生じる、オリジナルの ACE における暗黙の UoW を再利用しているだけである。 それは、SDS 上で Create/Delete/Update がコールされるたびに、unit of work のコンテキストの中で、オペレーションが完了するというものだ。 多数のオペレーションを、論理的にまとめることはできない(たとえば、2つの create と、1つの delete)。 それが、SQL 実装における次善である。なぜなら、新しい SDS がサポートするトランザクションを、活用したいと思っているからだ。

3- Performance and scalability issues: I haven’t spent any time looking at the application’s “chattiness” with the database that might lead to degraded performance, or any other data access optimizations. This is a whole area in itself, but not very different from “regular” application development. The only exception perhaps is that, in theory at least, the app and the database can be hosted in different datacenters (say the app in Amazon and the data in SDS). I’m not sure that would be a good idea anyway, probably not for this scenario. If the app was hosted in Windows Azure and used SDS, then they would be close in terms of network distance (low latency & high bandwidth). 

3- Performance and scalability issues: このアプリケーションとデータベースの間での “chattiness” については、時間を割いてこなかった。そのため、パフォーマンスの低下を招いているかもしれないし、データアクセスの最適化が必要かもしれない。 それは、アプリケーションの全域におよぶものであるが、“regular”  なアプリケーション開発と、そう変わるものでもない。 唯一の例外と思われるのは、少なくとも理論上において、アプリケーションとデータベースが別のデータセンターにホストされる可能性があることだ(たとえば、アプリケーションは Amazonで、データは SDS)。 それが適切な考え方だとは、確信していない。そして、このシナリオのためのものでもない。 このアプリケーションが Windows Azure 上にホストされ SDS を使うなら、ネットワーク・ディスタンスの観点から、両者の距離は近いものとなる(low latency & high bandwidth)。

Published Friday, June 12, 2009 12:03 PM by eugeniop

Pasted from <http://blogs.msdn.com/eugeniop/archive/2009/06/12/first-experiments-with-new-sql-data-services.aspx>

June 13, 2009

New version of LitwareHR

Filed under: Eugenio Tracker — Agile Cat @ 2:54 pm
Tags: , ,

SQL Server Data Services – SSDS – New version of LitwareHR

Eugenio Pace – Software as a Service Architecture Guidance

Published Wednesday, March 05, 2008 9:32 PM by eugeniop 
http://blogs.msdn.com/eugeniop/archive/2008/03/05/sql-server-data-services-sdss-new-version-of-litwarehr.aspx

Today, in his keynote, Ray Ozzie announced a new "cloud service" available from Microsoft: SQL Server Data Services (code name: Stika). It’s a good that he announced it, because now I’m out of quarantine and I can talk about it :-) .

今日(MIX 08)の Ray Ozzie によるアナウンスの要旨には、Microsoft から提供される新しい「クラウドサービス」: SQL Server Data Services (code name: Stika) があった。 彼のアナウンスがあって良かった。 なぜなら、もう口をつぐむ必要もなく、それにつて話ができるからだ :-)

For the last 2 months I’ve been working very closely with the SSDS team, understanding and exploring how their technology can be applied in the context of the work we do: (business) software delivered as a service. I’ve been playing the role of an ISV designing and creating solutions using SSDS. My playground has been, of course, LitwareHR: our reference application for and S+S app. 

これまでの2カ月において、とても緊密に SSDS チームと作業してきた。その結果、(ビジネス)ソフトウェアをサービスとして配信するという、私たちが推し進めているコンテキストにしたがって、このチームのテクノロジーを適用するための方式を、理解し探求することができた。 いま私は、SSDS を用いてソリューションの設計/開発を行う、ISV の役割を演じている。 私の活動の場は、もちろん LitwareHR である。 それは、私たちのリファレンス・アプリケーションであり、S + S アプリケーションでもある。

LitwareHR today looks like this:

現在の LitwareHR は、以下のような感じである:

Eugenio 090204a

LitwareHR on SSDS, looks like this:

そして、SSDS 上の LitwareHR は、以下のような感じである:

Eugenio 090204b

Same client experiences (Web Client, Rich Client, APIs), same business logic exposed through WCF, completely new storage.
同一のクライアント・エクスペリエンス(Web Client/Rich Client/API)と、WCF を介してエクスポーズされる同一のビジネスロジック、そして、完全に刷新されたストレージ。

My team’s job was to redesign Litware’s (multi-tenant) data access layer to use SSDS, adapting it to the new application model. It’s been a great and fun exercise, with lots of learning. 
私のチームのジョブは、SSDS を活用するために、Litware の(マルチ・テナント)データ・アクセス・レイヤのデザインを変更し、新しいアプリケーション・モデルに適合させることだ。 それは、重要で面白いエクササイズであるが、たくさんの学習も必要だ。

June 12, 2009

LitwareHR on SSDS – Part I

Filed under: Eugenio Tracker — Agile Cat @ 2:53 pm
Tags:

Eugenio Pace – Software as a Service Architecture Guidance

Published Friday, March 14, 2008 3:52 PM by eugeniop

Pasted from <http://blogs.msdn.com/eugeniop/archive/2008/03/14/litwarehr-on-ssds-part-i-multi-tenancy-flexibility.aspx> 

LitwareHR on SSDS – Part I – Multi-tenancy & Flexibility

SSDS’s application model and features map quite nicely to our customization and multi-tenancy requirements in LitwareHR.

SSDSのアプリケーション・モデルと機能は、私たちのカスタマイズとマルチ・テナントの要件を、きわめて適切に LitwareHR にマップする。

A significant amount of code in LitwareHR is in the generic, multi-tenant, extensible data access. Our multi-tenant database performance guide, compares different extensibility approaches (XML datatypes, extended tables, fixed columns), their advantages and disadvantages, etc.

LitwareHR における相当量のコードは、汎用的であり、また、マルチ・テナント対応であり、拡張可能なデー・タアクセスを持つ。私たちのマルチ・テナント・データベースに関するパフォーマンス・ガイドでは、いくつかの拡張のためのアプローチ(XML データタイプ/拡張テーブル、固定カラム)が比較され、その利点と弱点を明らかにしている。

All of that is greatly simplified in the version of LitwareHR that uses SSDS because of the built-in support for extensibility and tenant isolation in the service.

それらの全てが、SSDS を用いる LitwareHR のバージョンでは、きわめて単純化される。 なぜなら、サービスにおける拡張性とテナントの分離が、ビルトインでサポートされるからだ。

The ACE Model:

SSDS model is quite simple actually, it is referred to as the ACE model and it is basically a 3 level containment architecture:

実際に、SSDSモデルは、きわめてシンプルである。 ACEモデルと呼ばれる、3レベルの階層型アーキテクチャを持つ:

Eugenio 090208a2

Authority (the top level container) contains zero or more Containers which in turn contain sets of Entities. Entities have properties: intrinsic (like Id, Kind & Version are present in any entity) and custom properties which are user defined. Properties have a type (string, dates, numbers).

Authority(コンテナのトップレベル)は、ゼロ個から複数個の Container を内包し、それぞれの Container が、Entity のセットを順番に取り込んでいる。 Entity には、本質的なプロパティ(Id/Kind/Version といった、あらゆるエンティティに存在するもの)と、ユーザーが定義するカスタムなプロパティを持つ。そしてプロパティは、タイプ(string/dates/numbers)も持つ。

This model maps very nicely to LitwareHR requirements:

以下のモデルは、LitwareHR 要件に対して、きわめて適切にマップされる:

Authorities & Containers give us out-of-the-box tenant isolation for storage.

Authorities & Containers は、ストレージに対して直ちに利用できるテナント分離を提供する。

Entities give us exactly what we need to provide each tenant a different data shape for positions and resumes.

Entities は、 positions とresumesのための異なるデータ shape を、個々のコンテナに提供するために必要とする、まさに適切なものをもたらす。

In our current implementation of LitwareHR, there’s a single Authority (owned by Litware for LitwareHR) with multiple containers: one for LitwareHR itself where all application metadata is stored (this is the equivalent of the old TenantMetadataStore), and one Container for each tenant that is provisioned. Here’s a subset of this model:

現時点における LitwareHR の実装では、単一の Authority(LitwareHR 用の Litware により所有される)と、複数の Container が含まれる。 ひとつは LitwareHR 自身のための、つまり、すべてのアプリケーション・メタデータをストアする Container であり(従来の TenantMetadataStore に等しい)、もうひとつは、プロビジョニングされる個々のテナントのための Container である。以下は、このモデルのサブ・セットである:

Eugenio 090208b2 

Because LitwareHR allows each tenant to change the shape of the Position entity, instances of this type are all different between tenants.

LitwareHR により、Position エンティティの shape を変更する、個々のテナントが実現されるため、このタイプのインスタンスは、テナントごとに、すべて異なるものとなる。

Notice that SDSS is actually more flexible than how it is used in LitwareHR. SSDS allows instances of any entity to have any set of properties and there’s no schema forced into any particular instance. LitwareHR restricts flexibility at the tenant level, so all positions of a given tenant will have the same schema, but each tenant can have any schema they want.

SDSS は LitwareHR での用法よりも、はるかな柔軟性を持つことに注意すべきだ。 SSDS は、あらゆるプロパティ・セットを持つ、あらゆるエンティティのインスタンスであっても許可し、いかなる固有インスタンスに対しても、フォーカスするスキーマは存在しない。 LitwareHR は、テナント・レベルにおいて、その柔軟性を制約する。そのため、所定のテナントにおける全ての position は、同一のスキーマを持つことになるだろうが、それぞれのテナントは、そこで必要となる、あらゆるスキーマを持つことができる。

LitwareHR Metadata Container

Entities stored in LitwareHR’s metadata container will be used to drive the application: tenant information, UI, menus, views, entities schema for the tenant, etc.

LitwareHR のメタデータ・コンテナにストアされるエンティティは、アプリケーションを駆動するるために使用される。 それらは、テナント情報、UI、メニュー、ビュー、テナントのためのエンティティ・スキーマなどとなる。

Here’s the result of a query against the demo LitwareHR container. You can see various entities stored there, including a serialized recruiting workflow definition:   

デモ用の LitwareHR コンテナに対してクエリーを実行した結果は、以下のとおりである。 そこにストアされた各種のエンティティを、シリアライズされたリクルーティング・ワークフローの定義も含めて確認できるだろう。

Eugenio 090208c2

The URI for this query is http://litwarehr.data.sitka.microsoft.com/v1/LitwareHR?q= which essentially means: "bring me all the contents of container LitwareHR in litwarehr authority" (note the format of the URI: .data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">http://<AuthorityId>.data.sitka.microsoft.com/<ContainerId>?q=).

このクエリーのURIは以下のとおりであり、本質的に「litwarehr Authority に、LitwareHR の全てのコンテナ・コンテンツを受け渡す」という意味を持つ。
http://litwarehr.data.sitka.microsoft.com/v1/LitwareHR?q=

なお、このURIの書式は、以下のとおりである:

.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">.data.sitka.microsoft.com/?q">http://<AuthorityId>.data.sitka.microsoft.com/<ContainerId>?q=

SSDS query language (SLINQ) is a subset of LINQ syntax. For example, the query for retrieving all instances of particular entity type (e.g. "Tenant") would be:

"from e in entities where e.Kind==’Tenant’ select e"

SSDS query language(SLINQ)は、LINQ シンタックスのサブ・セットである。 たとえば、特定のエンティティ・タイプ(例えば "Tenant")における、すべてのインスタンスを取り出すためのクエリーは、以下のとおりになるだろう:「from e in entities where e.Kind == ‘Tenant’ select e」

SLINQ is a subset and there are many features not available quite yet: projections, grouping, etc.

SLINQ はサブ・セットであり、projections や grouping といった多くの機能が、まだ利用できない。

Currently, SSDS will return the whole entity, even if you just need a part of it. Of course you can still use LINQ on the client side to group, filter, etc. but over the wire the whole thing will be transported. 

現在時点では、たとえ一部が必要であっても、 SSDS はエンティティ全体をリターンするだろう。 もちろん、クライアント・サイドでは LINQ の group や filter などを使うことができが、全体が転送されるだろう。

Quid Pro Quo:

Nothing valuable is free, isn’t it? SSDS gives you unlimited storage, tremendous flexibility, geo-aware location. You don’t have to worry about backups, operations, disk failures, power, air conditioning, machines, etc. You just use it. But all this goodness comes at a cost: you don’t "own" the database any more, you can’t assume the database is "close" to you (too chatty interactions with it, will lead into latency issues) and the programming model you were used to is different: there are no tables, stored procedures, views, joins, etc.

価値が無ければタダであるが、SSDS はどうだろうか? SSDS が提供するものは、無制限のストレージと、途方もない柔軟性、そして、地理的要因を考えた配置である。 バックアップ/オペレーション/ディスクの故障/空調施設/マシンのことなど、心配しなくてもよい。 ただ、それを使うだけだ。 すべての利点はコストに跳ね返るが、もうデータベースは「所有」しなくて構わなくなる。データベースが、すぐ「近く」にあるなんて、想像できなくなる(つまり、チャットのようなインタラクションが、遅延の問題を導くわけだ)。そして、慣れ親しんできたプログラミング・モデルも、別のものに変わる。つまり、tables/stored procedures/views/joins などは無くなる。

You will have to decide whether these cons, out-weight the benefits in your particular scenario, and hopefully some of the lessons learnt in Litware, although impossible to extrapolate to every scenario, will help you make that decision.
As Nigel mentioned in MIX though, it is highly likely that many more features will be added to SSDS in the upcoming months.

発想の転換、そして 固有のシナリオにおいて重石から開放されるメリット、さらに Litware で望まれる若干のレッスン。すべてのシナリオは推定できないが、あなたの判断に、それらの要因は役立つだろう。 いずれにせよ、決めなければならなくなる。 Nigel が MIX で言及したように、この何ヶ月のうちに、さらに多くの機能が SSDS に加えられる可能性がある。

In the next chapters, I will go deeper into LitwareHR on SSDS architecture, the challenges we faced and how we solved them.

次のチャプタでは、SSDS アーキテクチャにおける LitwareHR  を掘り進める。 私たちが直面した課題と、それらを解決した方式について述べる。

June 9, 2009

LitwareHR on SSDS – Part II

Filed under: Eugenio Tracker — Agile Cat @ 2:52 pm
Tags: , ,

Eugenio Pace – Software as a Service Architecture Guidance

Published Wednesday, March 19, 2008 11:05 AM by eugeniop
From <
http://blogs.msdn.com/eugeniop/archive/2008/03/19/litwarehr-on-ssds-part-ii-the-data-access-layer.aspx>

LitwareHR on SSDS – Part II – The data access layer

The heart of LitwareHR implementation on SSDS is in it’s data access layer of course. In fact, we created two different, but functionally equivalent implementations: one runs against SQL (LitwareHR’s original implementation) and a second stack that runs against SSDS. Of course they are mutually exclusive and all layers above the DataModel cannot tell the difference.

SSDS 上の LitwareHR 実装における中心は、もちろん、そのデータ・アクセス・レイヤの中にある。現実に、私たちは、同じ機能を持つが、構造が異なる2つの実装モデルを作成した。ひとつは、SQL に接するかたちで実行され(LitwareHR のオリジナル実装)、二番目のスタック・モデルは、SSDS に接するかたちで実行される。もちろん、それらは相互に排他的であり、また、DataModel よりも上位にある、すべてのレイヤは相違を伝えることができない。

EugenioP 09_04_03a

As illustrated in the diagram above, the key class is Repository<T>, which among other things encapsulates all access to SSDS, translates T’s into SSDS’s Flexible Entities and in general provides a higher level of abstraction on top of SSDS artifacts. For example, Repository deals with tenants, which are then mapped into Authorities & Containers by a provider. The default implementation of this simply does a 1:1 mapping between Tenants and Containers, being Authorities fixed (as specified in configuration), but because it is using a provider model, you can supply a more sophisticated implementation.

上記のダイアグラムに示されるように、キークラスは Repository<T> である。それは、他の階層にはさまれ、SSDS に対する全てのアクセスをカプセル化する。T に受け渡されたものは、SSDS の Flexible Entities に展開され、また、一般的には、SSDS アーティファクトのトップに、高抽象レベルを供給する。 たとえば、 Repository は tenants を取り扱い、続いて、プロバイダにより、Authorities & Containers の中にマップされる。 ここでのデフォルト実装は、Tenants とContainers の間で 1:1 でマッピングされ、(コンフィグレーションで指定されるように)Authority は固定されるが、プロバイダ・モデルが使われているため、さらに洗練された実装を提供できる。

T allows us to use typed objects that represent LitwareHR entities: Resumes, Positions, etc. so a hypothetical LitwareHR developer can write things similar to this:

T により、LitwareHR エンティティを表現するための、Resumes や Positions などの類型化されたオブジェクトが使用できるようになる。それによいり、想定される LitwareHR デベロッパーは、以下に類似したことを記述できる:

public class Position : ExtensibleEntity
{
public string Code {set;get;}
public string Location {set; get;}
}

Position p = new Position { Id = Guid.NewGuid(), Code = "Code_1", Location = "Location_1", };
p.Fields.Add( "YearsOfExperience", 15 );

In LitwareHR all entities derive from ExtensibleEntity which is just a simple helper base class that provides some useful fields such as: Id, a collection of fields, etc.

In the example above, Id comes from ExtensibleEntity, Code and Location are defined at design time by the developer and "YearsOfExperience" might be a field that a particular tenant is adding to this position. Because it is a tenant specific field, it is defined at runtime.

LitwareHR において、すべてのエンティティは、単なるヘルパー・ベースのクラスである ExtensibleEntity から生じる。そのクラスにより、たとえば field sのコレクションである Id のような、いくつかの有用なフィールドが提供される。上記のサンプルにおいては、デザイン・タイムにデベロッパーにより定義される、ExtensibleEntity/Code/Location から Id が生じている。そして「YearsOfExperience」は、このポジションに特定のテナントが加える、フィールドになるかもしれない。それは、テナントが特定し、ランタイムに定義されるフィールドになる。

Behind the scenes the Position entity will be translated into a SSDS flexible entity. Id, and Kind are intrinsic properties in SSDS and are automatically mapped into the Position.Id and typeof(Position).ToString(). The rest is mapped to flexible properties.

その背後において、Position エンティティは、SSDS の柔軟なエンティティに変換されるだろう。 Id と Kind は、SSDS の本質的なプロパティであり、Position.Id と typeof(Position).ToString() に自動的にマップされる。 残りのものは、柔軟なプロパティにマップされる。

All those details are of course handled by Repository<T>. Its interface is straight forward and looks like the one below, which is self-explanatory.

それら全ての細部は、もちろん、Repository<T> により操作される。 そのインターフェイスは単純なものであり、また、以下のように説明を要しないものである。

Insert( T );
T GetById( id );
IEnumerable<T> ListAll();
IEnumerable<T> Search( string query );
Delete( id );
Update( T );

So a complete snippet (taken from one of our tests) looks like this:

したがって、それらの断片をまとめたものは以下のようになる:

EugenioP 09_04_03b

June 6, 2009

LitwareHR on SSDS – Part III

Filed under: Eugenio Tracker — Agile Cat @ 2:51 pm
Tags: ,

Eugenio Pace – Software as a Service Architecture Guidance

Published Monday, March 24, 2008 4:50 PM by eugeniop

From <http://blogs.msdn.com/eugeniop/archive/2008/03/24/litwarehr-on-ssds-part-iii-data-access-enhancements-1-caching.aspx>

LitwareHR on SSDS – Part III – Data access enhancements 1: caching

In most applications, the distance (in terms of bandwidth and latency) between the store (the database) and the application logic (like the web servers and web services) is usually very small. The connectivity between these two components is usually very reliable and with very high throughput. But because SSDS is on the other side of the cloud, latency and unreliability of the network could hurt the application performance and availability. Not to mention that in a production application, an ISV will very likely pay for each operation submitted against SSDS in addition to the storage he’s using.

大半のアプリケーションにおいて、ストア(データベース)とアプリケーション・ロジック(Web サーバーや Web サービスなど)の間の距離は、通常では極めて(バンド幅と遅延に関して)短い。これらの2つのコンポーネント間の接続性は、通常では極めて信頼性が高く、とても高いスループットを持つ。しかし、SSDS はクラウドの向こう側に存在するため、ネットワークの遅延と信頼性の欠如が、アプリケーションの性能と可用性に悪影響をおよぼす可能性がある。プロダクション環境における、アプリケーションについて言及するわけではないが、ISV が使用しているストレージのほかに、SSDS に対してサブミットされる個々のオペレーションためのコストが生じるだろう。

For all these reasons it is important to consider technical options that would minimize the degree of "chattiness" of the application (for decreased latency) and the total amount of calls made (for latency & for cost).

これら全ての理由に対して、検討すべき重要なテクニカル・オプションは、アプリケーションにおける「チャット性」を(遅延の低減のために)最小化し、発生するコールの総量(遅延とコストのために)を最小化することになるだろう。

With this in mind, it is highly likely your app will have a spectrum of information that it deals with, with different levels of longevity and volatility.

それを意識すると、アプリケーションが取り込む情報の種類に応じて、永続性と揮発性の異なるレベルを取り扱う可能性が、きわめて高くなると思われる。

If the data is immutable (e.g. reference information, read only, historic records, etc.) then there is a great chance you can aggressively cache it on the client side to avoid further calls. (Notice that "client side" is a relative term: in LitwareHR, the client side for SSDS is the web services layer).

もし、そのデータが不変(たとえば、リファレンス情報/リード・オンリー/ヒストリー記録)である場合には、必要以上のコールを回避するために、クライアント側で積極的にキャッシュを行えるという、大きな可能性が開ける。 (注意: LitwareHR の「クライアント・サイド」は相対的な用語であり、SSDS 用のクライアント・サイドは、Web サービス・レイヤとなる)

In LitwareHR, for example, Resumes cannot be modified. Someone can submit multiple resumes, but once it is submitted, it is immutable. A perfect candidate then for caching.

LitwareHR において、たとえば Resumes は、修正できない。 誰もが多数の Resumes をサブミットできるが、一度サブミットされると、不変となる。 そのときには、キャッシュのための、完ぺきな候補となる。

To demonstrate this scenario, we included caching capabilities into LitwareHR’s data access that can be enabled either programmatically and/or by configuration:

このシナリオを証明するために、LitwareHR のデータ・アクセスにキャッシュ機能を取り込んだ。 それは、コンフィグレーションによりプログラム的に and/or を切り替えることが可能なものである:

Eugenio 3 09_04_08

The CacheManager is simply using underneath Enterprise Library’s caching block that gives us nice backing store capabilities and some advanced expiration policies.

この CacheManager は、Enterprise Library のキャッシュ・ブロックにおける、下部構造を単に使っているだけである。それにより、適切なバッキング・ストア機能と、いくつかの先進的なエクスパイヤー・ポリシーが提供される。

The Repository will transparently get and store items (entities & full query results). To give the developer extra flexibility and control, entities only marked as "cacheable" (which is done through an interface implementation) are processed with the cache (if one is available). That means of course, that if an entity is not marked as "cacheable", then it will always go against the store, regardless of the existence and availability of a cache.

この Repository は、アイテム (entities & full query results) を透過的に取得し、ストアするだろう。デベロッパーに対して、さらなる柔軟性と盛業を提供するために、単に「cacheable(インターフェイス実装を介して処理される)」とだけマークされたエンティティが、キャッシュ(利用可能な場合に)を用いて処理される。もちろん、エンティティに「cacheable」のマークが無い場合には、キャッシュが存在し、その利用が可能であっても、ストアに対して処理が行われることになる。

As an example of how this works, here’s a small test. The class Book is an (extensible) entity and is also cacheable. 

その処理を確認するサンプルとして、以下に小規模なテストを示す。 クラス Book は(拡張可能な)エンティティであり、また、cacheable である。

public class Book : ExtensibleEntity, ICacheableEntity
{
public string Title { set; get; }
public string ISBN { set; get; }
public bool IsCached { set; get;} //This is ICacheableEntity implementation
}

We want to test a Repository for this class and caching behavior:

私たちは、このクラスの Repository と、キャッシュの振る舞いについてテストしたかった:

[TestMethod]
public void ShouldInsertBookGetByIdDelete()
{
using (Repository<Book> rp = new Repository<Book>(tenantId,
new RepositoryCacheManager( "CacheManager",
new SlidingTime( TimeSpan.FromMilliseconds( 3000 )),
true,
false )) )
{
Book bk = new Book { Id = Guid.NewGuid(), Title = "The Aleph", ISBN = "4374834" };
bk.Fields.Add("Author", "J.L.Borges" );
rp.Insert(bk);
Book rbk = rp.GetById(bk.Id);
Assert.IsNotNull(rbk);
Assert.IsTrue(rbk.IsCached);
Assert.AreEqual(bk.Title, rbk.Title);
Assert.AreEqual(bk.Fields["Author"].Value, rbk.Fields["Author"].Value);
Thread.Sleep(3500);
rbk = rp.GetById(bk.Id);
Assert.IsNotNull(rbk);
Assert.IsFalse(rbk.IsCached);
rp.Delete(bk.Id);
Assert.IsNull(rp.GetById(bk.Id));
}
}

Let’s see piece by piece how this works:

ここに含まれるのは、以下のとおりだ:

1- We create a new Repository for Book, using a constructor that takes the tenantid and a CacheManager implementation. This CacheManager takes this arguments:

  • The name of the EntLib’s cache to use (this translates into the configuration section to use)
  • The expiration policy (In the sample, it would be a sliding time of 3 seconds: items in the cache will be invalid after 3 seconds and discarded)
  • A boolean for caching entities (true in the example)
  • A boolean for caching queries (false in the example)

2- We create a new Book and add some fields, both explicit fields (as defined in the Book class) and an extension field (Author).

3- We insert the Book instance and then retrieve it immediately

4- Because the retrieval (hopefully :-) ) will happen before 3 seconds, it should come from the cache (flagged with the IsCached field)

5- We then wait for slightly more than the expiration period (3.5 seconds to be precise) and then retrieve it again. This time, it should come fresh from SSDS, therefore IsCached should be false.

6- We clean up by deleting it

EntLib’s underlying implementation has some interesting features we didn’t use. For example, you can subscribe to expiration notifications and handle them. You could, for instance, proactively request a a renewal when an item expires proactively keeping your cache up to date.

EntLib の基礎をなす実装は、いくつかの興味深い特徴を持っているが、ここでは、それらは使われていない。たとえば、エクスパイヤーの通知をサブスクライブし、それらを制御することができる。実際に、キャッシュを最新レベルに保つために、アイテムを積極的にエクスパイヤーさせるリクエストを、積極的に発行することができるだろう。

June 3, 2009

LitwareHR on SSDS – Part IV

Filed under: Eugenio Tracker — Agile Cat @ 2:49 pm
Tags: ,

Eugenio Pace – Software as a Service Architecture Guidance

Published Tuesday, April 01, 2008 2:43 PM by eugeniop

From <http://blogs.msdn.com/eugeniop/archive/2008/04/01/litwarehr-on-sdss-part-iv-data-access-enhancements-2-developing-offline-fro-ssds.aspx>

LitwareHR on SSDS – Part IV – Data access enhancements 2: developing offline

SQL Server Data Service is well…an online service. That means that you have to be connected to the network 100% of the time if you are using it. What if you are not connected? well…you know the whole story.

つまり、、、SQL Server Data Service はオンライン・サービスである。 そのため、SSDS を使用している際には、100%の割合で、ネットワークに接続していなければならないことになる。 接続されていないと、いったいどうなるのだろう? そのストーリーを、これから知ることになる。

Our goal while developing LitwareHR was to actually make the dev team as independent and autonomous as possible. Notice I say the dev team, not the application itself. We were comfortable in taking a dependency with SSDS for runtime, that is when LitwareHR would be deployed in a production data center. But we wanted developers to be able to work even if they are flying on a plane with no connectivity (like I was!). In one sentence we wanted a "mock SSDS".

LitwareHR を開発する際に持っていた目的は、実質的に開発チームを、可能な限り独立させ、また、自立させることにあった。アプリケーション自体ではなく、開発チームについて言及していることに注意して欲しい。 ランタイムにおいて、SSDS に対する依存性を持つことに満足していた。 つまり、プロダクション・データセンターに、LitwareHR がディプロイされるときを想定していた。 しかし、空を飛んでいる飛行機のように、デベロッパーが接続性を持たないときであっても(私がそうであったように!)、開発環境が適切に機能することを望んだ。 一言でいうと、「mock SSDS」が欲しかった。

With this in mind, we developed a new proxy implementing the same interface the real proxy implements, but against a local SQL Server Express database.

それを念頭において、本当のプロキシーと同じインターフェイスを実装している、新しいプロキシーを開発した。しかし、そこでは、ローカルの SQL Server Express が用いられる。

Again: our goal was not to create full-fledged offline SSDS, but rather an implementation complete enough to support our TDD development practices, and "complete enough" is key here. We gradually made it more complex as needed by LitwareHR, so no guarantees that it would actually work in another application, and no optimizations whatsoever.

もう一度いうが、私たちのゴールは、完全なオフラインSSDS を作ることではなかった。しかし、私たちの TDD 開発プラクティスを支援するには、必要にして充分なものであった。そして「必要にして充分」な実装が、ここのでキーとなる。それは、 LitwareHR で必要とされるにつれて、段階的に複雑なものになっていった。したがって、別のアプリケーションで動くという保証はなく、また、最適化も考えていない。

Each dev in our team would configure he’s own solution to use the offline version of the proxy, make sure all tests pass, etc. then we would test against the real one. Features on the offline client were strictly added as necessary as we made progress with the project and tests passed with the real proxy but failed with the mocked one.

このチームの開発者たちは、オフラインのプロキシー・バージョンを使って、彼らのソリューションを構成していった。そして、すべてのテスト・パスを確認していった。 それから、本当の環境でテストが行われた。オフライン・クライアントにおける機能は、プロジェクトでの必要性に応じて追加された。そこでは、本当のプロキシーを用いたテストでは成功しても、モックでは失敗するほどの、厳密性が適用された。

The ProxyFactory class allows us to switch between one implementation and the other. Repository doesn’t really know or care about what version is using.

ProxyFactory クラスは、2つの実装の間での、切り替えを実現した。リポジトリは、どのバージョンが使われているのかを知らず、また、気にかけなくても良い。

Eugenio 4 09_04_20

The implementation is quite straight forward actually. There are 2 tables: CONTAINERS and DATA. The table CONTAINERS is only used to record the existence of a new container (because Containers can be empty). The table DATA contains the entity instances themselves. Structure of these tables is as simple as you could imagine:

この実装は、現実的に極めて単純なものである。 CONTAINERS と DATA という、2つのテーブルがある。 CONTAINERS テーブルは、新しい CONTAINERS の存在を記録するためだけに用いられる(CONTAINERS が空であり得るため)。 DATA テーブルは、エンティティーインスタンス自身を取り込む。 ご想像のとおり、これらのテーブル構造は単純である:

CONTAINER:

[containerId] [nvarchar](255) NOT NULL

DATA:

[containerId] [nchar](255) NOT NULL,
[id] [nvarchar](255) NOT NULL,
[version] [int] NOT NULL,
[kind] [nvarchar](255) NOT NULL,
[entity] [xml] NOT NULL

containerId, Id, version and kind translate into SSDS entities’ intrinsic properties. Queries against these being frequent. entity is the field that contains the serialized flexible entity.

containerId と、Id、version、kind は、SSDS エンティティーの本質的なプロパティに変換される。 それらに対するクエリーは、頻繁に発行される。entity は、シリアライズされた柔軟なエンティティを含むフィールドである。

The schema of the serialized entity is also quite simple and direct. A "book" entity with 3 fields: Title, ISBN and Author would be serialized like this:

シリアライズされたエンティティのスキーマも、きわめてシンプルでダイレクトなものである。「book」エンティティは、Title、ISBN、Author という、 3つのフィールドを持つ。 それらは、以下のようにシリアライズされるだろう:

<entity>

  <field name="Title" type="System.String">The Aleph</field>

  <field name="ISBN" type="System.String">78755</field>

  <field name="Author" type="System.String">J.L.Borges</field>

</entity>

Operations like Insert, GetById, Delete and Update are trivial. Query is trickier because we had to (re) implement a parser for SLINQ. Good for us that SLINQ is fairly simple today. Once again, we just developed the basics so LitwareHR would work.

Insert、GetById、Delete、Update といった操作は、取るに足らないものである。クエリーに関しては、SLINQ 用のパーサーを実装する必要があるため、慎重を要する。 現時点の SLINQ が、かなりシンプルになったことは好都合である。もう一度いうが、LitwareHR を機能させるための、基本を開発したに過ぎない。

In a nutshell, it’s simply a translator from SLINQ syntax into a mix of T-SQL and XQuery. Searches involving intrinsic properties (Id, Kind, etc) are straight forward T-SQL statements. XQuery is only involved when the search criteria includes properties within the entity. For example:

簡単に言うと、それは、T-SQL と XQuery の複合体の中に、SLINQ シンタックスを変換するものとなる。 本質的なプロパティ(Id や kind など)を取り込む検索は、単純な T-SQL ステートメントに展開される。 XQuery が関連するのは、捜索の基準にエンティティ内のプロパティが含まれるときだけになる。 たとえば:

This query against a "C_1" container, looking for an entity with Id = E_1:

「C_1」コンテナに対するクエリーは、Id = E_1を用いるエンティティを検索する:

from e in entites where e.Id==’E_1" select e

is translated into:

上記は、以下に展開される:

SELECT id, entity, version, kind FROM DATA WHERE containerId=’C_1′ AND Id =  ‘E_1′

and getting all entities with a flexible property named "Title" equal to "The Aleph":

すべてのエンティティが取得されるが、そこには「Title」という柔軟なプロパティ名が含まれ、「The Aleph」と一致する:

from e in entities where e["Title"]=="The Aleph" select e

will become:

上記は、以下に展開される:

SELECT id, entity, version, kind FROM DATA WHERE containerId=’C_1′ AND entity.value(‘(/entity/field[@name="Title"])[1]‘,’NVARCHAR(MAX)’) =  ‘The Aleph’

We definitely recovered the investments we made in creating this facility. When we started development, SSDS was still changing and under development (this was far before MIX08), it was only available from our intranet (making it more difficult for our non-MSFT team members to access it: VPN, etc). With this approach, we definitely increased our productivity.

For serious, production offline access I’d look at Sync Services.

このファシリティを作成する投資からの、明確な回収に成功した。この試みが始まったとき(MIX08 以前)、まだ SSDS は変化している最中であり、開発中であった。それは、イントラネットからのみ利用が可能であり、チーム内の非 MSFT メンバーによる、VPN アクセスなどを困難にした。したがって、このアプローチにより、私たちの生産性は確実に向上した。厳密に言うと、プロダクション環境におけるオフライン・アクセスでは、Sync Services に注目している。

June 1, 2009

LitwareHR on SSDS – Part V

Filed under: Eugenio Tracker — Agile Cat @ 2:48 pm
Tags: ,

Eugenio Pace – Software as a Service Architecture Guidance

Published Monday, April 14, 2008 7:31 PM by eugeniop

From <http://blogs.msdn.com/eugeniop/archive/2008/04/14/litwarehr-on-ssds-part-v-searching-across-containers.aspx>

LitwareHR on SSDS – Part V – Searching across Containers

In SQL Server Data Services, the scope of a query is bound to a Container, but in LitwareHR we had a requirement of searching entities across multiple tenants, and because in our implementation each tenant gets its own Container, we had to create a way of performing queries (the same query to be more precise) that spanned across Containers.

SQL Server Data Services において、クエリーのスコープは Container にバインドされているが、LitwareHR では、マルチ・テナントに対応した、エンティティの検索という要件を持っている。さらに、その実装においては、それぞれのテナントが自身の Container を持つため、Container 間をまたぐように、クエリーを実行する方式(これまでクエリーを更に正確にする)が必要となる。

Remember, LitwareHR actually "owns" all containers. LitwareHR’s metadata (which is simply another Container as explained in a previous post), contains information about the tenant including a pointer to the tenant’s Container.

現実に、LitwareHR では、すべてのコンテナが「own」されることを、忘れないで欲しい。 LitwareHR のメタデータ(前回のポストで説明したように、メタデータも別のコンテナである)は、テナントに関する情報を取り込むが、そこには、テナントが所有するコンテナに対するポインタも含まれる。

The trivial way of implementing a cross-Container search would be to iterate on all tenant containers and query each of them. Something like this:

クロス・コンテナ検索を実装するための普通の方法は、すべてのテナント・コンテナ上でイテレーションを行い、それぞれに対してクエリーを実行するものになるだろう。 以下のような感じになる:

foreach (Container c in TenantContainerCollection)
{
IEnumerable<Entity> result = proxy.Query(CreateScope(c.ContainerId), query);
CombinedResults.Merge(result);
}

return CombinedResults;

Naturally, this doesn’t scale very well and is not taking advantage of the fact that this is a highly parallel problem. In fact, most probably each Query sent to SSDS will end up in a different node of the SSDS fabric, minimizing chances of server side contention.

必然的に、スケールを上手く処理するものにはならず、また、パラレルに関する大きな問題であるという事実において、SSDS のアドバンテージを活用するのにもなっていない。 現実的に考えても、おそらく SSDS に送られる Query は、SSDS ファブリックの別のノードで終わり、サーバー・サイドにおける競合を最小化するだろう。

So we created a helper class: CrossTenantSearch, that essentially takes an array of TenantId’s, a query statement (SLINQ) and returns the combined result sets.

そのため、ヘルパークラスである CrossTenantSearch を作成した。それは本質的に、TenantId の配列を取得し、クエリー・ステートメント(SLINQ)を発行し、結合された結果をリターンするものとなる。

Internally, it will asynchronously launch several concurrent searches, each one on a different thread of a ThreadPool and then will wait for all of them to complete, merge the partial results into a single collection and return.

内部的には、いくつかのコンカレントな検索が、ThreadPool の個々のスレッド上で非同期に開始される。そして、それら全てが完了するのを待って、シングル・コレクションに部分的な結果をマージし、最後にリターンが行われる。

The following diagram illustrates an example of running 3 concurrent queries (with different colors to identify each thread). Notice how the red thread returns even before the 3rd thread is launched, the green thread is longer (potentially returning a lot of results) and the yellow is very short.

以下のダイアグラムは、3つのコンカレント・クエリー(スレッドを識別するために色を変えている)を実行するための例を示している。 3番目のスレッド(黄色)が開始される前であっても、赤スレッドがリターンされる状況に注意すべきだ。緑のスレッドはLONGであり(多くの結果をリターンする可能性を持つ)、黄色のスレッドは極端にSHORTである。

Eugenio 5 09_04_28

After all of them return, results are combined into a single result set and sent back to the requestor. With this approach, the max time for a query is approximately the same as the longest query you have (e.g. the green thread in the diagram above). Caveat: this might not be valid for very large sets of containers, that is when there’s a large number of containers you are searching in, because you might get contention issues on the client side and also the merging of all the results might take a lot of time.

それら全てがリターンされた後に、結果がシングル・リザルト・セットに結合され、requestor にリターンされる。このアプローチを用いることで、クエリーの最大時間は、最も長いクエリーと(上記の緑スレッド)、ほぼ同じになる。警告:この方式は、きわめて大きなコンテナ・セットに対して、つまり、膨大な数のコンテナを検索するときには、有効にならないかもしれない。なぜなら、クライアント・サイドで競合が発生する可能性があり、さらには、すべての結果をマージするために、長い時間が消費される可能性があるからだ。

There is of course room for improvements: paging, returning to the client partial results and allow the client to drive further fetches, etc. None of these have been implemented in LitwareHR and are left as an exercise to the reader.

もちろん、改善の余地はある。 具体的には、ページングや、部分的な結果のクライアントに対するリターン、そして、クライアントにおける先読みなどが考えられる。これらの全てが、LitwareHR には実装されず、また、読者の課題として残されている。

Side note: when developing this feature we were puzzled by an exception we got related to thread apartments. It turns out by default, Visual Studio test runner runs in STA. There’s a somewhat obscure configuration parameter that you need to add to the testrunconfig file manually, as it is not exposed in the configuration window:

<ExecutionThread apartmentState="MTA"/>

See here for more info.

<完>

Blog at WordPress.com.