I'm designing a service fabric stateless service, which requires configuration data for each instance. My initial thought was creating named partitions, and using PartitionInfo to get the named key, with a shared read only dictionary to load settings per instance. Problem is, now accessing this instance internally (From other services) requires a partition key. Since all partitions using this method will serve the same data internally, it doesn't matter which partition I connect to (I'd want it to be random). So, this gives me many possible ways to fix this problem:
Accessing the partitions (in my attempt above) randomly using ServiceProxy.Create.
The following solutions that don't involve partitions:
A configuration based per instance. This post doesn't give much help in coming up with a solution. A configuration section unique to each instance would be the most ideal solution.
Create named instances, and use the name as the username (Basically attach a string to a non-partitioned instance)
Get an instance by index, and use the index against a shared read-only dictionary to get the username.
Somehow use InitializationData (See this post) to get a username string (If InitializationData can be unique per instance).
All of the above will solve my issue. Is any of these ways possible?
EDIT: An example of a service I'm trying to create:
Let's say we have a stackoverflow question service (SOQS for short). For the sake of this example, let's say that one user can be connected to stackoverflow's websocket at any one time. SOQS internal methods (Published to my service fabric) has one method: GetQuestions(). Each SOQS would need to connect to stackoverflow with a unique username/password, and as new questions are pushed through the websocket, they added to an internal list of questions. SOQS's GetQuestions() method (Called internally from my service fabric), would then give the same question list. I can then load balance by adding more instances (As long as I have more username/passwords) and the load internally to my fabric could then be distributed. I could call ServiceProxy.Create<SOQS>() to connect to a random instance to get my question list.
It sounds like what you are looking for to have a service type that has multiple actors with each actor having its own configuration. They wouldn't be multiple copies of the same service with unique configurations, it would be one (with replicas of course) instance of the service as a singleton, and individual actors for each instance.
As an example you could have the User Service (guessing what it is since you mention username string) read from some external storage mechanism the list of usernames and longs for instance ids for each to use for internal tracking. The service would then create an actor for each, with its own configuration information. Then the User Service would be the router for messaging to and from the individual actors.
I'm not entirely sure that this is what you're looking for, but one alternative might be to create an additional configuration service to provide the unique configs per instance. On startup of your stateless service, you simply request a random (or non-random) configuration object such as a json string, and bootstrap the service during initialization. That way, you don't have to mess with partitions, since each stateless instance will fire it's own Startup.cs (or equivalent).
Related
The cluster needs access to a dataset that lives in sql server, that is outside of the cluster.
Rather than forcing remote calls to the database for every request, I would like to create a stateful service that will periodically refresh its cache with data from the remote database.
Would we be looking at something like this following?
internal sealed class StatefulBackendService : StatefulService
{
public StatefulBackendService(StatefulServiceContext context)
: base(context)
{
}
/// <summary>
/// Optional override to create listeners (like tcp, http) for this service instance.
/// </summary>
/// <returns>The collection of listeners.</returns>
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new ServiceReplicaListener[]
{
new ServiceReplicaListener(
serviceContext =>
new KestrelCommunicationListener(
serviceContext,
(url, listener) =>
{
ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");
return new WebHostBuilder()
.UseKestrel()
.ConfigureServices(
services => services
.AddSingleton<IReliableStateManager>(this.StateManager)
.AddSingleton<StatefulServiceContext>(serviceContext))
.UseContentRoot(Directory.GetCurrentDirectory())
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl)
.UseStartup<Startup>()
.UseUrls(url)
.Build();
}))
};
}
}
Within this stateful service, how would I load data from a remote database and serve it through controllers?
Let's assume we have a simple model:
Create table Account (varchar name, int key)
I imagine that the operations would be in the following order:
Load Account table into memory
respond to requests such as http://statefulservice/account?$top=10
refresh data in the service on a time interval basis
What are the datatypes that I should be using in order to cache this data? What would be the process of loading the data into the stateful service from a sql server database>?
IMHO, even though it's possible to use Statefull services as a cache backed up by some database, the real power comes when you keep your data in the reliable collections only. With Service Fabric and Reliable Collections, you can store data directly in your service without the need for an external persistent store. See Application scenarios. Aside from providing high availability and low latency, the state is reliably replicated across multiple nodes so it could survive a node failure, and moreover, there is a Back up and restore feature that allows you to deal even with the entire cluster outage.
There are many things you should know about when dealing with Reliable Services. Service partiotioning, Transactions and lock modes, Guidelines and recommendations, etc.
As for the data types, explore Reliable Collection object serialization and Serialization and Upgrade.
Another thing you also should be aware of, is the Reliable Dictionary periodically removes least recently used values from memory, which could increase read latencies in certain cases. See more here - Service fabric reliable dictionary linq query very slow.
A simple example of integrating controllers and StateManager you could find in this article.
l--''''''---------''''''''''''
Here's a little more info related to your comment...
Hey m8... the reliable collections are designed to run multiple instances (the run on more than one node at a time)... Within each instance the data is partitioned into one or more groups (how you decide to partition is entirely up to you)... So there is load distribution and fail over, there is more to say... but I don't want to muddy the waters so I'm attempting to keep it high level. This type of service data in reliable collections exists in memory and can be "backed up"... If you want your data formally written to disc and have more control over WHEN it is written to disc you will need to take a look at Actors. This is a good (very simple) collection of examples of service fabric, reliable collections, and wiring up internal communications. Only think funky about looking at this one is there are a lot of different 'recipes' used to facilitate back-end and communication from the back-end to the public (stateless) side.
I see you added to your question and changed the intent a little... I will pointedly tell you what I 'think' you need for what you are really after... You want one or multiple 'Stateful Service's (this is your data service layer, this can be abstracted into 3 components if you want... the stateful service itself, and 2 class libraries one for your service interface and one for your contracts ... or rather your data models... basically this is a POCO), you would include the 2 class libraries in your stateful service and use them to create dictionary entries (probably something like new IReliableDictionary... and bind the interface. You will want to use (add to) the IService interface (you will need to grab a nuget package 'Service Fabric Remoting' for the interface project you created for your service interface, there is plenty of info out there on how to achieve remoting within service fabric as it is a standard communication method. There is more, but simply building this would be a viable experiment and would effectively take the place or you database. You can formally persist the data to disc using Actors or a simple backup method that is canned with service fabric. Essentially I suggest you build this in order to firm up the fact you can completely remove the database from this scenario... you really don't need it. What I have described above takes the place of the db ONLY... without writing a front-end for this (that uses remoting to communicate with your backend) this would not be accessible to the public... at least not easily.
TL;DR - Basically I'm agreeing with what one of your other contributors is stating... My opinion is less humble so I'll simple state it. You application will be less complicated, faster and more reliable if you handle your data within service fabric... Still TL;DR? - Ditch the db my man. If you are really nervous about it only existing in memory, use Actors
I am trying to connect directly to the performance counters emitted by ServiceModel (for services, endpoints and operations). The problem is that when I try to correlate with a certain service (or endpoint/operation) I need to specified instance name of the counter.
According to MSDN the pattern by which instance name is simple,
however in certain cases when one of the components of the instance name (uri, contract name, etc.) is too long it’s shortened and hash code is added at either the beginning or the end of the string.The article doesn’t specify how it’s hashed.
So my question is there a way to get ServiceModel instance name based on the service name and it's address
I know it is not ideal, but you could copy the current .NET implementation for generating counter instance names to your own code/application to programatically generate the same names from the full service name and address.
You can see the code used by WCF here:
For SerivcePerformanceCounters:
http://referencesource.microsoft.com/#System.ServiceModel/System/ServiceModel/Diagnostics/ServicePerformanceCountersBase.cs,6d61d34585241697
For EndpointPerformanceCounters:
http://referencesource.microsoft.com/#System.ServiceModel/System/ServiceModel/Diagnostics/EndpointPerformanceCountersBase.cs,e3319d41297320e3
For OperationPerformanceCounters:
http://referencesource.microsoft.com/#System.ServiceModel/System/ServiceModel/Diagnostics/OperationPerformanceCountersBase.cs,5e170817afd5d0ba
The downside is that any change to the .NET algorithm for naming instances will break your implementation.
I'm as frustrated as you surely are, but haven't found a better solution.
My project group and I are to develop a generic workflow system, and have decided to implement a single Node (a task in the workflow) as a C# Visual Studio Web API project (Using the ASP.NET MVC structure).
In the process of implementing a Node's logic, we've come across the trouble of how to store data in our Node. Our Node specifically consists of a few lists of Uri's leading to other Nodes as well as some status/state boolean values. These values are currently stored in a regular class but with all the values as internal static fields.
We're wondering if there's a better way to do this? Particularly, as we'd like to later apply a locking-mechanism, it'd be prefereable to have an object that we can interact with, however we are unsure of how we can access this "common" object in various Controllers - or rather in a single controller, which takes on the HTTP requests that we receive for ou Node.
Is there a way to make the Controller class use a modified constructor which takes this object? And if so, the next step: Where can we provide that the Controller will receive the object in this constructor? There appears to be no code which instantiates Web API controllers.
Accessing static fiels in some class seems to do the trick, data-wise, but it forces us to implement our own locking-mechanism using a boolean value or similar, instead of simply being able to lock the object when it is altered.
If I am not making any sense, do tell. Any answers that might help are welcome! Thanks!
Based on your comments, I would say the persistence mechanism you are after is probably one of the server-side caching options (System.Runtime.Caching or System.Web.Caching).
System.Runtime.Caching is the newer of the 2 technologies and provides the an abstract ObjectCache type that could potentially be extended to be file-based. Alternatively, there is a built-in MemoryCache type.
Unlike a static method, caches will persist state for all users based on a timeout (either fixed or rolling), and can potentially have cache dependencies that will cause the cache to be immediately invalidated. The general idea is to reload the data from a store (file or database) after the cache expires. The cache protects the store from being hit by every request - the store is only hit after the timeout is reached or the cache is otherwise invalidated.
In addition, you can specify that items are "Not Removable", which will make them survive when an application pool is restarted.
More info: http://bartwullems.blogspot.com/2011/02/caching-in-net-4.html
I am trying to implement a scenario.
One of the component of my app system needs to send and receive data from same direct exchange but with two different routing key.
So is there any thing I need to consider such as:
Sharing of variables
such as connection,channel,
Data flow to correct listener
One more thing two components of my app system uses same direct exchange to publish data but uses different routing key. So is it safe?
For guidance around threading then take a look at the .net client documentation, specifically section 2.9 entitled Threading, deadlocks, and associated restrictions on
consumers.
The summary is to create one instance of IConnection, the create a channel (IModel) per thread.
In terms of how you use your queues etc...you will need to ensure that the logic is correct for what you want to achieve.
I'm using Amazon EC2 instances for multiple processes with various states. It's important for reporting and analysis that an instances state can be accessed at any time. So far I've thought of three options.
Publish this state via an HTTP endpoint or webservice
Add and update instance tags for the different processes and their states
Use instance metadata. I'm not sure if this requires SimpleDB to be used.
Out of these, only 1 and 3 are options I like. Choice 2 is just not what AWS instance tags should be used for. 3 is the option I like the most.
So I ask, how would I go about option 3? Do I need to use SimpleDB to accomplish it? Has anyone found any Amazon docs on how to create instance metadata?
I also want to leave this question open ended, so if anyone disagrees with option 3 please make a case.
Yes you can use Instance meta-data. There are many ways to store that meta-data like in database, file system etc.
Check this documentation:
Using Instance Metadata
Amazon EC2 instance has associated meta-data, as well as user data supplied at the time of launching the instance. The meta and user data is instance-specific, and therefore only accessible to the instance. One of the most useful data is user-data, which can be used to pass configuration information or even initialization scripts to the instance upon launch.