Webservice Cache用于长期运行的流程设计理念

c# .net web-services caching

74 观看

4回复

198 作者的声誉

我正在寻找一些设计理念

我有一个网站消耗的ASP.Net网络服务。其中一个调用大约需要13秒来检索大约70000行。db上有4秒,Web服务器上有9秒需要处理,因为每条记录都有处理。这已经尽可能优化,并从最初的42秒降低。

数据不会经常改变,因此我的想法是在Web服务上创建一个缓存并在计时器上轮询每隔30秒左右更新一次缓存。然后webservice调用从缓存中检索已处理的记录

我正在寻找设计理念,以寻求最佳方法。我知道ASP.Net有一个输入缓存字典,但这不会解决轮询问题,所以我不需要单独的单例,然后我有可能的线程问题。

变得非常困惑,不确定我是否在正确的行上,或者我是否应该计算数据并将其存储在数据库表中,任何指导都将非常感谢

作者: Richard Watts 的来源 发布者: 2019 年 1 月 16 日

回应 4


0

1 作者的声誉

您可以使用Redis缓存数据,如果数据更改,则可以使用sql依赖关系更新缓存。只是你需要redis和sql依赖我想。

作者: Abdulsamet Şentürk 发布者: 2019 年 1 月 19 日

0

3530 作者的声誉

如果我要实现您的方案,我不会更喜欢轮询,因为重复调用服务并保持服务/网络忙碌的重点较少。此外,如果您要实现新客户端,则必须再次实施轮询。

而是在静态类中使用基于字典的缓存。您使用像CacheManager这样的现有库。一般的想法是使用用于进行服务调用的参数来创建密钥。然后将处理后获得的结果存储在ConcurrentDictionary由多个线程自己进行访问的结果中。

仅在更新基础数据库表(?)时清除存储的结果,或者每30秒后清除一次太复杂的存储结果。

此外,您还可以在数据访问层上实现类似的缓存机制,以降低当前的4秒。在基础数据更改(添加,更新,删除,插入操作)后刷新缓存的数据!

作者: bit 发布者: 2019 年 1 月 22 日

0

1067 作者的声誉

我们在ASP.NET中实现了一个可能适用于您的用例的轮询模式。

在我们中Global.ashx,我们有:

protected void Application_Start(object sender, EventArgs e)
{
  ConfigurationMonitor.Start();
}

这里ConfiguraitonMonitor看起来是这样的:

public static class ConfigurationMonitor
{
    private static readonly Timer timer = new Timer(PollingInterval);
    public static bool MonitoringEnabled
    {
        get
        {
            return ((timer.Enabled || Working) ? true : false);
        }
    }
    private static int _PollingInterval;
    public static int PollingInterval
    {
        get
        {
            if (_PollingInterval == 0)
            {
                _PollingInterval = (Properties.Settings.Default.ConfigurationPollingIntervalMS > 0) ? Properties.Settings.Default.ConfigurationPollingIntervalMS : 5000;
            }
            return (_PollingInterval);

        }
        set { _PollingInterval = value; }
    }


    private static bool _Working = false;
    public static bool Working
    {
        get { return (_Working); }
    }
    public static void Start()
    {
        Start(PollingInterval);
    }

