更新: 下: CreateArticleRelations コード例を追加しました。
わかりました、これはトリッキーです。プレビュー環境と本番環境に関して、hyper-v で大きなパフォーマンスの問題が発生しています。
まず、セットアップはこちら。
すべてのサーバーで .NET 4.0。
プレビュー
Web サーバー : 仮想マシン、8 GB RAM、4 CPU、Windows Server 2008 r2 (64)
データベース: 仮想サーバー、6 GB RAM、2 CPU、Windows Server 2008 r2 (64)
生産:
ウェブサーバー: 仮想マシン、8 GB RAM、4 CPU、Windows Server 2008 r2 (64)
データベース: 物理マシン、48 GB RAM、16 CPU、Windows Server 2008 r2 (64)
これらで運営しているB2Bショップです。そして、1 つの製品の統合を実行すると、その結果は私にとって驚くべきものです。写真を提供します。
プレビュー中の 1 つの製品の実行には、すべてが更新されるまでに 83 秒かかります。本番環境で 1 つの製品を実行すると、すべてが更新されるまでに 301 秒 (!) かかります。同じ商品!
これをローカルで実行すると、完了するまでに約 40 秒かかります。
両方のサーバーで dotTrace profiling remote を実行して、何が時間がかかっているかを実際に確認しました。ロギングには EnterpriseLibrary、cms には umbraco、コマース プラットフォームには uCommerce を使用しています。私が見た発見の一例を下の写真の例を見てください。
まず、CreateArticleRelations は本番サーバーでは 140 秒かかりますが、プレビューでは 46 秒しかかかりません。同じ商品、同じデータ。それから本当にファンキーなものに。一番上にある実稼働サイトでは、enterpriselogging に 64 秒かかっていることがわかりますが、プレビューの実行ではかなり遅いため、絶対に時間がかからないとは言えません。
ロギングの実装は次のようになります。
private string LogMessage(string message, int priority, string category, TraceEventType severity, int code, int skipFrames = 2)
{
//Check if "code" exists in eCommerceB2B.LogExceptions
var dbf = new ThirdPartSources();
var exeptions = dbf.GetLogExeptions();
foreach (var exeption in exeptions)
{
if (code.ToString() == exeption)
return DateTime.Now.ToString();
}
try
{
var stack = new StackTrace(skipFrames);
if (_logWriter.IsLoggingEnabled())
{
var logEntry = new LogEntry
{
Title =
stack.GetFrame(0).GetMethod().ReflectedType.FullName + " " +
stack.GetFrame(0).GetMethod(),
Message = message,
Priority = priority,
Severity = severity,
TimeStamp = DateTime.Now,
EventId = code
};
logEntry.Categories.Add(category);
_logWriter.Write(logEntry);
return logEntry.TimeStampString;
}
ロギングは、ローリング フラットファイルとデータベースに設定されます。ロギングを無効にしようとしたところ、約 20 秒節約できましたが、まだ LogMessage が一番上に表示されています。
これは何日も私の心を吹き飛ばしました、そして私は解決策を見つけることができないようです. 確かにログを完全に削除することはできますが、問題の原因を突き止めたくありません。
私が気になるのは、たとえば、1 つのメソッド (CreateArticleRelations) を実行すると、運用サーバーでほぼ 4 倍の時間がかかることです。CPU レベルが 30% を超えることはなく、5 GB の RAM が利用可能です。アプリケーションは、コンソール アプリケーションとして実行されます。
誰か私を救ってください!:) 必要に応じて、さらにデータを提供できます。私の賭けは、それが仮想サーバーと関係があるということですが、何を確認すればよいかわかりません。
アップデート:
コメントごとに、LogMessage を完全にコメントアウトしようとしました。全体で約 100 秒節約できます。これは、何かがひどく間違っていることを示しています。リレーションの作成に 169 秒かかるのに対し、プレビューでは 46 秒かかり、プレビューではログ記録が引き続き有効になっています。エンタープライズ ライブラリをこのように動作させるために何が問題になる可能性がありますか? それでも、本番サーバーで 4 倍遅いコードを実行するのはなぜですか? LogMessage を削除した後の画像をご覧ください。プロダクションからです。
CreateArticleRelations
private void CreateArticleRelations(Product uCommerceProduct, IStatelessSession session)
{
var catalogues = _jsbArticleRepository.GetCustomerSpecificCatalogue(uCommerceProduct.Sku).CustomerRelations;
var defaultCampaignName = _configurationManager.GetValue(ConfigurationKeys.UCommerceDefaultCampaignName);
var optionalArticleCampaignName = _configurationManager.GetValue(ConfigurationKeys.UCommerceDefaultOptionalArticleCampaignName);
var categoryRelations =
session.Query<CategoryProductRelation>()
.Fetch(x => x.Category)
.Fetch(x => x.Product)
.Where(
x =>
x.Category.Definition.Name == _customerArticleCategory && x.Product.Sku == uCommerceProduct.Sku)
.ToList();
var relationsAlreadyAdded = _categoryRepository.RemoveCataloguesNotInRelation(catalogues, categoryRelations,
session);
_categoryRepository.SetArticleCategories(session, relationsAlreadyAdded, uCommerceProduct, catalogues,
_customerCategories, _customerArticleCategory,
_customerArticleDefinition);
//set campaigns and optional article
foreach (var jsbArticleCustomerRelation in catalogues)
{
// Article is in campaign for just this user
if (jsbArticleCustomerRelation.HasCampaign)
{
_campaignRepository.CreateCampaignAndAddProduct(session, jsbArticleCustomerRelation, defaultCampaignName);
}
else // remove the article from campaign for user if exists
{
_campaignRepository.DeleteProductFromCampaign(session, jsbArticleCustomerRelation, defaultCampaignName);
}
// optional article
if(jsbArticleCustomerRelation.IsOptionalArticle)
{
_campaignRepository.CreateCampaignAndAddProduct(session, jsbArticleCustomerRelation, optionalArticleCampaignName);
}
else
{
_campaignRepository.DeleteProductFromCampaign(session, jsbArticleCustomerRelation, optionalArticleCampaignName);
}
}
}
ここでは、何らかの方法でほぼすべての行でデータベースにアクセスします。たとえば、DeleteProductFromCampaign では、次のコードはプレビュー環境で 43 秒、運用環境で 169 秒かかります。
public void DeleteProductFromCampaign(IStatelessSession session, JSBArticleCustomerRelation jsbArticleCustomerRelation, string campaignName)
{
var productTarget =
session.Query<ProductTarget>()
.FirstOrDefault(
x =>
x.CampaignItem.Campaign.Name == jsbArticleCustomerRelation.CustomerNumber &&
x.CampaignItem.Name == campaignName &&
x.Sku == jsbArticleCustomerRelation.ArticleNumber);
if (productTarget != null)
{
session.Delete(productTarget);
}
}
したがって、たとえばこのコードは、本番サーバーでは 4 倍遅く実行されます。サーバー間の最大の違いは、実稼働 (物理) サーバーが多数のインスタンスでセットアップされており、そのうちの 1 つ (20 GB OM RAM) を使用していることです。