    /// <summary>
    /// Scans each DLL in a folder, building a list of the ConfigurationMonitor methods to call.
    /// </summary>
    private static List<ConfigurationMonitorAttribute> _MonitorMethods;
    private static List<ConfigurationMonitorAttribute> MonitorMethods
    {
        get
        {
            if (_MonitorMethods == null)
            {
                _MonitorMethods = new List<ConfigurationMonitorAttribute>();
                MonitorMethodsMessage = string.Empty;
                foreach (var assemblyFile in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"), Properties.Settings.Default.ConfigurtionMonitorDLLPath))
                {
                    var assembly = Assembly.LoadFrom(assemblyFile);
                    foreach (ConfigurationMonitorAttribute monitor in assembly.GetCustomAttributes(typeof(ConfigurationMonitorAttribute), inherit: false))
                    {
                        _MonitorMethods.Add(monitor);
                    }
                }
            }
            return (_MonitorMethods);
        }
    }

    /// <summary>
    /// Resets and instanciates MonitorMethods property to refresh dlls being monitored
    /// </summary>
    public static void LoadMonitoringMethods()
    {
        _MonitorMethods = null;
        List<ConfigurationMonitorAttribute> monitorMethods = MonitorMethods;
    }

    /// <summary>
    /// Initiates a timer to monitor for configuration changes.
    /// This method is invoke on web application startup.
    /// </summary>
    /// <param name="pollingIntervalMS"></param>
    public static void Start(int pollingIntervalMS)
    {
        if (Properties.Settings.Default.ConfigurationMonitoring)
        {
            if (!timer.Enabled)
            {
                LoadMonitoringMethods();
                timer.Interval = pollingIntervalMS;
                timer.Enabled = true;
                timer.Elapsed += new ElapsedEventHandler(OnTimerElapsed);
                timer.Start();
            }
            else
            {
                timer.Interval = pollingIntervalMS;
            }
        }
    }
    public static void Stop()
    {
        if (Properties.Settings.Default.ConfigurationMonitoring)
        {
            if (timer.Enabled)
            {
                timer.Stop();
            }
        }
    }

    /// <summary>
    /// Monitors CE table for changes
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private static void OnTimerElapsed(object sender, ElapsedEventArgs e)
    {
        timer.Enabled = false;
        PollForChanges();
        timer.Enabled = true;
    }
    public static DateTime PollForChanges()
    {
        LastPoll = PollForChanges(LastPoll);
        return (LastPoll);
    }
    public static DateTime PollForChanges(DateTime lastPollDate)
    {
        try
        {
            _Working = true;
            foreach (ConfigurationMonitorAttribute monitor in MonitorMethods)
            {
                try
                {
                    lastPollDate = monitor.InvokeMethod(lastPollDate);
                    if (lastPollDate > LastRefreshDate)
                        LastRefreshDate = lastPollDate;
                }
                catch (System.Exception ex)
                {
                    // log the exception; my code omitted for brevity
                }
            }
        }
        catch (System.Exception ex)
        {
            // log the exception; my code omitted for brevity

        }
        finally
        {
            _Working = false;
        }
        return (lastPollDate);
    }

    #region Events
    /// <summary>
    /// Event raised when an AppDomain reset should occur
    /// </summary>
    public static event AppDomainChangeEvent AppDomainChanged;
    public static void OnAppDomainChanged(string configFile, IDictionary<string, object> properties)
    {
        if (AppDomainChanged != null) AppDomainChanged(null, new AppDomainArgs(configFile, properties));
    }
    #endregion
}

当我们有一个想要“参与”这个轮询机制的用例时,我们用一个属性标记一些方法:

[assembly: ConfigurationMonitorAttribute(typeof(bar), "Monitor")]
namespace foo
{
  public class bar 
  {
    public static DateTime Monitor(DateTime lastPoll)
    {
      // do your expensive work here, setting values in your cache
    }
  }
}

我们通过ConfigurationMonitor返回a 触发方法的模式DateTime是一个相当奇怪的边缘情况。你当然可以采用一种void方法。

ConfigurationMonitorAttribute是这样的:

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class ConfigurationMonitorAttribute : Attribute
{
    private Type _type;
    private string _methodName;

    public ConfigurationMonitorAttribute(Type type, string methodName)
    {
        _type = type;
        _methodName = methodName;
    }

    public Type Type
    {
        get
        {
            return _type;
        }
    }

    public string MethodName
    {
        get
        {
            return _methodName;
        }
    }

    private MethodInfo _Method;
    protected MethodInfo Method
    {
        get
        {
            if (_Method == null)
            {
                _Method = Type.GetMethod(MethodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
                if (_Method == null)
                    throw new ArgumentException(string.Format("The type {0} doesn't have a static method named {1}.", Type, MethodName));

            }
            return _Method;
        }
    }
    public DateTime InvokeMethod(DateTime lastPoll)
    {
        try
        {
            return (DateTime)Method.Invoke(null, new object[] { lastPoll });
        }
        catch (System.Exception err)
        {
            new qbo.Exception.ThirdPartyException(string.Format("Attempting to monitor {0}/{1} raised an error.", _type, _methodName), err);
        }
        return lastPoll;
    }
}
作者: Eric Patrick 发布者: 2019 年 1 月 22 日

0

44 作者的声誉

除了只是说“我想添加缓存”之外,还有其他一些事情需要考虑。

  1. 如果您在Azure或Web场中运行,则需要集中式缓存(REDIS或类似),因为内存缓存将被破坏并与您的站点一起重新创建,并且本地到服务器场中的一台服务器,因此您赢了不一定会看到性能提升。

  2. 如果您确实设置了REDIS缓存,请确保您仔细配置它。编码必须只是为了考虑连接,如果你做得不对,你最终会超越你的连接池。

  3. 这更多的只是你的情况,但即使4秒返回70k记录似乎很高。您是否已经完成执行计划以查看是否存在可以应用CTE的缺失索引或优化?

作者: Rob 发布者: 2019 年 1 月 22 日
32x32